diff --git a/README.md b/README.md deleted file mode 100644 index 13e8362..0000000 --- a/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# "Stateful" Assignment - -Make a learning resource with some sort of workflow/progression, which can be demarcated with steps/points/awards/badges/etc. Have the project pick up where the user left off if they refresh (or close and re-open) the page. See [persistence](https://github.com/bfl-itp/syllabus/blob/master/topics/persistence.md) page in syllabus for options. diff --git a/css/MarkerCluster.Default.css b/css/MarkerCluster.Default.css new file mode 100644 index 0000000..90558dd --- /dev/null +++ b/css/MarkerCluster.Default.css @@ -0,0 +1,38 @@ +.marker-cluster-small { + background-color: rgba(181, 226, 140, 0.6); + } +.marker-cluster-small div { + background-color: rgba(110, 204, 57, 0.6); + } + +.marker-cluster-medium { + background-color: rgba(241, 211, 87, 0.6); + } +.marker-cluster-medium div { + background-color: rgba(240, 194, 12, 0.6); + } + +.marker-cluster-large { + background-color: rgba(253, 156, 115, 0.6); + } +.marker-cluster-large div { + background-color: rgba(241, 128, 23, 0.6); + } + +.marker-cluster { + background-clip: padding-box; + border-radius: 20px; + } +.marker-cluster div { + width: 30px; + height: 30px; + margin-left: 5px; + margin-top: 5px; + + text-align: center; + border-radius: 15px; + font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif; + } +.marker-cluster span { + line-height: 30px; + } \ No newline at end of file diff --git a/css/MarkerCluster.css b/css/MarkerCluster.css new file mode 100644 index 0000000..9629861 --- /dev/null +++ b/css/MarkerCluster.css @@ -0,0 +1,6 @@ +.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow { + -webkit-transition: -webkit-transform 0.2s ease-out, opacity 0.2s ease-in; + -moz-transition: -moz-transform 0.2s ease-out, opacity 0.2s ease-in; + -o-transition: -o-transform 0.2s ease-out, opacity 0.2s ease-in; + transition: transform 0.2s ease-out, opacity 0.2s ease-in; + } \ No newline at end of file diff --git a/css/site.css b/css/site.css new file mode 100644 index 0000000..bfd2393 --- /dev/null +++ b/css/site.css @@ -0,0 +1,70 @@ +/* Page Specific CSS */ + +body {font-family: proxima-nova; background: #fff; color: #333; font-size: 16px; border: 52px #F8F8F8 solid; margin: 0px; padding: 20px 20px 200px 20px;} +h1 {font-size: 60px; font-family: Poiret One; font-weight: thin; margin: 0px;} +h2 {font-size: 30px; font-family: Poiret One; font-weight: thin; margin: 11px 0px;} +h3 {font-family: Poiret One; font-size: 20px; margin: 10px 0px;} +h4 {font-family: proxima-nova; font-size: 24px;} + +img {width: 100%;} +p a, a {color: #333; text-decoration: none; padding-bottom: 0px; border-bottom: 1px #9393fd solid;} +a:hover {color: #47CCFC;} +small {padding: 10px 0px; font-size: 10px;} +p {margin: 0px; padding: 0px; font-size: 12px;} +li {line-height: 19px; font-size: 12px;} +ol {line-height: 24px;} +a.button {border: none;} + +pre {word-wrap: break-word; padding: 14px; background: #F0F0F0; } +code {font-family: "Consolas", "Ubuntu Mono", monospace; line-height: 22px; font-size: 13px; color: #636363; font-weight: normal;} + +.red-text {color: #9393fd;} + +#map {height: 400px; max-width: 530px; min-width: 300px; background: #DADADA;} +#map a {border: none;} + +.container {margin: 24px 0px;} +#tableFilter {margin: 12px 0px; border: none; border-bottom: 1px solid #333; background-color: transparent; padding: 0px; font-family: Lato; color: #333; font-size: 13px; height: 22px;} + +::selection {background: #E5FF1D;} +::-moz-selection {background: #E5FF1D;} + +ul.nav {list-style: none; margin: 0px; padding: 0px;} +ul.nav li {display: inline; font-size: 10px; letter-spacing: .1em; text-transform: uppercase; padding-right: 4px;} +ul.nav li a {border: none;} +ul.nav li a:hover {border-bottom: 1px #9393fd solid;} + +#wrapper {margin: 0px auto; max-width: 900px; padding-top: 40px; /*margin-left: 250px;*/} + +.button {padding: 5px 5px; background-color: #BEBEBE; font-size: 10px; color: #fff;} +.button:hover {background: #B9FCFC; color: #47CCFC;} +.fauxButton {padding: 5px 5px; background-color: #FF4646; font-size: 11px; color: #fff; display: inline;} +.fauxButton .selected {background-color: #FF4646;} +.colorText {color: #FF4646; text-transform: uppercase; font-weight: 700;} + +.leaflet-popup-content h2 {font-family: Lato; font-size: 14px; text-transform: uppercase;} + +#rightSide {height: 400px; max-width: 350px; width: 100%; float: right; padding-top: 5px;} +#selectedSpot {display: none;} +#latestSpot ul, #selectedSpot ul {list-style: none; margin-top: 12px 0px; padding: 0px;} +.category {text-transform: uppercase; font-size: 9px; letter-spacing: .2em; padding-right: 6px;} + +#info p {font-size: 14px; padding: 4px; line-height: 19px; font-weight: 300;} +#info {border-top: 4px #F8F8F8 solid;} + +#hackSpotsTable {cursor: pointer; background: #fff; overflow-x: auto; padding-bottom: 20px;} +#hackSpotsTable table {min-width: 900px;} +#hackSpotsTable .tHeader:hover {color: #FF4646;} +.tHeader::after {content: " \2193 \2191 "; font-size: 10px; padding-left: 3px;} +.spotRow:hover {color: #FF4646;} +.spotRow {border-left: 3px solid #ff00ff;} +.hideRow {display: none;} +.selectedRow {color: #FF4C0D;} + +@media only screen and (-webkit-min-device-pixel-ratio: 2) and (min-width: 320px) and (max-width: 1024px) { + body {border: 20px #F8F8F8 solid; margin: 0px; padding: 20px 20px 80px 20px;} + #tableFilter, .clear, .resetMap {display: none;} + #wrapper {max-width: 460px; padding-top: 20px;} + #hackSpotsTable, #map {min-width: 224px;} +} + diff --git a/css/style.css b/css/style.css new file mode 100644 index 0000000..0ee1c73 --- /dev/null +++ b/css/style.css @@ -0,0 +1,53 @@ +/* General */ + +/* body {margin: 0px auto;} + a {color: #333;} + small {padding: 10px 0px;} + #wrapper {margin: 0px auto; max-width: 600px;} + .button {padding: 5px 4px; background-color: #fff; font-size: 10px;}*/ + .button:hover {cursor: hand;} + input:focus {outline: none;} + +/* Table */ + + table {text-align: left; width: 100%} + th {padding: 10px 0px;} + td, text {padding: 3px 20px 3px 0px; font-size: 14px;} + #tableFilter {margin: 12px 0px; border: none; border-bottom: 1px solid #333; background-color: transparent; padding: 0px; font-family: Merriweather; color: #fff; font-size: 13px; height: 22px;} + .noMatches {margin-left: 20px; font-size: 11px; font-style: italic; visibility: hidden;} + +/* Containers */ + .container {margin: 14px 0px;} + #map {height: 400px; max-width: 800px; background: #DADADA;} + #holder {height: 400px; max-width: 600px; background: #FFE4E4;} + #bar2 {height: 320px; max-width: 600px; background: #F8CDCD;} + +/* Bar Chart */ + + .labels text {text-align: right;} + .bar .labels text {fill: #333;} + .bar rect {fill: #e6e6e6;} + .axis {shape-rendering: crispEdges;} + .x.axis line {stroke: #FFE4E4; /*stroke-opacity: .2;*/ fill: none;} + .x.axis path {fill: none;} + .x.axis text {fill: #333;} + .xLabel {font-family: sans-serif; font-size: 9px;} + +/* Line Chart */ + +/* .axis {shape-rendering: crispEdges;} + .x.axis .minor, .y.axis .minor {stroke-opacity: .5;} + .x.axis {stroke-opacity: 1;}*/ +/* .y.axis line, .y.axis path, .x.axis path {fill: none; stroke: #acacac; stroke-width: 1;} + .x.axis line {stroke: #acacac; stroke-opacity: .75;}*/ +/* .bigg {-webkit-transition: all .2s ease-in-out; -webkit-transform: scale(2);} + path.chartLine {stroke: #14ECC8; stroke-width: 3; fill: none;}*/ + div.tooltip {position: absolute; text-align: left; padding: 4px 8px; width: auto; font-size: 10px; height: auto; background: #fff; border: 0px; pointer-events: none;} + /*circle {fill: #fff;}*/ + +/* Map */ + + .leaflet-popup-content {font-family: Merriweather;} + .leaflet-popup-content h2 {margin-bottom: 4px;} + + img.petThumbs {height: 80px; width: 80px; border-radius: 1000px;} \ No newline at end of file diff --git a/img/fbi_spinner.gif b/img/fbi_spinner.gif new file mode 100644 index 0000000..872ede5 Binary files /dev/null and b/img/fbi_spinner.gif differ diff --git a/img/hackspotsss.png b/img/hackspotsss.png new file mode 100644 index 0000000..7da0be8 Binary files /dev/null and b/img/hackspotsss.png differ diff --git a/index.html b/index.html index 33d38f7..7369747 100644 --- a/index.html +++ b/index.html @@ -1,9 +1,271 @@ - - - So-and-so's Stateful Assignment - - - YOUR PROJECT HERE - + + + + + + Sweet off-the-floor study spots + + + + + + + + + + + + + + + + + + + +
+

