diff --git a/.gitignore b/.gitignore index de0622a..cd57f46 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ bower_components *.sw[pon] node_modules +marketplace-elements.css diff --git a/Makefile b/Makefile index 4a8fb91..f0f5de4 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -default: js css +default: css install: @npm install @@ -6,11 +6,8 @@ install: @cp bower_components/marketplace-constants/dist/css/regions.styl bower_components/marketplace-frontend/src/media/css/lib @node_modules/.bin/stylus bower_components/marketplace-frontend/src/media/css/*.styl -js: - cp -f marketplace-elements.js dist/js/marketplace-elements.js - css: - stylus marketplace-elements.styl -o dist/css + stylus --include bower_components/marketplace-frontend/src/media/css --include bower_components/marketplace-constants/dist/css marketplace-elements.styl serve: python -m SimpleHTTPServer diff --git a/dist/css/marketplace-elements.css b/dist/css/marketplace-elements.css deleted file mode 100644 index 195dea3..0000000 --- a/dist/css/marketplace-elements.css +++ /dev/null @@ -1,369 +0,0 @@ -.mkt-cloak { - display: none; -} -.mkt-banner { - background: #797979; - color: #fff; - display: block; - line-height: 1.3; - overflow: hidden; - position: relative; -} -.mkt-banner-content { - margin: 2px auto; - max-width: 1070px; - position: relative; - text-align: center; -} -.mkt-banner-content .mkt-banner-close { - color: #fff; - cursor: pointer; - font-size: 40px; - font-weight: 100; - line-height: 0; - margin: 0; - padding: 0 10px 0 0; - position: absolute; - right: 0; - top: 50%; -} -.mkt-banner-content .mkt-banner-close:hover { - color: rgba(255,255,255,0.8); -} -.mkt-banner-content .mkt-banner-close:active { - color: rgba(255,255,255,0.6); -} -.mkt-banner-content > span { - display: inline-block; -} -.mkt-banner-content > span, -.mkt-banner-content > div { - margin-top: 10px; - padding: 0; -} -.mkt-banner-content a { - color: #fff; - font-weight: 100; - text-decoration: underline; -} -.mkt-banner-content > a { - border-radius: 5px; - color: #fff; - display: inline-block; - font-weight: 500; - margin: 10px; - padding: 10px; - text-decoration: none; -} -.mkt-banner-content > a.spin { - color: transparent; - position: relative; -} -.mkt-banner-content > a.spin:after { - -webkit-animation: 0.9s spin infinite steps(30); - animation: 0.9s spin infinite steps(30); - height: 30px; - margin: 0 auto; - background: url("../img/btn_spinner.png") no-repeat center; - width: 30px; - height: 18px; - margin: 2px 0; - background: url("../img/btn_spinner_18.png") no-repeat center; - width: 18px; - content: ""; - display: block; - left: calc(50% - 9px); - position: absolute; - top: calc(50% - 11px); -} -.mkt-banner[theme="firefox"] .mkt-banner-content { - background: url("../../img/logos/firefox-64.png") no-repeat; - background-position: 0 50%; - background-size: 64px 60px; - min-height: 60px; - padding: 0 40px 0 70px; -} -.mkt-banner[theme="firefox"] .mkt-banner-content > a { - background-color: #535353; -} -.mkt-banner[theme="firefox"] .mkt-banner-content > a:hover { - background-color: #4b4b4b; -} -.mkt-banner-content { - font-size: 15px; - font-weight: 500; - padding: 0 40px; -} -.mkt-banner-content small { - font-size: 15px; - font-weight: 500; -} -.mkt-banner[theme=success] { - background: #64be3c; -} -.mkt-banner[theme=success] .mkt-banner-content > a { - background-color: #4d8d32; -} -.mkt-banner[theme=success] .mkt-banner-content > a:hover { - background-color: #457f2d; -} -.mkt-banner[theme=success-light] { - background: #66d071; -} -.mkt-banner[theme=success-light] .mkt-banner-content > a { - background-color: #4d8d32; -} -.mkt-banner[theme=success-light] .mkt-banner-content > a:hover { - background-color: #457f2d; -} -.mkt-banner[theme=positive] { - background: #4cb1ff; -} -.mkt-banner[theme=positive] .mkt-banner-content > a { - background-color: #3d86bd; -} -.mkt-banner[theme=positive] .mkt-banner-content > a:hover { - background-color: #3779aa; -} -.mkt-banner[theme=positive-light] { - background: #42cafe; -} -.mkt-banner[theme=positive-light] .mkt-banner-content > a { - background-color: #3d86bd; -} -.mkt-banner[theme=positive-light] .mkt-banner-content > a:hover { - background-color: #3779aa; -} -.mkt-banner[theme=wait] { - background: #ffdc32; -} -.mkt-banner[theme=wait] .mkt-banner-content > a { - background-color: #bea434; -} -.mkt-banner[theme=wait] .mkt-banner-content > a:hover { - background-color: #ab942f; -} -.mkt-banner[theme=wait-light] { - background: #ffe26e; -} -.mkt-banner[theme=wait-light] .mkt-banner-content > a { - background-color: #bea434; -} -.mkt-banner[theme=wait-light] .mkt-banner-content > a:hover { - background-color: #ab942f; -} -.mkt-banner[theme=error] { - background: #f54b3c; -} -.mkt-banner[theme=error] .mkt-banner-content > a { - background-color: #b63932; -} -.mkt-banner[theme=error] .mkt-banner-content > a:hover { - background-color: #a4332d; -} -.mkt-banner[theme=error-light] { - background: #ff6c70; -} -.mkt-banner[theme=error-light] .mkt-banner-content > a { - background-color: #b63932; -} -.mkt-banner[theme=error-light] .mkt-banner-content > a:hover { - background-color: #a4332d; -} -.mkt-segmented-select { - display: none; -} -.mkt-segmented-button { - background: #fff; - border-color: #4cb1ff; - border-style: solid; - border-width: 1px 1px 1px 0; - color: #4cb1ff; - cursor: pointer; - outline: none; - padding: 10px; -} -.mkt-segmented-button:first-of-type { - border-radius: 5px 0 0 5px; - border-width: 1px; -} -.mkt-segmented-button:last-of-type { - border-radius: 0 5px 5px 0; -} -.mkt-segmented-button[selected] { - background: #4cb1ff; - border-color: #4cb1ff; - color: #fff; -} -.mkt-segmented-button:hover { - background: #42cafe; - border-color: #42cafe; - color: #fff; -} -.mkt-segmented-button:active { - background: #3d86bd; - border-color: #3d86bd; - color: #fff; -} -.mkt-tab-control-select { - display: none; -} -.mkt-tab-control-button { - background: transparent; - border-color: transparent; - border-style: solid; - border-width: 0 0 3px 0; - color: #000; - cursor: pointer; - margin: 0 5px; - outline: none; - padding: 5px 0; - text-transform: uppercase; -} -.mkt-tab-control-button[selected] { - border-color: #4cb1ff; - color: #4cb1ff; -} -.mkt-tab-control-button:hover { - border-color: #42cafe; - color: #42cafe; -} -.mkt-tab-control-button:active { - border-color: #3d86bd; - color: #3d86bd; -} -.mkt-tabs .mkt-tab { - display: none; -} -.mkt-tabs .mkt-tab.mkt-tab-active { - display: block; -} -@media (min-width: 1025px) { - .mkt-banner-content { - padding: 0; - } -} -@media (max-width: 709px) { - .mkt-banner small { - display: none; - } -} -/* - .mkt-prompt - form as full width of page. By default, only a full-width submit btn. - .mkt-prompt[data-modal] - modal overlay. By default, half-width cancel/submit btns. -*/ -.mkt-prompt { - position: relative; - width: 100%; -} -.mkt-prompt .mkt-prompt-content { - background: #fff; - padding-bottom: 10px; -} -.mkt-prompt .mkt-prompt-content > form:first-child, -.mkt-prompt .mkt-prompt-content > div:first-child { - padding: 5px 20px; -} -.mkt-prompt form > div:not(.mkt-prompt-btn-wrap) { - margin-bottom: 20px; - width: 100%; -} -.mkt-prompt h3 { - font-weight: 500; - margin-top: 20px; -} -.mkt-prompt p { - font-size: $font-size; - line-height: 22px; - margin: 15px 0; -} -.mkt-prompt textarea { - border: 1px solid #f1f1f1; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - font-family: "Fira Sans OT", "Fira Sans", FiraSansWeb, sans-serif; - margin-bottom: 25px; - min-height: 100px; - padding: 10px; - width: 100%; -} -.mkt-prompt select { - width: 100%; -} -.mkt-prompt-btn-wrap { - display: inline-flex; - width: 100%; -} -.mkt-prompt-btn-wrap button { - border: 0; - color: #fff; - flex-grow: 1; - font-size: 13px; - font-weight: 500; - height: 48px; -} -.mkt-prompt-btn-wrap button:hover { - cursor: pointer; -} -.mkt-prompt-btn-wrap button[type="cancel"] { - display: none; - background: #4cb1ff; -} -.mkt-prompt-btn-wrap button[type="cancel"]:hover { - background: #42cafe; -} -.mkt-prompt-btn-wrap button[type="cancel"]:active { - background: #3d86bd; -} -.mkt-prompt-btn-wrap button[type="submit"] { - background: #64be3c; -} -.mkt-prompt-btn-wrap button[type="submit"]:hover { - background: #66d071; -} -.mkt-prompt-btn-wrap button[type="submit"]:active { - background: #4d8d32; -} -.mkt-prompt form:invalid [type="submit"] { - background: #cbcbcb; -} -.mkt-prompt form:invalid [type="submit"]:hover { - cursor: default; -} -.mkt-prompt[data-modal] { - background: rgba(203,203,203,0.8); - height: 100%; - left: 0; - position: fixed; - top: 0; - width: 100%; - z-index: 1000; -} -.mkt-prompt[data-modal] .mkt-prompt-content { - border-radius: 0; - padding-bottom: 0; - position: absolute; - left: 0; - margin: 5% auto 0; - max-width: 535px; - right: 0; - width: 90%; -} -.mkt-prompt[data-modal] .mkt-prompt-btn-wrap { - margin-bottom: -5px; - position: relative; - right: 20px; - width: calc(100% + 40px); -} -.mkt-prompt[data-modal] [type="cancel"] { - display: inline-block; -} -@media (min-width: 700px) { - .mkt-prompt .mkt-prompt-content { - margin-bottom: 20px; - } - .mkt-prompt[data-modal] .mkt-prompt-content { - width: 66.6666666666667%; - } -} diff --git a/dist/js/marketplace-elements.js b/dist/js/marketplace-elements.js deleted file mode 100644 index 4cf7f58..0000000 --- a/dist/js/marketplace-elements.js +++ /dev/null @@ -1,458 +0,0 @@ -(function () { - var CustomEvent, MktEvent; - (function () { - // IE Custom Event polyfill. - CustomEvent = function(event, params) { - params = params || {}; - var evt = document.createEvent('CustomEvent'); - evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); - return evt; - }; - CustomEvent.prototype = window.Event.prototype; - MktEvent = function(event, detail) { - // Bubbles/cancelable by default; - return CustomEvent(event, { - bubbles: true, - cancelable: true, - detail: detail, - }); - }; - })(); - - function makeStorage(storage) { - return { - getItem: function(key) { - return JSON.parse(storage.getItem(key)); - }, - setItem: function(key, value) { - storage.setItem(key, JSON.stringify(value)); - }, - }; - } - - // Mock gettext if it doesn't exist globally. - var gettext = window.gettext || function (str) { return str; }; - - // Abstract element with attribute -> class mappings. - var MktHTMLElement = function () {}; - MktHTMLElement.prototype = Object.create(HTMLElement.prototype, { - attributeChangedCallback: { - value: function (name, previousValue, value) { - // Handle setting classes based on attributeClasses. - if (this.attributeClasses.hasOwnProperty(name)) { - var className = this.attributeClasses[name]; - if (value === null) { - this.classList.remove(className); - } else { - this.classList.add(className); - } - } - }, - }, - attributeClasses: { - value: {}, - }, - createdCallback: { - value: function () { - var root = this; - forEach(Object.keys(this.attributeClasses), function (attr) { - var className = root.attributeClasses[attr]; - if (root.hasAttribute(attr) && className) { - root.classList.add(className); - } - root.__defineGetter__(attr, function () { - // Treat `foo=""` as `foo=true`. - return root.getAttribute(attr) || - root.hasAttribute(attr); - }); - root.__defineSetter__(attr, function (value) { - if (value === null || value === false) { - root.removeAttribute(attr); - } else { - root.setAttribute(attr, value || true); - } - }); - }); - }, - }, - }); - - document.registerElement('mkt-banner', { - prototype: Object.create(MktHTMLElement.prototype, { - attributeClasses: { - value: { - dismiss: null, - }, - }, - createdCallback: { - value: function () { - MktHTMLElement.prototype.createdCallback.call(this); - this.classList.add('mkt-banner'); - - if (!this.hasAttribute('theme')) { - this.setAttribute('theme', 'success'); - } - - if (this.rememberDismissal && this.dismissed) { - this.dismissBanner(); - } - - // Format the initial HTML. - this.html(this.innerHTML); - }, - }, - html: { - value: function (html) { - var root = this; - - var content = document.createElement('div'); - content.classList.add('mkt-banner-content'); - content.innerHTML = html; - - if (!this.undismissable) { - var closeButton = document.createElement('div'); - closeButton.classList.add('mkt-banner-close'); - closeButton.href = '#'; - closeButton.innerHTML = '×'; - closeButton.title = gettext('Close'); - closeButton.addEventListener('click', function (e) { - e.preventDefault(); - root.dismissBanner(); - }); - content.appendChild(closeButton); - } - - this.innerHTML = ''; - this.appendChild(content); - }, - }, - dismissed: { - get: function () { - return this.storage.getItem(this.storageKey); - }, - }, - dismissBanner: { - value: function () { - if (this.rememberDismissal) { - this.storage.setItem(this.storageKey, true); - } - this.parentNode.removeChild(this); - }, - }, - rememberDismissal: { - get: function () { - return this.dismiss === 'remember' || - this.dismiss === 'session'; - }, - }, - storage: { - get: function () { - if (this.dismiss === 'remember') { - return makeStorage(localStorage); - } else if (this.dismiss === 'session') { - return makeStorage(sessionStorage); - } - }, - }, - storageKey: { - get: function () { - if (this.hasAttribute('name')) { - return 'mkt-banner-hide-' + this.getAttribute('name'); - } else { - return 'hide_' + this.id.replace(/-/g, '_'); - } - }, - }, - undismissable: { - get: function () { - return this.dismiss === 'off'; - }, - }, - }), - }); - - document.registerElement('mkt-login', { - prototype: Object.create(MktHTMLElement.prototype, { - createdCallback: { - value: function () { - if (this.isLink) { - var link = document.createElement('a'); - link.href = '#'; - link.classList.add('persona'); - link.textContent = this.textContent; - this.innerHTML = ''; - this.appendChild(link); - } - }, - }, - isLink: { - get: function () { - return this.hasAttribute('link'); - }, - }, - }), - }); - - document.registerElement('mkt-segmented', { - prototype: Object.create(MktHTMLElement.prototype, { - createdCallback: { - value: function () { - var root = this; - var select = this.querySelector('select'); - this.select = select; - select.classList.add('mkt-segmented-select'); - this.classList.add('mkt-segmented'); - - var buttons = map(select.options, function(option, i) { - var button = document.createElement('button'); - button.index = i; - button.classList.add('mkt-segmented-button'); - button.textContent = option.textContent; - button.addEventListener('click', selectButton); - return button; - }); - - var selected; - // This call will set `selected`. - selectButton.call(buttons[select.selectedIndex]); - - function selectButton() { - if (selected == this) { - return; - } else if (selected) { - selected.removeAttribute('selected'); - } - this.setAttribute('selected', ''); - selected = this; - select.selectedIndex = this.index; - root.dispatchEvent(new Event('change', {bubbles: true})); - } - - buttons.forEach(function(button) { - root.appendChild(button); - }); - }, - }, - value: { - get: function () { - return this.select.value; - }, - } - }), - }); - - document.registerElement('mkt-tab-control', { - prototype: Object.create(MktHTMLElement.prototype, { - createdCallback: { - value: function () { - var root = this; - var select = this.querySelector('select'); - this.select = select; - select.classList.add('mkt-tab-control-select'); - this.classList.add('mkt-tab-control'); - - var buttons = map(select.options, function (option, i) { - var button = document.createElement('button'); - button.index = i; - button.classList.add('mkt-tab-control-button'); - button.textContent = option.textContent; - button.addEventListener('click', selectButton); - return button; - }); - - // Set the currently selected option. - var selected; - // This call will set `selected`. - selectButton.call(buttons[select.selectedIndex]); - - // Hook this up to a if `control` is set. - var controlledTabsId = root.getAttribute('control'); - var controlledTabs; - if (controlledTabsId) { - controlledTabs = document.getElementById(controlledTabsId); - controlledTabs.controller = root.id; - controlledTabs.setAttribute('current', root.value); - root.addEventListener('change', function () { - controlledTabs.setAttribute('current', root.value); - }); - } - - function selectButton() { - if (selected == this) { - return; - } else if (selected) { - selected.removeAttribute('selected'); - } - this.setAttribute('selected', ''); - selected = this; - select.selectedIndex = this.index; - root.dispatchEvent(new Event('change', {bubbles: true})); - } - - buttons.forEach(function(button) { - root.appendChild(button); - }); - }, - }, - value: { - get: function () { - return this.select.value; - }, - } - }), - }); - - document.registerElement('mkt-tabs', { - prototype: Object.create(MktHTMLElement.prototype, { - createdCallback: { - value: function () { - var root = this; - var tabs = filter(root.querySelectorAll('section'), function(section) { - // Only select immediate sections. - return section.parentNode === root; - - }); - - root.tabs = tabs; - var current = root.getAttribute('current'); - - root.classList.add('mkt-tabs'); - forEach(tabs, function(tab) { - tab.classList.add('mkt-tab'); - if (tab.getAttribute('name') == current) { - tab.classList.add('mkt-tab-active'); - } - }); - }, - }, - attributeChangedCallback: { - value: function (name, oldValue, newValue) { - var root = this; - function findTab(name) { - return find(root.tabs, function (tab) { - return tab.getAttribute('name') == name; - }); - } - if (name == 'current') { - if (oldValue) { - findTab(oldValue).classList.remove('mkt-tab-active'); - } - if (newValue) { - findTab(newValue).classList.add('mkt-tab-active'); - root.dispatchEvent(new Event('change')); - } - } - }, - }, - }), - }); - - document.registerElement('mkt-prompt', { - prototype: Object.create(MktHTMLElement.prototype, { - createdCallback: { - value: function() { - var root = this; - this.isModal = this.hasAttribute('data-modal'); - this.classList.add('mkt-prompt'); - - // Wrap in a section. - var section = document.createElement('section'); - section.className = 'mkt-prompt-content'; - forEach(this.children, function(child) { - section.appendChild(child); - }); - this.appendChild(section); - - this.querySelector('form > div:last-child') - .classList.add('mkt-prompt-btn-wrap'); - - // Default behavior is to allow the first button act as - // the cancel button. And the second to be the submit button. - forEach(this.querySelectorAll('.mkt-prompt-btn-wrap button'), function(btn, i) { - if (i === 0 && !btn.hasAttribute('type')) { - btn.type = 'cancel'; - } else if (i === 1 && !btn.hasAttribute('type')) { - btn.type = 'submit'; - } - }); - - if (this.isModal) { - // Dismiss if click outside of the modal. - this.addEventListener('click', function(e) { - if (e.target === root) { - root.dismissModal(); - } - }); - - // Cancel button closes modal. - var cancelButton = this.querySelector('button[type="cancel"]'); - cancelButton.addEventListener('click', function(e) { - e.preventDefault(); - this.dispatchEvent(MktEvent('mkt-prompt-cancel')); - root.dismissModal(); - }); - } - - // Submit button triggers event with data. - var submitButton = this.querySelector('button[type="submit"]'); - var form = this.querySelector('form'); - form.addEventListener('submit', function(e) { - e.preventDefault(); - if (root.validate()) { - var detail = serialize(root.querySelector('form')); - root.dispatchEvent(MktEvent('mkt-prompt-submit', detail)); - root.dismissModal(); - } - }, true); - } - }, - dismissModal: { - // Remove the modal from the page. - value: function() { - if (this.isModal) { - this.parentNode.removeChild(this); - } - } - }, - validate: { - value: function() { - return this.querySelector('form').checkValidity(); - } - }, - }), - }); - - function forEach(arr, fn) { - // For NodeList. - return Array.prototype.forEach.call(arr, fn); - } - - function find(arr, predicate) { - // For NodeList. - for (var i = 0, n = arr.length; i < n; i++) { - if (predicate(arr[i])) { - return arr[i]; - } - } - } - - function map(arr, fn) { - // For NodeList. - return Array.prototype.map.call(arr, fn); - } - - function filter(arr, fn) { - // For NodeList. - return Array.prototype.filter.call(arr, fn); - } - - function serialize(form) { - var data = {}; - forEach(form.elements, function(ele) { - if (!ele.disabled && ele.name) { - data[ele.name] = ele.value; - } - }); - return data; - } -})(); diff --git a/marketplace-elements.styl b/marketplace-elements.styl index f3c729f..ea2e8b4 100644 --- a/marketplace-elements.styl +++ b/marketplace-elements.styl @@ -1,4 +1,4 @@ -@import 'bower_components/marketplace-frontend/src/media/css/lib'; +@import 'lib'; $font-narrow = 100; $font-bold = 500; @@ -86,7 +86,7 @@ $font-bold = 500; .mkt-banner[theme="firefox"] { .mkt-banner-content { - background: url("../../img/logos/firefox-64.png") no-repeat; + background: url("../img/logos/firefox-64.png") no-repeat; background-position: 0 50%; background-size: 64px 60px; min-height: 60px;