Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit.

  • Loading branch information...
commit c6e72a4e5dd4aaad0a54f09c9b8d24e50b2a1f7e 1 parent 9ff6cfb
@WebSeed WebSeed authored
View
24 config.rb
@@ -0,0 +1,24 @@
+# Require any additional compass plugins here.
+
+# Set this to the root of your project when deployed:
+http_path = "/"
+css_dir = "stylesheets"
+sass_dir = "sass"
+images_dir = "images"
+javascripts_dir = "javascripts"
+
+# You can select your preferred output style here (can be overridden via the command line):
+# output_style = :expanded or :nested or :compact or :compressed
+
+# To enable relative paths to assets via compass helper functions. Uncomment:
+# relative_assets = true
+
+# To disable debugging comments that display the original location of your selectors. Uncomment:
+# line_comments = false
+
+
+# If you prefer the indented syntax, you might want to regenerate this
+# project again passing --syntax sass, or you can uncomment this:
+# preferred_syntax = :sass
+# and then run:
+# sass-convert -R --from scss --to sass sass scss && rm -rf sass && mv scss sass
View
60 default.html
@@ -0,0 +1,60 @@
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Viewporter</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" href="stylesheets/normalize.css">
+ <link rel="stylesheet" href="stylesheets/main.css">
+ </head>
+ <body>
+ <header class="header group">
+ <div class="container">
+ <h1 class="trafalgar">Viewporter</h1>
+ <p class="great-primer">An <a href="http://news.bbc.co.uk/sport1/hi/football/euro_2008/7479459.stm">“absolutely phenomonal”</a> tool for viewing websites at any size.</p>
+ <!--<p>You want your designs to stand the test of time, just like Motty's commentary has.</p>-->
+ </div>
+ </header>
+ <div role="main">
+ <section class="group size-section">
+ <div class="group container">
+ <div class="region size-description">
+ <h2>Any site at any size</h2>
+ <h3 class="pica">Designing for the unknown</h3>
+ <p class="lead">
+ Make sure that your content adapts and scales properly at any width and height, find the breaking-point in the design and apply tweaks appropriately.
+ </p>
+ </div>
+ <div class="region size-figure">
+ <figure>
+ <img src="stylesheets/images/url_size_toggle.png">
+ <figcaption class="img-caption long-primer">Quickly toggle between size and URL input</figcaption>
+ </figure>
+ </div>
+ </section>
+ <section class="group presets-section">
+ <div class="group container">
+ <div class="region presets-description">
+ <h2>Presets</h2>
+ </div>
+ <div class="region presets-figure">
+ <figure>
+ <img src="stylesheets/images/preset_box.png">
+ <figcaption class="img-caption long-primer">Store preset sizes relevant to your project</figcaption>
+ </figure>
+ </div>
+ </section>
+ <section class="group saving-section">
+ <div class="group container">
+ <div class="region saving-description">
+ <h2>State Saving</h2>
+ </div>
+ <div class="region saving-figure">
+ <figure>
+ <img src="stylesheets/images/saving.png">
+ <figcaption class="img-caption long-primer">Quickly toggle between size and URL input</figcaption>
+ </figure>
+ </div>
+ </section>
+ </div>
+ </body>
+</html>
View
97 index.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta charset="utf-8">
+ <title>Viewporter</title>
+ <meta name="viewport" content="width=device-width">
+ <link rel="stylesheet" href="stylesheets/normalize.css">
+ <link rel="stylesheet" href="stylesheets/viewporter.css">
+ <script>
+ /*
+ (function () {
+ var params = {}, qs = location.search.substring(1), re = /([^&=]+)=([^&]*)/g, m;
+ while (m = re.exec(qs))
+ params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
+ window.viewporter = {params: params};
+ } ());
+ */
+ </script>
+
+ <script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
+ <script src="js/mousetrap.min.js"></script>
+ <script src="js/utils.js"></script>
+ <script src="js/viewporter.js"></script>
+ </head>
+ <body>
+ <h1 class="visually-hidden">Viewporter</h1>
+ <noscript>Oops, your browser doesn't support JavaScript or it is disabled.</noscript>
+ <script>
+ /* var url = viewporter.params.url || 'default.html'; */
+ document.write('<div id="viewport-container"><iframe id="viewport" src="http://www.bbc.co.uk/sport/winter-olympics/2014"></iframe></div>');
+ </script>
+
+ <section id="main-menu" class="menu main-menu mode-url">
+ <a id="presets-btn" class="toggle-btn presets-btn h-bdr" href="#"><span class="icon"></span> <span class="label">Presets</span></a>
+ <a id="share-btn" class="toggle-btn share-btn h-bdr" href="#"><span class="icon"></span> <span class="label">Share</span></a>
+ <div class="mode-menu">
+
+ <section id="size-menu" class="menu size-menu h-bdr">
+ <form class="size-form" method="get" action="index.html">
+ <label for="size-width-input" class="size-lbl size-width-lbl">W</label>
+ <input id="size-width-input" class="menu-item text-input size-width-input" type="text" placeholder="Auto" />
+ <label for="size-height-input" class="size-lbl size-height-lbl">H</label>
+ <input id="size-height-input" class="menu-item text-input size-height-input" type="text" placeholder="Auto" />
+ <input type="submit" name="resize" value="Resize" id="resize-btn" class="menu-item menu-btn resize-btn" />
+ </form>
+ </section>
+
+ <section id="url-menu" class="menu url-menu h-bdr">
+ <form class="url-form" method="get" action="index.html">
+ <label class="visually-hidden" for="url">URL</label>
+ <input id="url-input" class="menu-item text-input url-input" type="url" name="url" placeholder="Enter a URL" />
+ <input type="submit" value="Set" id="url-btn" class="menu-item menu-btn url-btn" />
+ </form>
+ </section>
+
+ </div>
+ <a id="help-btn" class="toggle-btn help-btn h-bdr" href="#"><span class="label">Help</span></a>
+ <a id="mode-btn" class="toggle-btn mode-btn h-bdr mode-size" href="#"><span class="icon"></span> <span class="label">URL</span></a>
+ </section>
+
+ <!-- Presets panel -->
+ <section id="presets-panel" class="panel presets-panel edit-disabled" style="display: none">
+ <table id="presets-table" class="table presets-table">
+ <colgroup>
+ <col class="col-name" />
+ <col class="col-size" />
+ <col class="col-kb" />
+ <col class="col-delete" />
+ <col class="col-move" />
+ </colgroup>
+ <thead>
+ <tr>
+ <th class="col-name" scope="col">Name</th>
+ <th class="col-size" scope="col">
+ <span class="icon icon-size" title="Size">Size</span>
+ </th>
+ <th class="col-kb" scope="col">
+ <span class="icon icon-kb" title="Keyboard shortcut">Keyboard shortcut</span>
+ </th>
+ <th class="col-delete" scope="col">Delete</th>
+ <th class="col-move" scope="col">Move</th>
+ </tr>
+ </thead>
+ <tbody>
+ </tbody>
+ </table>
+ <footer class="menu presets-footer-menu">
+ <div class="save-container h-bdr-l">
+ <a id="save-current-as-preset-btn" href="#" class="menu-item menu-btn save-btn"><span class="icon icon-save-white"></span>Save current</a>
+ </div>
+ <a id="presets-edit-btn" class="toggle-btn edit-btn h-bdr-r" href="#"><span class="icon"></span> <span class="label">Edit</span></a>
+ </footer>
+ </section>
+
+ <section id="flash-info" class="flash-info"></section>
+ </body>
+</html>
View
8 js/mousetrap.min.js
@@ -0,0 +1,8 @@
+/* mousetrap v1.3 craig.is/killing/mice */
+(function(){function s(a,c,b){a.addEventListener?a.addEventListener(c,b,!1):a.attachEvent("on"+c,b)}function y(a){return"keypress"==a.type?String.fromCharCode(a.which):h[a.which]?h[a.which]:z[a.which]?z[a.which]:String.fromCharCode(a.which).toLowerCase()}function t(a,c){a=a||{};var b=!1,d;for(d in m)a[d]&&m[d]>c?b=!0:m[d]=0;b||(p=!1)}function A(a,c,b,d,g){var f,e,h=[],j=b.type;if(!l[a])return[];"keyup"==j&&u(a)&&(c=[a]);for(f=0;f<l[a].length;++f)if(e=l[a][f],!(e.seq&&m[e.seq]!=e.level)&&j==e.action&&
+("keypress"==j&&!b.metaKey&&!b.ctrlKey||c.sort().join(",")===e.modifiers.sort().join(",")))d&&e.combo==g&&l[a].splice(f,1),h.push(e);return h}function v(a,c,b){if(!k.stopCallback(c,c.target||c.srcElement,b)&&!1===a(c,b))c.preventDefault&&c.preventDefault(),c.stopPropagation&&c.stopPropagation(),c.returnValue=!1,c.cancelBubble=!0}function w(a){"number"!==typeof a.which&&(a.which=a.keyCode);var c=y(a);if(c)if("keyup"==a.type&&x==c)x=!1;else{var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");
+a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");var b=A(c,b,a),d,g={},f=0,e=!1;for(d=0;d<b.length;++d)b[d].seq?(e=!0,f=Math.max(f,b[d].level),g[b[d].seq]=1,v(b[d].callback,a,b[d].combo)):!e&&!p&&v(b[d].callback,a,b[d].combo);a.type==p&&!u(c)&&t(g,f)}}function u(a){return"shift"==a||"ctrl"==a||"alt"==a||"meta"==a}function B(a,c,b){if(!b){if(!q){q={};for(var d in h)95<d&&112>d||h.hasOwnProperty(d)&&(q[h[d]]=d)}b=q[a]?"keydown":"keypress"}"keypress"==b&&c.length&&(b="keydown");return b}function C(a,
+c,b,d,g){r[a+":"+b]=c;a=a.replace(/\s+/g," ");var f=a.split(" "),e,h,j=[];if(1<f.length){var k=a,n=b;m[k]=0;n||(n=B(f[0],[]));a=function(){p=n;++m[k];clearTimeout(D);D=setTimeout(t,1E3)};b=function(a){v(c,a,k);"keyup"!==n&&(x=y(a));setTimeout(t,10)};for(d=0;d<f.length;++d)C(f[d],d<f.length-1?a:b,n,k,d)}else{h="+"===a?["+"]:a.split("+");for(f=0;f<h.length;++f)e=h[f],E[e]&&(e=E[e]),b&&("keypress"!=b&&F[e])&&(e=F[e],j.push("shift")),u(e)&&j.push(e);b=B(e,j,b);l[e]||(l[e]=[]);A(e,j,{type:b},!d,a);l[e][d?
+"unshift":"push"]({callback:c,modifiers:j,action:b,seq:d,level:g,combo:a})}}for(var h={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},z={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},F={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6",
+"&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},E={option:"alt",command:"meta","return":"enter",escape:"esc"},q,l={},r={},m={},D,x=!1,p=!1,g=1;20>g;++g)h[111+g]="f"+g;for(g=0;9>=g;++g)h[g+96]=g;s(document,"keypress",w);s(document,"keydown",w);s(document,"keyup",w);var k={bind:function(a,c,b){a=a instanceof Array?a:[a];for(var d=0;d<a.length;++d)C(a[d],c,b);return this},unbind:function(a,c){return k.bind(a,function(){},c)},trigger:function(a,c){if(r[a+
+":"+c])r[a+":"+c]();return this},reset:function(){l={};r={};return this},stopCallback:function(a,c){return-1<(" "+c.className+" ").indexOf(" mousetrap ")?!1:"INPUT"==c.tagName||"SELECT"==c.tagName||"TEXTAREA"==c.tagName||c.contentEditable&&"true"==c.contentEditable}};window.Mousetrap=k;"function"===typeof define&&define.amd&&define(k)})();
View
36 js/utils.js
@@ -0,0 +1,36 @@
+/* http://api.jquery.com/jQuery.Callbacks/ */
+var topics = {};
+jQuery.Topic = function(id) {
+ var callbacks,
+ method,
+ topic = id && topics[id];
+ if (!topic) {
+ callbacks = jQuery.Callbacks();
+ topic = {
+ publish: callbacks.fire,
+ subscribe: callbacks.add,
+ unsubscribe: callbacks.remove
+ };
+ if (id) {
+ topics[id] = topic;
+ }
+ }
+ return topic;
+};
+
+Function.prototype.debounce = function (threshold, execAsap) {
+ var func = this, timeout;
+ return function debounced () {
+ var obj = this, args = arguments;
+ function delayed () {
+ if (!execAsap)
+ func.apply(obj, args);
+ timeout = null;
+ };
+ if (timeout)
+ clearTimeout(timeout);
+ else if (execAsap)
+ func.apply(obj, args);
+ timeout = setTimeout(delayed, threshold || 100);
+ };
+};
View
843 js/viewporter.js
@@ -0,0 +1,843 @@
+$(function (w) {
+
+ var viewporter = {
+
+ MODE_SIZE: "size",
+ MODE_URL: "url",
+
+ init: function () {
+
+ var self = this;
+
+ this.subscribe();
+
+ this.params = this.getParams();
+
+ this.viewport = $('#viewport');
+ this.viewportContainer = $('#viewport-container');
+
+ this.mainMenu = $('#main-menu');
+
+ this.mode = this.MODE_SIZE;
+ this.modeButton = $('#mode-btn');
+
+ this.shareButton = $('#share-btn');
+
+ this.helpButton = $('#help-btn');
+
+ this.flashInfo.init();
+
+ this.urlUI.init();
+ this.urlModel.init(
+ this.getFromParamOrStorage('url')
+ );
+
+ this.sizeUI.init();
+ this.sizeModel.init(
+ this.getFromParamOrStorage('width'),
+ this.getFromParamOrStorage('height')
+ );
+
+ this.presetsUI.init();
+ this.presetsModel.init(this.sizeModel);
+
+ this.bindKeyboardShortcuts();
+
+ this.shareButton.on('click', function () {
+
+ var qs,
+ shareUrl;
+
+ if (!window.location.origin) {
+ window.location.origin = window.location.protocol + "//" + window.location.host;
+ }
+
+ qs = '/viewporter/index.html?url=' + encodeURIComponent(self.urlModel.url) +
+ (self.sizeModel.width ? ('&width=' + encodeURIComponent(self.sizeModel.width)) : '') +
+ (self.sizeModel.height ? ('&height=' + encodeURIComponent(self.sizeModel.height)) : '');
+ shareUrl = window.location.origin + qs;
+
+ window.prompt('Copy and paste the following URL into your browser', shareUrl);
+ });
+
+ this.helpButton.on('click', function () {
+ self.showHelp();
+ });
+
+ this.modeButton.on('click', function () {
+ self.toggleMode();
+ });
+
+
+ },
+ getFromParamOrStorage: function (key) {
+ var value;
+ if (this.params[key]) {
+ value = this.params[key];
+ console.log("Fetched '" + key + "' from params (" + value + ")");
+ } else {
+ value = localStorage.getItem(key);
+
+ if (!value) {
+ value = '';
+ }
+
+ console.log("Fetched '" + key + "' from local storage (" + value + ")");
+ }
+ return value;
+ },
+ subscribe: function () {
+
+ var self = this;
+
+ $.Topic("sizeModel:didResize").subscribe(function (width, height) {
+ localStorage.setItem("width", width);
+ localStorage.setItem("height", height);
+ self.sizeIFrame(width, height);
+ });
+
+ $.Topic('urlModel:didChangeUrl').subscribe(function (url) {
+ localStorage.setItem("url", url);
+ self.setUrl(url);
+ });
+
+ $.Topic("presetsModel:didSelectPreset").subscribe(function (preset) {
+ self.sizeWithPreset(preset);
+ });
+
+ $.Topic("viewporter:toggleFullscreen").subscribe(function () {
+ self.mainMenu.toggleClass('hidden');
+ self.viewportContainer.toggleClass('fullscreen');
+ });
+ },
+ getParams: function () {
+ var params = {}, qs = location.search.substring(1), re = /([^&=]+)=([^&]*)/g, m;
+ while (m = re.exec(qs)) {
+ params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
+ }
+ return params;
+ },
+ toggleMode: function () {
+
+ var label = this.modeButton.find('.label');
+
+ if (this.mode === this.MODE_SIZE) {
+ this.mode = this.MODE_URL;
+ this.modeButton.removeClass('mode-size').addClass('mode-url');
+ label.text("Size");
+ $.Topic("viewporter:didChangeToUrlMode").publish();
+ } else if (this.mode === this.MODE_URL) {
+ this.mode = this.MODE_SIZE;
+ this.modeButton.removeClass('mode-url').addClass('mode-size');
+ label.text("URL");
+ $.Topic("viewporter:didChangeToSizeMode").publish();
+ }
+ },
+ sizeWithPreset: function (preset) {
+ this.sizeIFrame(preset.width, preset.height);
+ },
+ bindKeyboardShortcuts: function () {
+
+ var self = this;
+
+ /* F: Toggle fullscreen */
+ Mousetrap.bind('f', function (e) {
+ $.Topic('viewporter:toggleFullscreen').publish();
+ });
+
+ /* M: Togle mode */
+ Mousetrap.bind('m', function () {
+ self.toggleMode();
+ });
+
+ /* P: Presets */
+ Mousetrap.bind('p', function (e) {
+ self.presetsUI.toggleActive();
+ });
+
+ /* Numeric keyboard shortcuts */
+ Mousetrap.bind('1', function (e) { self.presetsModel.selectPresetByIndex(0) });
+ Mousetrap.bind('2', function (e) { self.presetsModel.selectPresetByIndex(1) });
+ Mousetrap.bind('3', function (e) { self.presetsModel.selectPresetByIndex(2) });
+ Mousetrap.bind('4', function (e) { self.presetsModel.selectPresetByIndex(3) });
+ Mousetrap.bind('5', function (e) { self.presetsModel.selectPresetByIndex(4) });
+ Mousetrap.bind('6', function (e) { self.presetsModel.selectPresetByIndex(5) });
+ Mousetrap.bind('7', function (e) { self.presetsModel.selectPresetByIndex(6) });
+ Mousetrap.bind('8', function (e) { self.presetsModel.selectPresetByIndex(7) });
+ Mousetrap.bind('9', function (e) { self.presetsModel.selectPresetByIndex(8) });
+ },
+ setUrl: function (url) {
+ this.viewport.attr('src', url);
+ },
+ sizeIFrame: function (width, height) {
+ this.viewport.width((!width || width === 'Auto') ? '100%' : width);
+ this.viewport.height((!height || height === 'Auto') ? '99%' : height);
+ },
+ showHelp: function () {
+ this.urlModel.setUrl('default.html');
+ },
+ };
+
+ viewporter.flashInfo = {
+ init: function () {
+ this.panel = $('#flash-info');
+ this.subscribe();
+ this.timeoutId = null;
+ },
+ subscribe: function () {
+
+ var self = this;
+
+ $.Topic("viewporter:toggleFullscreen").subscribe(function () {
+ self.showMessage("Fullscreen toggled");
+ });
+
+ $.Topic("sizeModel:didResize").subscribe(function (width, height) {
+ self.showMessage("Resized to " + (width ? width : "Auto") + " &times; " + (height ? height : "Auto"));
+ });
+
+ $.Topic("presetsModel:didSelectPreset").subscribe(function (preset) {
+ self.showMessage(preset.name);
+ });
+
+ $.Topic("viewporter:didChangeToUrlMode").subscribe(function () {
+ self.showMessage("URL Mode");
+ });
+
+ $.Topic("viewporter:didChangeToSizeMode").subscribe(function () {
+ self.showMessage("Size Mode");
+ });
+
+ $.Topic('urlModel:didChangeUrl').subscribe(function (url) {
+ self.showMessage(url);
+ });
+ },
+ showMessage: function (message) {
+ var self = this;
+ self.panel.html(message);
+ self.panel.stop(true, true);
+
+ if (self.timeoutId) {
+ window.clearTimeout(self.timeoutId);
+ self.timeoutId = null;
+ }
+
+ self.panel.css('display', 'block').css('opacity', '100');
+ self.timeoutId = window.setTimeout(function () {
+ self.panel.fadeOut(500, function () {
+ self.panel.css('display', 'none');
+ self.timeoutId = null;
+ });
+ }, 1000);
+ }
+ };
+
+ viewporter.urlModel = {
+ init: function (url) {
+ this.setUrl(url || 'http://www.bbc.co.uk/sport/winter-olympics/2014');
+ this.subscribe();
+ },
+ subscribe: function () {
+ var self = this;
+ $.Topic('urlUI:didChangeUrl').subscribe(function (url) {
+ self.setUrl(url);
+ });
+ },
+ setUrl: function (url) {
+ this.url = url;
+ $.Topic('urlModel:didChangeUrl').publish(url);
+ }
+ };
+
+ viewporter.urlUI = {
+ init: function () {
+
+ var self = this;
+
+ this.menu = $('#url-menu');
+ this.urlInput = $('#url-input');
+ this.urlButton = $('#url-btn');
+ this.active = false;
+
+ this.urlButton.on('click', function (e) {
+ e.preventDefault();
+ self.urlButtonPressed();
+ })
+
+ this.subscribe();
+ },
+ subscribe: function () {
+
+ var self = this;
+
+ $.Topic("viewporter:didChangeToUrlMode").subscribe(function () {
+ self.activate();
+ });
+
+ $.Topic("viewporter:didChangeToSizeMode").subscribe(function () {
+ self.deactivate();
+ });
+
+ $.Topic('urlModel:didChangeUrl').subscribe(function (url) {
+ self.setUrl(url);
+ });
+ },
+ setUrl: function (url) {
+
+ url = url !== null ? url : '';
+
+ if (this.urlInput.val() !== url) {
+ this.urlInput.val(url);
+ }
+ },
+ urlButtonPressed: function () {
+ $.Topic('urlUI:didChangeUrl').publish(this.urlInput.val());
+ },
+ toggleActive: function () {
+ if (this.active) {
+ this.deactivate();
+ } else {
+ this.activate();
+ }
+ },
+ activate: function () {
+ if (!this.active) {
+ //this.urlInput.focus();
+ this.active = true;
+ this.menu.addClass('active');
+ $.Topic('urlUI:didActivate').publish();
+ }
+ },
+ deactivate: function () {
+ if (this.active) {
+ this.active = false;
+ this.menu.removeClass('active');
+ $.Topic('urlUI:didDeactivate').publish();
+ }
+ }
+ };
+
+ viewporter.sizeModel = {
+ init: function (width, height) {
+
+ var self = this;
+ this.setSize(width, height);
+
+ self.subscribe();
+ },
+ subscribe: function () {
+
+ var self = this;
+
+ $.Topic('sizeUI:resizeButtonPressed').subscribe(function (width, height) {
+ self.setSize(width, height);
+ });
+ },
+ setSize: function (width, height) {
+ this.width = width;
+ this.height = height;
+ $.Topic('sizeModel:didResize').publish(this.width, this.height);
+ }
+ };
+
+ viewporter.sizeUI = {
+ init: function () {
+
+ var self = this;
+
+ this.menu = $('#size-menu');
+
+ this.widthInput = $('#size-width-input');
+ this.heightInput = $('#size-height-input');
+
+ this.resizeButton = $('#resize-btn');
+
+ this.resizeButton.on('click', function (e) {
+ e.preventDefault();
+ self.resizeButtonPressed();
+ });
+
+ this.subscribe();
+ },
+ resizeButtonPressed: function () {
+
+ if (this.widthInput.val().toLowerCase() === 'auto') {
+ this.widthInput.val('');
+ }
+ if (this.heightInput.val().toLowerCase() === 'auto') {
+ this.heightInput.val('');
+ }
+
+ $.Topic('sizeUI:resizeButtonPressed').publish(this.widthInput.val(), this.heightInput.val());
+ },
+ subscribe: function () {
+ var self = this;
+
+ $.Topic('sizeModel:didResize').subscribe(function (width, height) {
+ self.setSize(width, height);
+ });
+ },
+ setSize: function (width, height) {
+ this.widthInput.val(width || '');
+ this.heightInput.val(height || '');
+ },
+ toggleActive: function () {
+ if (this.active) {
+ this.deactivate();
+ } else {
+ this.activate();
+ }
+ },
+ activate: function () {
+ if (!this.active) {
+ this.active = true;
+ this.menu.addClass('active');
+ this.widthInput.focus();
+ $.Topic('sizeUI:didActivate').publish();
+ }
+ },
+ deactivate: function () {
+ if (this.active) {
+ this.active = false;
+ this.menu.removeClass('active');
+ $.Topic('sizeUI:didDeactivate').publish();
+ }
+ }
+ };
+
+ viewporter.presetsModel = {
+ init: function (sizeModel) {
+
+ var defaultPresets = [
+ {
+ "id": 1,
+ "name": "Tiny Mobile",
+ "width": "240px",
+ "height": "Auto"
+ },
+ {
+ "id": 2,
+ "name": "Smartphone Portrait",
+ "width": "320px",
+ "height": "Auto"
+ },
+ {
+ "id": 3,
+ "name": "Smartphone Landscape",
+ "width": "500px",
+ "height": "Auto"
+ },
+ {
+ "id": 4,
+ "name": "Tablet Landscape",
+ "width": "1008px",
+ "height": "Auto"
+ },
+ {
+ "id": 5,
+ "name": "Desktop",
+ "width": "1024px",
+ "height": "Auto"
+ },
+ {
+ "id": 6,
+ "name": "Wide Desktop",
+ "width": "1280px",
+ "height": "Auto"
+ }
+ ],
+ presets;
+
+ this.sizeModel = sizeModel;
+ this.maxPresetId = -1;
+ this.presets = [];
+ this.presetsById = {};
+ this.selectedPreset = null;
+
+ /* Fetch from local storage */
+ if (localStorage.getItem("presets") !== null) {
+ this.presets = JSON.parse(localStorage.getItem("presets"));
+ }
+ /* Retrieve from local storage */
+ else {
+ this.presets = defaultPresets;
+ this.save();
+ }
+
+ this.initPresets();
+
+ this.subscribe();
+ },
+ subscribe: function () {
+
+ var self = this;
+
+ $.Topic("presetsUI:saveCurrentAsPreset").subscribe(function () {
+ self.addNewPreset(self.sizeModel.width, self.sizeModel.height);
+ });
+
+ $.Topic('presetUI:selectPreset').subscribe(function (presetId) {
+ self.selectPreset(self.presetsById[presetId]);
+ });
+
+ $.Topic('presetUI:deletePreset').subscribe(function (presetId) {
+ self.deletePreset(self.presetsById[presetId]);
+ });
+
+ $.Topic('presetUI:moveUpPreset').subscribe(function (presetId) {
+ self.movePresetUp(self.presetsById[presetId]);
+ });
+
+ $.Topic('presetUI:moveDownPreset').subscribe(function (presetId) {
+ self.movePresetDown(self.presetsById[presetId]);
+ });
+
+ $.Topic('presetUI:changePresetName').subscribe(function (presetId, name) {
+ self.changePresetName(self.presetsById[presetId], name);
+ });
+ },
+ initPresets: function () {
+ var len = this.presets.length,
+ preset,
+ i;
+
+ /* sortedPresets = presets.slice();
+ sortedPresets.sort(this.sortByOrder); */
+
+ for (i = 0; i < len; i++) {
+ preset = this.presets[i];
+
+ if (preset.id > this.maxPresetId) {
+ this.maxPresetId = preset.id;
+ }
+
+ this.presetsById[preset.id] = preset;
+ $.Topic("presetsModel:didAppendPreset").publish(preset);
+ }
+ },
+ save: function () {
+ localStorage.setItem("presets", JSON.stringify(this.presets));
+ },
+ nextPresetId: function () {
+ return ++this.maxPresetId;
+ },
+ addNewPreset: function (width, height) {
+
+ var presetId = this.nextPresetId(),
+ preset = {
+ "id": presetId,
+ "name": "New preset #" + presetId,
+ "width": width ? width : "Auto",
+ "height": height ? height : "Auto"
+ };
+
+ this.presets.push(preset);
+ this.presetsById[preset.id] = preset;
+ $.Topic("presetsModel:didAppendPreset").publish(preset);
+ this.selectPreset(preset);
+ this.save();
+ },
+ deselectSelectedPreset: function () {
+ this.selectPreset(null);
+ },
+ selectPresetByIndex: function (presetIndex) {
+ if (presetIndex < this.presets.length) {
+ this.selectPreset(this.presets[presetIndex]);
+ }
+ },
+ selectPreset: function (preset) {
+
+ var deselectedPreset = this.selectedPreset;
+ this.selectedPreset = preset;
+
+ if (deselectedPreset !== null) {
+ $.Topic("presetsModel:didDeselectPreset").publish(deselectedPreset);
+ }
+
+ if (preset !== null) {
+ $.Topic("presetsModel:didSelectPreset").publish(this.selectedPreset);
+ }
+ },
+ changePresetName: function (preset, name) {
+ preset.name = name;
+ this.save();
+ $.Topic("presetsModel:didChangePresetName").publish(preset);
+ },
+ movePresetUp: function (preset) {
+ var index = this.presets.indexOf(preset),
+ presetToSwap;
+ if (index > 0) {
+ presetToSwap = this.presets[index - 1];
+ this.presets[index - 1] = preset;
+ this.presets[index] = presetToSwap;
+ this.save();
+ $.Topic("presetsModel:didSwapPresets").publish(preset, presetToSwap);
+ }
+ },
+ movePresetDown: function (preset) {
+ var index = this.presets.indexOf(preset),
+ presetToSwap;
+ if (index < this.presets.length - 1) {
+ presetToSwap = this.presets[index + 1];
+ this.presets[index + 1] = preset;
+ this.presets[index] = presetToSwap;
+ this.save();
+ $.Topic("presetsModel:didSwapPresets").publish(presetToSwap, preset);
+ }
+ },
+ deletePreset: function (preset) {
+ var index = this.presets.indexOf(preset);
+ this.presets.splice(index, 1);
+ delete this.presetsById[preset.id];
+ this.save();
+ $.Topic('presetModel:didDeletePreset').publish(preset);
+ },
+ sortById: function (a, b) {
+ return ((a.id < b.id) ? -1 : ((a.id > b.id) ? 1 : 0));
+ },
+ sortByOrder: function (a, b) {
+ return ((a.order < b.order) ? -1 : ((a.order > b.order) ? 1 : 0));
+ },
+ sortByName: function (a, b) {
+ return a.name.localeCompare(b.name);
+ }
+ };
+
+ viewporter.presetsUI = {
+ init: function () {
+
+ var self = this;
+
+ this.MAX_NUM_PRESETS = 9;
+
+ this.activateToggle = $('#presets-btn');
+ this.panel = $('#presets-panel');
+ this.editToggle = $('#presets-edit-btn');
+ this.saveButton = $('#save-current-as-preset-btn');
+ this.table = $('#presets-table');
+ this.active = false;
+ this.editing = false;
+
+ this.activateToggle.on('click', function (e) {
+ e.preventDefault();
+ self.toggleActive();
+ });
+
+ this.editToggle.on('click', function (e) {
+ e.preventDefault();
+ self.toggleEdit();
+ });
+
+ this.saveButton.on('click', function (e) {
+ e.preventDefault();
+ $.Topic("presetsUI:saveCurrentAsPreset").publish();
+ });
+
+ this.subscribe();
+ },
+ subscribe: function () {
+
+ var self = this;
+
+ $.Topic("presetsModel:didSelectPreset").subscribe(function (preset) {
+ self.selectPreset(preset);
+ });
+
+ $.Topic("presetsModel:didDeselectPreset").subscribe(function (preset) {
+ self.deselectPreset(preset);
+ });
+
+ $.Topic("presetsModel:didAppendPreset").subscribe(function (preset) {
+ self.appendPreset(preset);
+ });
+
+ $.Topic('viewporter:toggleFullscreen').subscribe(function () {
+ self.toggleHidden();
+ });
+
+ $.Topic('sizeUI:didDeactivate').subscribe(function () {
+ self.disableEditing();
+ self.deactivate();
+ });
+
+ $.Topic('presetModel:didDeletePreset').subscribe(function (preset) {
+ self.deletePreset(preset);
+ });
+
+ $.Topic("presetsModel:didSwapPresets").subscribe(function (preset, presetToSwap) {
+ self.swapPresets(preset, presetToSwap);
+ });
+ },
+ getPresetRowById: function (presetId) {
+ return this.table.find('[data-id="' + presetId + '"]')
+ },
+ selectPreset: function (preset) {
+ var $row = this.getPresetRowById(preset.id);
+ $row.addClass('selected');
+ },
+ deselectPreset: function (preset) {
+ var $row = this.getPresetRowById(preset.id);
+ $row.removeClass('selected');
+ },
+ appendPreset: function (preset) {
+ var self = this,
+ row = this.rowHtml(preset);
+
+ this.table.find('tbody:last').append(row);
+
+ this.updateSaveButton();
+
+ $row = this.getPresetRowById(preset.id);
+
+ $row.on('click', function (e) {
+ if (!self.editing) {
+ e.preventDefault();
+ $.Topic('presetUI:selectPreset').publish(preset.id);
+ }
+ });
+
+ $row.find('.delete-btn').on('click', function (e) {
+ e.preventDefault();
+ $.Topic('presetUI:deletePreset').publish(preset.id);
+ });
+
+ $row.find('.move-up-btn').on('click', function (e) {
+ e.preventDefault();
+ $.Topic('presetUI:moveUpPreset').publish(preset.id);
+ });
+
+ $row.find('.move-down-btn').on('click', function (e) {
+ e.preventDefault();
+ $.Topic('presetUI:moveDownPreset').publish(preset.id);
+ });
+ },
+ deletePreset: function (preset) {
+ $row = this.getPresetRowById(preset.id);
+ $row.remove();
+ this.updateSaveButton();
+ },
+ swapPresets: function (presetA, presetB) {
+ var row1 = this.getPresetRowById(presetA.id),
+ row2 = this.getPresetRowById(presetB.id);
+ row1.after(row2);
+ },
+ updateSaveButton: function () {
+ if (this.table.find('.preset-row').length >= this.MAX_NUM_PRESETS) {
+ this.saveButton.hide();
+ } else {
+ this.saveButton.show();
+ }
+ },
+ rowHtml: function (preset) {
+
+ /* NOTE: Preset properties must not contain special characters */
+
+ var name = preset.name.replace(/"/g , "&#34;"),
+ row = '\
+ <tr class="preset-row" data-id="' + preset.id + '">\
+ <td class="col-name">\
+ <div class="name">\
+ <span class="label">' + name + '</span>\
+ <input class="menu-item text-input" type="text" value="' + name + '" />\
+ </div>\
+ </td>\
+ <td>' + preset.width + ' &times; ' + preset.height + '</td>\
+ <td class="col-kb"></td>\
+ <td class="col-delete">\
+ <a href="#" class="cell-btn delete-btn">\
+ <span class="icon" title="Delete">Delete</span>\
+ </a>\
+ </td>\
+ <td class="col-move">\
+ <a href="#" class="cell-btn move-up-btn">\
+ <span class="icon" title="Move up">Move up</span>\
+ </a><a href="#" class="cell-btn move-down-btn">\
+ <span class="icon" title="Move down">Move down</span>\
+ </a>\
+ </td>\
+ </tr>';
+
+ return row;
+ },
+ toggleHidden: function () {
+ if (this.active) {
+ if (this.hidden) {
+ this.hidden = false;
+ this.panel.show();
+ } else {
+ this.hidden = true;
+ this.panel.hide();
+ }
+ }
+ },
+ toggleActive: function () {
+ if (this.active) {
+ this.deactivate();
+ } else {
+ this.activate();
+ }
+ },
+ activate: function () {
+ this.active = true;
+ this.activateToggle.addClass('active');
+ this.panel.fadeIn(250);
+ },
+ deactivate: function () {
+ this.active = false;
+ this.activateToggle.removeClass('active');
+ this.panel.hide();
+ },
+ toggleEdit: function () {
+
+ var self = this,
+ rowInput,
+ rowLabel,
+ rowInputText,
+ presetId;
+
+ if (this.editing) {
+
+ /* Check for changes */
+ $.each(this.table.find('.preset-row'), function (index, row) {
+
+ var $row = $(row);
+
+ rowInput = $row.find('.col-name .text-input');
+ rowLabel = $row.find('.col-name .label');
+ rowInputText = rowInput.val().trim();
+
+ if (rowInputText !== rowLabel.text()) {
+ rowLabel.text(rowInputText);
+ presetId = $row.data('id');
+ $.Topic('presetUI:changePresetName').publish(presetId, rowInputText);
+ }
+ })
+
+ this.disableEditing();
+ } else {
+ this.enableEditing();
+ }
+ },
+ enableEditing: function () {
+ if (!this.editing) {
+ this.editing = true;
+ this.editToggle.addClass('active');
+ this.editToggle.find('.label').text('Done');
+ this.panel.addClass('edit-enabled').removeClass('edit-disabled');
+ }
+ },
+ disableEditing: function () {
+ if (this.editing) {
+ this.editing = false;
+ this.editToggle.removeClass('active');
+ this.editToggle.find('.label').text('Edit');
+ this.panel.addClass('edit-disabled').removeClass('edit-enabled');
+ }
+ }
+ };
+
+ $(function () {
+ viewporter.init();
+ });
+
+}(this));
View
230 sass/main.scss
@@ -0,0 +1,230 @@
+@import "compass";
+
+* {
+ @include box-sizing(border-box);
+}
+
+/* Colours */
+$lab-green: #1e9c6c;
+$light-grey: #f0eeee;
+$dark-grey: #414042;
+$text-black: #444545;
+$mint-dark-shadow: #027252;
+
+/* Base styling */
+
+$base-font-size: 1.6rem;
+$base-line-height: 1.25;
+
+html {
+ margin: 0;
+ padding: 0;
+ font-size: 62.5%;
+ /* -webkit-font-smoothing: antialiased; */
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ font-family: "Arial", sans-serif;
+ background: #f5f5f5;
+ font-size: $base-font-size;
+ line-height: $base-line-height;
+ font-weight: normal;
+ color: $text-black;
+}
+
+button,
+input {
+ border: 0 none;
+ margin: 0;
+ background-color: transparent;
+}
+
+img {
+ max-width:100%;
+}
+
+a, a:visited {
+ color:$lab-green;
+ border-bottom:1px solid $light-grey;
+}
+a {
+ text-decoration: none;
+}
+
+a:focus {
+ outline: none;
+}
+
+
+.visually-hidden {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+
+/* Clearfix */
+
+.group:before,
+.group:after {
+ content: " ";
+ display: table;
+}
+.group:after {
+ clear: both;
+}
+.group {
+ *zoom: 1;
+}
+
+/* Typographic Scale */
+
+h1,.trafalgar{
+ font-size:4.8rem;
+ color:$lab-green;
+ line-height:1.5;
+ margin:0;
+ letter-spacing: -0.048rem;
+}
+h2,.double-pica{
+ font-size:2.4rem;
+ color:$lab-green;
+ margin:0 0 1.6rem;
+}
+h3,.great-primer{
+ font-size:2.0rem;
+ margin:0 0 0.4rem;
+}
+h4,.pica{
+ font-size:1.6rem;
+ color:$dark-grey;
+}
+h5,.long-primer{
+ font-size:1.3rem;
+}
+h6,.brevier {
+ font-size:1.0rem;
+}
+
+h1, .trafalgar, h2, .double-pica, h3, .great-primer {
+ font-weight:bold;
+}
+
+p {
+ margin:0 0 1.6rem;
+}
+.img-caption {
+ font-style: italic;
+ text-align: center;
+ margin:1.6rem auto 0.8rem;
+ max-width: 40rem;
+}
+
+.container
+{
+ margin:0 auto;
+ max-width:53.000em;
+ padding:0 0.8rem;
+}
+.region {
+ position: relative;
+ vertical-align: top;
+ width: 100%;
+ float:left;
+}
+section {
+ padding: 3.2rem 0;
+}
+header {
+ padding: 3.2rem 0.8rem;
+}
+
+.size-section, .saving-section {
+ background:$light-grey;
+}
+.size-description, .presets-description, .saving-description {
+ width:90%;
+ float:none;
+ margin:0 auto;
+ max-width:38rem;
+}
+.size-figure, .presets-figure, .saving-figure {
+ margin:0 auto;
+ text-align:center;
+}
+figure {
+ padding: 0.4rem 0 0;
+}
+.header {
+ text-align:center;
+}
+.header p {
+ max-width: 38rem;
+ margin:0 auto;
+}
+
+@media screen and (min-width: 28.5em){
+ section {
+ padding: 3.2rem 1.6rem;
+ }
+ header {
+ padding: 4.8rem 1.6rem 6.8rem;
+ }
+ .container {
+ width:83.333%;
+ }
+}
+
+@media screen and (min-width: 37.5em){
+ h1,.trafalgar{
+ font-size:6.4rem;
+ }
+}
+
+@media screen and (min-width: 850px){
+ section {
+ padding: 6.8rem 1.6rem;
+ }
+ .region {
+ float:left;
+ }
+ .size-description, .presets-description, .saving-description {
+ width:40%;
+ max-width:100%;
+ }
+ .size-description, .saving-description {
+ width:40%;
+ padding-left:0.8rem;
+ left:60%;
+ }
+ .presets-description {
+ padding-right:0.8rem;
+ }
+ .presets-figure {
+ padding-left:0.8rem;
+ }
+ .presets-figure, .size-figure, .saving-figure {
+ width:60%;
+ }
+ .size-figure, .saving-figure {
+ padding-right:0.8rem;
+ left:-40%;
+ }
+ figure {
+ padding: 1.6rem 0 0;
+ }
+ .header p {
+ max-width:100%;
+ }
+
+}
+
+
+
+
View
780 sass/viewporter.scss
@@ -0,0 +1,780 @@
+@import "compass";
+
+* {
+ @include box-sizing(border-box);
+}
+
+/* Colours */
+
+$grey-dark-shadow: #202020;
+$grey-shadow: #323232;
+$grey: #444444;
+$grey-highlight: #515151;
+$mint-highlight: #30a983;
+$mint-shadow: #028d5d;
+$mint-dark-shadow: #025b3c;
+$focus-yellow: #ddffcc;
+
+$table-cell-background: #efeded;
+$table-cell-selected-background: #dfdbdb;
+$table-text: #747474;
+
+/* Sizing & positioning */
+
+$menu-height: 4.8rem;
+$menu-pad: 1rem;
+$menu-item-height: $menu-height - 2 * $menu-pad;
+
+$size-menu-width: 49rem;
+$size-width: 8rem;
+$presets-width: 11rem;
+$custom-size-panel-width: $size-menu-width - $size-width - $presets-width;
+
+$url-menu-width: 32rem;
+$url-width: 8rem;
+$url-input-container-width: $url-menu-width - $url-width;
+
+@mixin input-placeholder($color) {
+ &.placeholder {
+ color: $color;
+ }
+ &:-moz-placeholder {
+ color: $color;
+ }
+ &::-webkit-input-placeholder {
+ color: $color;
+ }
+}
+
+@mixin h-menu-border {
+ border-left: 0.1rem solid rgba(255, 255, 255, 0.1);
+ border-right: 0.1rem solid rgba(0, 0, 0, 0.3);
+}
+
+.h-bdr,
+.h-bdr-l {
+ border-left: 0.1rem solid rgba(255, 255, 255, 0.1);
+}
+
+.h-bdr,
+.h-bdr-r {
+ border-right: 0.1rem solid rgba(0, 0, 0, 0.3);
+}
+
+@mixin h-recess-border {
+ border-left: 0.2rem solid rgba(0, 0, 0, 0.3);
+ border-right: 0.2rem solid rgba(0, 0, 0, 0.3);
+}
+
+@mixin v-cell-border {
+ border-top: 0.1rem solid rgba(255, 255, 255, 1.0);
+ border-bottom: 0.1rem solid rgba(0, 0, 0, 0.15);
+}
+
+@mixin v-cell-focus-border {
+ border-top: 0.1rem solid rgba(0, 0, 0, 0);
+ border-bottom: 0.1rem solid rgba(0, 0, 0, 0.15);
+}
+
+@mixin v-cell-selected-border {
+ border-top: 0.1rem solid rgba(0, 0, 0, 0.2);
+ border-bottom: 0.1rem solid rgba(0, 0, 0, 0.2);
+}
+
+/* Base styling */
+
+html {
+ margin: 0;
+ padding: 0;
+ font-size: 62.5%;
+ /* -webkit-font-smoothing: antialiased; */
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ font-family: "Arial", sans-serif;
+ color: #fff;
+ background: white; /* rgba(0, 0, 0, 0.15); */
+ font-size: 1.4rem;
+ min-width: 35rem;
+ font-weight:bold;
+}
+
+button,
+input {
+ border: 0 none;
+ margin: 0;
+ background-color: transparent;
+}
+
+a {
+ text-decoration: none;
+}
+
+a:focus {
+ outline: none;
+}
+
+.visually-hidden {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+
+/* Icons */
+
+$icon-size: 2rem;
+
+.icon {
+ display: inline-block;
+ vertical-align: middle;
+ overflow: hidden;
+ text-indent: -7999em;
+ background-image: url(images/icons-240x120.png);
+ background-size: 24rem 12rem;
+ background-repeat: no-repeat;
+ width: $icon-size;
+ height: $icon-size;
+}
+
+@media (-webkit-min-device-pixel-ratio: 1.5), (min-resolution: 144dpi) {
+ .icon {
+ background-image: url(images/icons-240x120@2x.png);
+ }
+}
+
+@mixin icon-kb($variant: 0) {
+ background-position: 0 ($variant * -$icon-size);
+}
+
+@mixin icon-share($variant: 0) {
+ background-position: (-$icon-size) ($variant * -$icon-size);
+}
+
+@mixin icon-save($variant: 0) {
+ background-position: (2 * -$icon-size) ($variant * -$icon-size);
+}
+
+@mixin icon-url($variant: 0) {
+ background-position: (3 * -$icon-size) ($variant * -$icon-size);
+}
+
+@mixin icon-presets($variant: 0) {
+ background-position: (4 * -$icon-size) ($variant * -$icon-size);
+}
+
+@mixin icon-edit($variant: 0) {
+ background-position: (5 * -$icon-size) ($variant * -$icon-size);
+}
+
+@mixin icon-size($variant: 0) {
+ background-position: (6 * -$icon-size) ($variant * -$icon-size);
+}
+
+@mixin icon-pencil($variant: 0) {
+ background-position: (7 * -$icon-size) ($variant * -$icon-size);
+}
+
+@mixin icon-tick($variant: 0) {
+ background-position: (8 * -$icon-size) ($variant * -$icon-size);
+}
+
+@mixin icon-delete($variant: 0) {
+ background-position: (9 * -$icon-size) ($variant * -$icon-size);
+}
+
+@mixin icon-down-arrow($variant: 0) {
+ background-position: (10 * -$icon-size) ($variant * -$icon-size);
+}
+
+@mixin icon-up-arrow($variant: 0) {
+ background-position: (11 * -$icon-size) ($variant * -$icon-size);
+}
+
+.icon-kb {
+ @include icon-kb(0);
+}
+
+.icon-size {
+ @include icon-size(0);
+}
+
+.icon-save-white {
+ @include icon-save(2);
+}
+
+/* Viewport */
+
+#viewport-container {
+ text-align: center;
+ width: 100%;
+ overflow: hidden;
+ position: absolute;
+ bottom: 0;
+ background: #ccc;
+
+ @include single-transition(top, 0.5s, ease-out);
+ top: $menu-height;
+ &.fullscreen {
+ top: 0;
+ }
+}
+
+#viewport {
+ @include single-transition(all, 0.5s, ease-out);
+ margin: 0 auto;
+ width: 100%;
+ height: 99%;
+ border: none;
+ background: #fff; /* Some sites do not set a background colour! */
+}
+
+.toggle-btn {
+ display: block;
+ position: absolute;
+ top: 0;
+ font-size: 1.2rem;
+ height: $menu-height;
+ color: #fff;
+ padding: 0 1rem;
+ cursor: pointer;
+ text-transform: uppercase;
+ &.presets-btn.active {
+ background: $grey-shadow;
+ }
+ &:hover {
+ background:#4C4C4C;
+ }
+}
+
+.toggle-btn,
+.menu-btn {
+ .icon {
+ margin-right: 0.2rem;
+ }
+}
+
+.menu-item {
+ display: block;
+ position: absolute;
+ font-size: 1.2rem;
+ line-height: $menu-item-height;
+ height: $menu-item-height;
+ top: $menu-pad;
+}
+
+.menu-btn {
+ display: block;
+ text-align: center;
+ text-transform: uppercase;
+ text-shadow: 0 -0.1rem rgba(0, 0, 0, 0.2);
+ font-size: 1.2rem;
+ font-weight:bold;
+ color: #fff;
+ cursor: pointer;
+ padding: 0 1rem;
+ @include box-shadow(#000 0 0.1rem 0);
+ @include border-radius(0.2rem);
+ @include background-image(linear-gradient($mint-highlight, $mint-shadow));
+ &:hover,
+ &:focus {
+ @include box-shadow(#000 0 0.1rem 0, inset $mint-shadow 0 0 1rem);
+ }
+}
+
+.cell-btn {
+ height: 2.5rem;
+ line-height: 2.5rem;
+}
+
+.text-input {
+ @include input-placeholder(#999);
+ font-size: 1.3rem;
+ font-weight: bold;
+ background: #fff;
+ color: $grey-shadow;
+ padding: 0 0.5rem;
+ width: 6rem;
+ border-radius:0.2rem;
+ &:focus {
+ @include box-shadow(inset $grey-highlight 0 0 0.1rem);
+ }
+}
+
+.menu {
+ position: relative;
+ background: $grey;
+ height: $menu-height;
+ line-height: $menu-height;
+}
+
+.main-menu {
+ width: 100%;
+
+ @include single-transition(top, 0.5s, ease-out);
+ top: 0;
+ &.hidden {
+ top: -$menu-height;
+ }
+
+ .presets-btn {
+ width: 11rem;
+ left: 0;
+ .icon {
+ @include icon-presets(0);
+ }
+ &.active .icon {
+ @include icon-presets(2);
+ }
+ }
+ .share-btn {
+ width: 10rem;
+ left: 11rem;
+ .icon {
+ @include icon-share(0);
+ }
+ }
+ .help-btn {
+ color: #928F8F;
+ right: 11rem;
+ text-align: center;
+ width: 10rem;
+ }
+ .mode-btn {
+ width: 11rem;
+ right: 0;
+ &.mode-size {
+ .icon {
+ @include icon-url(0); /* Note: indicates switch *to* URL */
+ }
+ }
+ & .icon {
+ margin-left:1.2rem;
+ }
+ &.mode-url {
+ .icon {
+ @include icon-size(0);
+ }
+ }
+ }
+ .mode-menu {
+ position: absolute;
+ left: 21rem;
+ right: 21rem;
+ height: $menu-height;
+
+ .size-menu {
+ position: absolute;
+ top: 0;
+ width: 100%;
+ height: 100%;
+
+
+ .size-form {
+ position: relative;
+ width: 34rem;
+ height: $menu-height;
+ margin: 0 auto;
+
+ .size-lbl {
+ position: absolute;
+ left: $menu-pad;
+ top: $menu-pad;
+ width: 2rem;
+ font-size: 1.1rem;
+ text-align: center;
+ height: $menu-item-height;
+ line-height: $menu-item-height;
+ background: #928f8f;
+ color: #fff;
+ border-radius:0.2rem 0 0 0.2rem;
+ }
+ .size-width-input,
+ .size-height-input {
+ width: 10rem;
+ border-radius:0 0.2rem 0.2rem 0;
+ }
+ .size-width-lbl {
+ left: 0;
+ }
+ .size-width-input {
+ left: 2rem;
+ }
+ .size-height-lbl {
+ left: 13rem;
+ }
+ .size-height-input {
+ left: 15rem;
+ }
+ .resize-btn {
+ left: 26rem;
+ width: 8rem;
+ }
+ }
+ }
+
+ .url-menu {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ @include h-recess-border;
+ @include background-image(linear-gradient($grey-dark-shadow 0, $grey-shadow 15%));
+
+ @include single-transition(top, 0.3s, ease-out);
+ top: -$menu-height;
+ &.active {
+ top: 0;
+ }
+
+ .url-form {
+ position: relative;
+ width: 34rem;
+ height: $menu-height;
+ margin: 0 auto;
+ .url-input {
+ width: 25rem;
+ left: 0;
+ }
+ .url-btn {
+ width: 8rem;
+ right: 0;
+ }
+ }
+ }
+
+ }
+}
+
+.panel {
+ position: fixed;
+ @include single-box-shadow(rgba(0, 0, 0, 0.3), 0, 0, 2rem, 0);
+}
+
+.flash-info {
+ position: fixed;
+ display: none;
+ left: 2rem;
+ bottom: 3rem;
+ color: #fff;
+ background: $mint-shadow;
+ padding: 1rem 1.5rem;
+ border: 0.3rem solid $mint-highlight;
+}
+
+.presets-footer-menu {
+ width: 100%;
+ height: $menu-height;
+ border-bottom: 0.1rem solid $grey-shadow;
+}
+
+.presets-panel {
+ top: $menu-height + 1rem;
+ left: 1rem;
+ width: 40rem;
+ background: $grey;
+ /* Arrow: http://cssarrowplease.com */
+ &:after {
+ bottom: 100%;
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+ pointer-events: none;
+ left: 5rem;
+ margin-left: -1rem;
+ border-color: rgba(68, 68, 68, 0); border-bottom-color: #444444;
+ border-width: 1rem;
+ }
+ &.edit-enabled {
+ .col-name {
+ .label {
+ display: none;
+ }
+ }
+ .col-kb {
+ display: none;
+ }
+ }
+ &.edit-disabled {
+ .col-name {
+ input {
+ display: none;
+ }
+ }
+ .col-move,
+ .col-delete {
+ display: none;
+ }
+ .preset-row {
+ &.selected td {
+ @include background-image(linear-gradient($mint-shadow 0, $mint-highlight 5%));
+ @include v-cell-selected-border;
+ }
+ &.selected td,
+ &.selected td .name {
+ color: white;
+ }
+ }
+ }
+ .presets-table {
+ counter-reset: row;
+ .col-name {
+ text-align: left;
+ }
+ .preset-row {
+ counter-increment: row;
+ &:first-child .move-up-btn {
+ visibility: hidden;
+ }
+ &:last-child .move-down-btn {
+ visibility: hidden;
+ }
+ }
+ td {
+ white-space: nowrap;
+ &.col-name {
+ width: 18rem;
+ max-width: 18rem;
+ }
+ .name {
+ position: relative;
+ color: $grey-shadow;
+ font-weight: bold;
+ height: $menu-height;
+ line-height: $menu-height;
+ .label {
+ overflow: hidden;
+ }
+ input {
+ width: 100%;
+ border: 0.1rem solid #ccc;
+ }
+ }
+ &.col-kb:after {
+ content: counter(row);
+ }
+ .move-up-btn {
+ .icon {
+ @include icon-up-arrow(1);
+ }
+ &:hover .icon{
+ @include icon-up-arrow(3);
+ }
+ }
+ .move-down-btn {
+ .icon {
+ @include icon-down-arrow(1);
+ }
+ &:hover .icon{
+ @include icon-down-arrow(3);
+ }
+ }
+ .delete-btn {
+ .icon {
+ @include icon-delete(1);
+ }
+ &:hover .icon{
+ @include icon-delete(3);
+ }
+ }
+ }
+ .col-size {
+ width: 13rem;
+ }
+ .col-kb,
+ .col-delete {
+ width: 7rem;
+ }
+ }
+ .presets-footer-menu {
+ position: relative;
+ .save-container {
+ position: absolute;
+ left: 9rem;
+ top: 0;
+ width: 31rem;
+ height: $menu-height;
+ .save-btn {
+ text-align: left;
+ width: 14rem;
+ right: $menu-pad;
+ }
+ }
+ .edit-btn {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 9rem;
+ .icon { @include icon-edit(0); }
+ &.active .icon { @include icon-tick(0); }
+ }
+ }
+}
+
+.table {
+ color: $table-text;
+ width: 100%;
+ border-collapse: separate;
+ tr:hover td,
+ tr:focus td {
+ background: $table-cell-selected-background;
+ @include v-cell-focus-border;
+ }
+ th, td {
+ text-align: center;
+ height: $menu-height; /*4rem;*/
+ line-height: 2.5rem;
+ padding: 0 1rem;
+ background: $grey;
+ }
+ td {
+ font-size: 1.4rem;
+ background: $table-cell-background;
+ cursor: pointer;
+ @include v-cell-border;
+ }
+ th {
+ color: #fff;
+ text-transform: uppercase;
+ font-size: 1.2rem;
+ font-weight: bold;
+ border-bottom: 0.1rem solid $grey-shadow;
+ }
+}
+
+
+/* Media Queries */
+@media screen and (min-width: 0em) and (max-width: 50em){
+ .presets-panel:after {
+ left:2rem;
+ }
+ .main-menu {
+ .mode-menu {
+ right:12rem;
+ left:12rem;
+ .size-menu {
+ .size-form {
+ width:27rem;
+ .size-width-input,
+ .size-height-input {
+ width:7rem;
+ }
+ .size-width-lbl {
+
+ }
+ .size-width-input {
+ }
+ .size-height-lbl {
+ left:10rem;
+ }
+ .size-height-input {
+ left:12rem;
+ }
+ .resize-btn {
+ width:7rem;
+ left:20rem;
+ }
+
+ }
+ }
+ .url-menu {
+ .url-form {
+ width:27rem;
+ .url-input{
+ width:19rem;
+ }
+ .url-btn {
+ width:7rem;
+ left:20rem;
+ }
+
+ }
+ }
+ }
+ .mode-btn, .presets-btn, .share-btn, .help-btn {
+ width:6rem;
+ }
+ .mode-btn .label, .presets-btn .label, .share-btn .label, .help-btn .label {
+ display: none;
+ }
+ .help-btn:before {
+ content:'?';
+ }
+ .share-btn {
+ left:6rem;
+ .icon {
+ @include icon-share(1);
+ }
+ }
+ .help-btn {
+ right:6rem;
+ }
+ .mode-btn .icon, .presets-btn .icon, .share-btn .icon {
+ margin-left:0.8rem;
+ }
+ }
+}
+
+
+@media screen and (min-width: 70em){
+ .main-menu {
+ .mode-menu {
+ .size-menu {
+ .size-form {
+ width:68rem;
+ .size-lbl {
+ left: $menu-pad;
+ top: $menu-pad;
+ width: 3rem;
+ }
+ .size-width-input,
+ .size-height-input {
+ width: 16rem;
+ }
+ .size-width-lbl {
+ left: 10.5rem;
+ }
+ .size-width-input {
+ left: 13.5rem;
+ }
+ .size-height-lbl {
+ left: 30.5rem;
+ }
+ .size-height-input {
+ left: 33.5rem;
+ }
+ .resize-btn {
+ left: 50.5rem;
+ width: 8rem;
+ }
+
+ }
+ }
+ .url-menu {
+ .url-form {
+ width:68rem;
+ .url-input{
+ width:50rem;
+ left:4.5rem;
+ }
+ .url-btn {
+ width:8rem;
+ left:55.5rem;
+ }
+
+ }
+ }
+ }
+ }
+}
+
+
+
+
View
BIN  stylesheets/images/icons-240x120.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  stylesheets/images/icons-240x120@2x.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  stylesheets/images/preset_box.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  stylesheets/images/preset_box.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  stylesheets/images/saving.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  stylesheets/images/url_size_toggle.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  stylesheets/images/url_size_toggle.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
282 stylesheets/main.css
@@ -0,0 +1,282 @@
+/* line 3, ../sass/main.scss */
+* {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+/* Colours */
+/* Base styling */
+/* line 19, ../sass/main.scss */
+html {
+ margin: 0;
+ padding: 0;
+ font-size: 62.5%;
+ /* -webkit-font-smoothing: antialiased; */
+}
+
+/* line 26, ../sass/main.scss */
+body {
+ margin: 0;
+ padding: 0;
+ font-family: "Arial", sans-serif;
+ background: #f5f5f5;
+ font-size: 1.6rem;
+ line-height: 1.25;
+ font-weight: normal;
+ color: #444545;
+}
+
+/* line 38, ../sass/main.scss */
+button,
+input {
+ border: 0 none;
+ margin: 0;
+ background-color: transparent;
+}
+
+/* line 44, ../sass/main.scss */
+img {
+ max-width: 100%;
+}
+
+/* line 48, ../sass/main.scss */
+a, a:visited {
+ color: #1e9c6c;
+ border-bottom: 1px solid #f0eeee;
+}
+
+/* line 52, ../sass/main.scss */
+a {
+ text-decoration: none;
+}
+
+/* line 56, ../sass/main.scss */
+a:focus {
+ outline: none;
+}
+
+/* line 61, ../sass/main.scss */
+.visually-hidden {
+ border: 0;
+ clip: rect(0 0 0 0);
+ height: 1px;
+ margin: -1px;
+ overflow: hidden;
+ padding: 0;
+ position: absolute;
+ width: 1px;
+}
+
+/* Clearfix */
+/* line 75, ../sass/main.scss */
+.group:before,
+.group:after {
+ content: " ";
+ display: table;
+}
+
+/* line 79, ../sass/main.scss */
+.group:after {
+ clear: both;
+}
+
+/* line 82, ../sass/main.scss */
+.group {
+ *zoom: 1;
+}
+
+/* Typographic Scale */
+/* line 88, ../sass/main.scss */
+h1, .trafalgar {
+ font-size: 4.8rem;
+ color: #1e9c6c;
+ line-height: 1.5;
+ margin: 0;
+ letter-spacing: -0.048rem;
+}
+
+/* line 95, ../sass/main.scss */
+h2, .double-pica {
+ font-size: 2.4rem;
+ color: #1e9c6c;
+ margin: 0 0 1.6rem;
+}
+
+/* line 100, ../sass/main.scss */
+h3, .great-primer {
+ font-size: 2.0rem;
+ margin: 0 0 0.4rem;
+}
+
+/* line 104, ../sass/main.scss */
+h4, .pica {
+ font-size: 1.6rem;
+ color: #414042;
+}
+
+/* line 108, ../sass/main.scss */
+h5, .long-primer {
+ font-size: 1.3rem;
+}
+
+/* line 111, ../sass/main.scss */
+h6, .brevier {
+ font-size: 1.0rem;
+}
+
+/* line 115, ../sass/main.scss */
+h1, .trafalgar, h2, .double-pica, h3, .great-primer {
+ font-weight: bold;
+}
+
+/* line 119, ../sass/main.scss */
+p {
+ margin: 0 0 1.6rem;
+}
+
+/* line 122, ../sass/main.scss */
+.img-caption {
+ font-style: italic;
+ text-align: center;
+ margin: 1.6rem auto 0.8rem;
+ max-width: 40rem;
+}
+
+/* line 130, ../sass/main.scss */
+.container {
+ margin: 0 auto;
+ max-width: 53.000em;
+ padding: 0 0.8rem;
+}
+
+/* line 135, ../sass/main.scss */
+.region {
+ position: relative;
+ vertical-align: top;
+ width: 100%;
+ float: left;
+}
+
+/* line 141, ../sass/main.scss */
+section {
+ padding: 3.2rem 0;
+}
+
+/* line 144, ../sass/main.scss */
+header {
+ padding: 3.2rem 0.8rem;
+}
+
+/* line 148, ../sass/main.scss */
+.size-section, .saving-section {
+ background: #f0eeee;
+}
+
+/* line 151, ../sass/main.scss */
+.size-description, .presets-description, .saving-description {
+ width: 90%;
+ float: none;
+ margin: 0 auto;
+ max-width: 38rem;
+}
+
+/* line 157, ../sass/main.scss */
+.size-figure, .presets-figure, .saving-figure {
+ margin: 0 auto;
+ text-align: center;
+}
+
+/* line 161, ../sass/main.scss */
+figure {
+ padding: 0.4rem 0 0;
+}
+
+/* line 164, ../sass/main.scss */
+.header {
+ text-align: center;
+}
+
+/* line 167, ../sass/main.scss */
+.header p {
+ max-width: 38rem;
+ margin: 0 auto;
+}
+
+@media screen and (min-width: 28.5em) {
+ /* line 173, ../sass/main.scss */
+ section {
+ padding: 3.2rem 1.6rem;
+ }
+
+ /* line 176, ../sass/main.scss */
+ header {
+ padding: 4.8rem 1.6rem 6.8rem;
+ }
+
+ /* line 179, ../sass/main.scss */
+ .container {
+ width: 83.333%;
+ }
+}
+@media screen and (min-width: 37.5em) {
+ /* line 185, ../sass/main.scss */
+ h1, .trafalgar {
+ font-size: 6.4rem;
+ }
+}
+@media screen and (min-width: 850px) {
+ /* line 191, ../sass/main.scss */
+ section {
+ padding: 6.8rem 1.6rem;
+ }
+