Sweet off-the-floor study spots

+
+ +
+
+
+
+
+
+
+
+
+ + Clear Reset Map + no matches +
+
+
+

Contribute!

+
+

This website is connected to this Google Spreadsheet, which I've shared, so click and add your favorite off-floor near-NYU spots to the bottom of the list! For the map you'll need to get the lat and long of the spot, you can get that here. The locating of these places is helpful, so plz try to fill out all the columns.

+ +

Info

+

Last year, when we were kicked (urged?) off the floor during thesis, some of the first years felt unsure of, well, where to go. Luckily, there are lots of great spots nearby. Let's share some of our favorites! Hopefully, this will be a great resource for Thesis Tuesdays and just anytime we want a change of scene. + This was made by Kristina Budelis for the Builing for Learning class using this github example, which uses sheetsee, a snazzyclient-side library for connecting Google Spreadsheets to a website and visualizing the information. Enjoy! +
+ some_text + + +

+
+ + + + + + + + + + + + + diff --git a/js/ICanHaz.js b/js/ICanHaz.js new file mode 100644 index 0000000..25a14ac --- /dev/null +++ b/js/ICanHaz.js @@ -0,0 +1,542 @@ +/*! +ICanHaz.js version 0.10 -- by @HenrikJoreteg +More info at: http://icanhazjs.com +*/ +(function () { +/* + mustache.js — Logic-less templates in JavaScript + + See http://mustache.github.com/ for more info. +*/ + +var Mustache = function () { + var _toString = Object.prototype.toString; + + Array.isArray = Array.isArray || function (obj) { + return _toString.call(obj) == "[object Array]"; + } + + var _trim = String.prototype.trim, trim; + + if (_trim) { + trim = function (text) { + return text == null ? "" : _trim.call(text); + } + } else { + var trimLeft, trimRight; + + // IE doesn't match non-breaking spaces with \s. + if ((/\S/).test("\xA0")) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; + } else { + trimLeft = /^\s+/; + trimRight = /\s+$/; + } + + trim = function (text) { + return text == null ? "" : + text.toString().replace(trimLeft, "").replace(trimRight, ""); + } + } + + var escapeMap = { + "&": "&", + "<": "<", + ">": ">", + '"': '"', + "'": ''' + }; + + function escapeHTML(string) { + return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { + return escapeMap[s] || s; + }); + } + + var regexCache = {}; + var Renderer = function () {}; + + Renderer.prototype = { + otag: "{{", + ctag: "}}", + pragmas: {}, + buffer: [], + pragmas_implemented: { + "IMPLICIT-ITERATOR": true + }, + context: {}, + + render: function (template, context, partials, in_recursion) { + // reset buffer & set context + if (!in_recursion) { + this.context = context; + this.buffer = []; // TODO: make this non-lazy + } + + // fail fast + if (!this.includes("", template)) { + if (in_recursion) { + return template; + } else { + this.send(template); + return; + } + } + + // get the pragmas together + template = this.render_pragmas(template); + + // render the template + var html = this.render_section(template, context, partials); + + // render_section did not find any sections, we still need to render the tags + if (html === false) { + html = this.render_tags(template, context, partials, in_recursion); + } + + if (in_recursion) { + return html; + } else { + this.sendLines(html); + } + }, + + /* + Sends parsed lines + */ + send: function (line) { + if (line !== "") { + this.buffer.push(line); + } + }, + + sendLines: function (text) { + if (text) { + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) { + this.send(lines[i]); + } + } + }, + + /* + Looks for %PRAGMAS + */ + render_pragmas: function (template) { + // no pragmas + if (!this.includes("%", template)) { + return template; + } + + var that = this; + var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { + return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); + }); + + return template.replace(regex, function (match, pragma, options) { + if (!that.pragmas_implemented[pragma]) { + throw({message: + "This implementation of mustache doesn't understand the '" + + pragma + "' pragma"}); + } + that.pragmas[pragma] = {}; + if (options) { + var opts = options.split("="); + that.pragmas[pragma][opts[0]] = opts[1]; + } + return ""; + // ignore unknown pragmas silently + }); + }, + + /* + Tries to find a partial in the curent scope and render it + */ + render_partial: function (name, context, partials) { + name = trim(name); + if (!partials || partials[name] === undefined) { + throw({message: "unknown_partial '" + name + "'"}); + } + if (!context || typeof context[name] != "object") { + return this.render(partials[name], context, partials, true); + } + return this.render(partials[name], context[name], partials, true); + }, + + /* + Renders inverted (^) and normal (#) sections + */ + render_section: function (template, context, partials) { + if (!this.includes("#", template) && !this.includes("^", template)) { + // did not render anything, there were no sections + return false; + } + + var that = this; + + var regex = this.getCachedRegex("render_section", function (otag, ctag) { + // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder + return new RegExp( + "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) + + otag + // {{ + "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3) + ctag + // }} + + "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped + + otag + // {{ + "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). + ctag + // }} + + "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. + + "g"); + }); + + + // for each {{#foo}}{{/foo}} section do... + return template.replace(regex, function (match, before, type, name, content, after) { + // before contains only tags, no sections + var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", + + // after may contain both sections and tags, so use full rendering function + renderedAfter = after ? that.render(after, context, partials, true) : "", + + // will be computed below + renderedContent, + + value = that.find(name, context); + + if (type === "^") { // inverted section + if (!value || Array.isArray(value) && value.length === 0) { + // false or empty list, render it + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } else if (type === "#") { // normal section + if (Array.isArray(value)) { // Enumerable, Let's loop! + renderedContent = that.map(value, function (row) { + return that.render(content, that.create_context(row), partials, true); + }).join(""); + } else if (that.is_object(value)) { // Object, Use it as subcontext! + renderedContent = that.render(content, that.create_context(value), + partials, true); + } else if (typeof value == "function") { + // higher order section + renderedContent = value.call(context, content, function (text) { + return that.render(text, context, partials, true); + }); + } else if (value) { // boolean section + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } + + return renderedBefore + renderedContent + renderedAfter; + }); + }, + + /* + Replace {{foo}} and friends with values from our view + */ + render_tags: function (template, context, partials, in_recursion) { + // tit for tat + var that = this; + + var new_regex = function () { + return that.getCachedRegex("render_tags", function (otag, ctag) { + return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); + }); + }; + + var regex = new_regex(); + var tag_replace_callback = function (match, operator, name) { + switch(operator) { + case "!": // ignore comments + return ""; + case "=": // set new delimiters, rebuild the replace regexp + that.set_delimiters(name); + regex = new_regex(); + return ""; + case ">": // render partial + return that.render_partial(name, context, partials); + case "{": // the triple mustache is unescaped + case "&": // & operator is an alternative unescape method + return that.find(name, context); + default: // escape the value + return escapeHTML(that.find(name, context)); + } + }; + var lines = template.split("\n"); + for(var i = 0; i < lines.length; i++) { + lines[i] = lines[i].replace(regex, tag_replace_callback, this); + if (!in_recursion) { + this.send(lines[i]); + } + } + + if (in_recursion) { + return lines.join("\n"); + } + }, + + set_delimiters: function (delimiters) { + var dels = delimiters.split(" "); + this.otag = this.escape_regex(dels[0]); + this.ctag = this.escape_regex(dels[1]); + }, + + escape_regex: function (text) { + // thank you Simon Willison + if (!arguments.callee.sRE) { + var specials = [ + '/', '.', '*', '+', '?', '|', + '(', ')', '[', ']', '{', '}', '\\' + ]; + arguments.callee.sRE = new RegExp( + '(\\' + specials.join('|\\') + ')', 'g' + ); + } + return text.replace(arguments.callee.sRE, '\\$1'); + }, + + /* + find `name` in current `context`. That is find me a value + from the view object + */ + find: function (name, context) { + name = trim(name); + + // Checks whether a value is thruthy or false or 0 + function is_kinda_truthy(bool) { + return bool === false || bool === 0 || bool; + } + + var value; + + // check for dot notation eg. foo.bar + if (name.match(/([a-z_]+)\./ig)) { + var childValue = this.walk_context(name, context); + if (is_kinda_truthy(childValue)) { + value = childValue; + } + } else { + if (is_kinda_truthy(context[name])) { + value = context[name]; + } else if (is_kinda_truthy(this.context[name])) { + value = this.context[name]; + } + } + + if (typeof value == "function") { + return value.apply(context); + } + if (value !== undefined) { + return value; + } + // silently ignore unkown variables + return ""; + }, + + walk_context: function (name, context) { + var path = name.split('.'); + // if the var doesn't exist in current context, check the top level context + var value_context = (context[path[0]] != undefined) ? context : this.context; + var value = value_context[path.shift()]; + while (value != undefined && path.length > 0) { + value_context = value; + value = value[path.shift()]; + } + // if the value is a function, call it, binding the correct context + if (typeof value == "function") { + return value.apply(value_context); + } + return value; + }, + + // Utility methods + + /* includes tag */ + includes: function (needle, haystack) { + return haystack.indexOf(this.otag + needle) != -1; + }, + + // by @langalex, support for arrays of strings + create_context: function (_context) { + if (this.is_object(_context)) { + return _context; + } else { + var iterator = "."; + if (this.pragmas["IMPLICIT-ITERATOR"]) { + iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; + } + var ctx = {}; + ctx[iterator] = _context; + return ctx; + } + }, + + is_object: function (a) { + return a && typeof a == "object"; + }, + + /* + Why, why, why? Because IE. Cry, cry cry. + */ + map: function (array, fn) { + if (typeof array.map == "function") { + return array.map(fn); + } else { + var r = []; + var l = array.length; + for(var i = 0; i < l; i++) { + r.push(fn(array[i])); + } + return r; + } + }, + + getCachedRegex: function (name, generator) { + var byOtag = regexCache[this.otag]; + if (!byOtag) { + byOtag = regexCache[this.otag] = {}; + } + + var byCtag = byOtag[this.ctag]; + if (!byCtag) { + byCtag = byOtag[this.ctag] = {}; + } + + var regex = byCtag[name]; + if (!regex) { + regex = byCtag[name] = generator(this.otag, this.ctag); + } + + return regex; + } + }; + + return({ + name: "mustache.js", + version: "0.4.0", + + /* + Turns a template and view into HTML + */ + to_html: function (template, view, partials, send_fun) { + var renderer = new Renderer(); + if (send_fun) { + renderer.send = send_fun; + } + renderer.render(template, view || {}, partials); + if (!send_fun) { + return renderer.buffer.join("\n"); + } + } + }); +}(); +/*! + ICanHaz.js -- by @HenrikJoreteg +*/ +/*global */ +(function () { + function trim(stuff) { + if (''.trim) return stuff.trim(); + else return stuff.replace(/^\s+/, '').replace(/\s+$/, ''); + } + var ich = { + VERSION: "0.10", + templates: {}, + + // grab jquery or zepto if it's there + $: (typeof window !== 'undefined') ? window.jQuery || window.Zepto || null : null, + + // public function for adding templates + // can take a name and template string arguments + // or can take an object with name/template pairs + // We're enforcing uniqueness to avoid accidental template overwrites. + // If you want a different template, it should have a different name. + addTemplate: function (name, templateString) { + if (typeof name === 'object') { + for (var template in name) { + this.addTemplate(template, name[template]); + } + return; + } + if (ich[name]) { + console.error("Invalid name: " + name + "."); + } else if (ich.templates[name]) { + console.error("Template \"" + name + " \" exists"); + } else { + ich.templates[name] = templateString; + ich[name] = function (data, raw) { + data = data || {}; + var result = Mustache.to_html(ich.templates[name], data, ich.templates); + return (ich.$ && !raw) ? ich.$(result) : result; + }; + } + }, + + // clears all retrieval functions and empties cache + clearAll: function () { + for (var key in ich.templates) { + delete ich[key]; + } + ich.templates = {}; + }, + + // clears/grabs + refresh: function () { + ich.clearAll(); + ich.grabTemplates(); + }, + + // grabs templates from the DOM and caches them. + // Loop through and add templates. + // Whitespace at beginning and end of all templates inside