commit f9c5f3db5a8cbb3d25e1a84c19b7c56d73b71422 Author: Lukas Bestle Date: Mon Aug 15 18:01:14 2016 +0200 Initial public commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/codesignd/1-globals/colors/colors.html.php b/codesignd/1-globals/colors/colors.html.php new file mode 100644 index 0000000..4703dc8 --- /dev/null +++ b/codesignd/1-globals/colors/colors.html.php @@ -0,0 +1,54 @@ +
+

Color previews

+ + + + +
diff --git a/codesignd/1-globals/colors/colors.scss b/codesignd/1-globals/colors/colors.scss new file mode 100644 index 0000000..e1caecf --- /dev/null +++ b/codesignd/1-globals/colors/colors.scss @@ -0,0 +1,4 @@ +$color--brand-primary: #ed8f1b !default; +$color--brand-primary-alternate: lighten($color--brand-primary, 15%) !default; +$color--brand-secondary: #0bb888 !default; +$color--brand-secondary-alternate: lighten($color--brand-secondary, 5%) !default; diff --git a/codesignd/1-globals/favicons/favicon-152.png b/codesignd/1-globals/favicons/favicon-152.png new file mode 100644 index 0000000..062ae70 Binary files /dev/null and b/codesignd/1-globals/favicons/favicon-152.png differ diff --git a/codesignd/1-globals/favicons/favicon-96.png b/codesignd/1-globals/favicons/favicon-96.png new file mode 100644 index 0000000..4ce118c Binary files /dev/null and b/codesignd/1-globals/favicons/favicon-96.png differ diff --git a/codesignd/1-globals/favicons/favicon.ico b/codesignd/1-globals/favicons/favicon.ico new file mode 100644 index 0000000..7e41b5e Binary files /dev/null and b/codesignd/1-globals/favicons/favicon.ico differ diff --git a/codesignd/2-blocks/contact/contact.html.php b/codesignd/2-blocks/contact/contact.html.php new file mode 100644 index 0000000..587f13b --- /dev/null +++ b/codesignd/2-blocks/contact/contact.html.php @@ -0,0 +1,41 @@ +
+
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non + proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ + +
+ +
+ Thank you for your message. +
+
+ + +
+ + diff --git a/codesignd/2-blocks/contact/contact.scss b/codesignd/2-blocks/contact/contact.scss new file mode 100644 index 0000000..19f2705 --- /dev/null +++ b/codesignd/2-blocks/contact/contact.scss @@ -0,0 +1,100 @@ +.contact { + position: relative; + + display: flex; + justify-content: space-between; + + @media (max-width: 50em) { + flex-direction: column; + } +} + +.contact__main { + flex: 1; +} + +.contact__form { + position: relative; +} + +.contact__stamp { + position: absolute; + bottom: -1.5rem; + right: 1rem; + width: 6rem; + + visibility: hidden; + opacity: 0; + filter: blur(2px); + transform: scale(1.3); + transition: visibility 0s linear 0.3s, opacity 0.3s ease, filter 0.3s ease, transform 0.3s ease; + + .form--sent & { + visibility: visible; + opacity: 1; + filter: none; + transform: none; + transition-delay: 0s; + } +} + +.contact__thank-you { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: -1; +} + +.contact__sidebar { + max-width: 16rem; + margin-left: 2rem; + + @media (max-width: 50em) { + max-width: 100%; + margin: 0; + margin-top: 2rem; + + display: flex; + flex-wrap: wrap; + } +} + +.contact__detail { + @media (min-width: 50em), (max-width: 42em) { + &:not(:last-child) { + margin-bottom: 1.8rem; + } + } + + @media (max-width: 50em) { + width: 50%; + } + + @media (max-width: 42em) { + width: 100%; + } +} + +.contact__heading { + font-size: -cdd-rem(20); + margin-bottom: 0.3em; +} + +.contact__email { + display: flex; + margin-bottom: 0.3rem; + + > :nth-child(1) { + margin-right: 0.5rem; + padding-right: 0.5rem; + border-right: 1px solid $color--passive; + } + + > :nth-child(2) { + align-self: center; + + font-size: -cdd-rem(22); + } +} diff --git a/codesignd/2-blocks/contact/stamp.svg b/codesignd/2-blocks/contact/stamp.svg new file mode 100644 index 0000000..4816b4e --- /dev/null +++ b/codesignd/2-blocks/contact/stamp.svg @@ -0,0 +1 @@ + diff --git a/codesignd/2-blocks/home-banner/home-banner.config.php b/codesignd/2-blocks/home-banner/home-banner.config.php new file mode 100644 index 0000000..8f8f493 --- /dev/null +++ b/codesignd/2-blocks/home-banner/home-banner.config.php @@ -0,0 +1,14 @@ + [ + 'illustration' => false, + 'text' => '

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptas repellendus modi ea praesentium totam, earum, accusamus pariatur cumque.

' + ], + 'preview' => function() { + // Use the home illustration if we have one + $illustration = page('home')->image('illustration.svg')->url(); + + return compact('illustration'); + } +]; diff --git a/codesignd/2-blocks/home-banner/home-banner.html.php b/codesignd/2-blocks/home-banner/home-banner.html.php new file mode 100644 index 0000000..92b441a --- /dev/null +++ b/codesignd/2-blocks/home-banner/home-banner.html.php @@ -0,0 +1,21 @@ +
+ + + + +
+
+ + l::get('home-banner.learnmore', 'Learn more'), + 'label' => l::get('home-banner.learnmore.label', 'Learn more about my services'), + 'link' => url('services'), + 'modifiers' => 'novisited' + ]) ?> + l::get('home-banner.contact', 'Contact'), + 'link' => url('contact'), + 'modifiers' => ['novisited', 'secondary'] + ]) ?> +
+
diff --git a/codesignd/2-blocks/home-banner/home-banner.scss b/codesignd/2-blocks/home-banner/home-banner.scss new file mode 100644 index 0000000..95ab12b --- /dev/null +++ b/codesignd/2-blocks/home-banner/home-banner.scss @@ -0,0 +1,36 @@ +.home-banner { + display: flex; + align-items: flex-start; + + @media (max-width: 44em) { + flex-direction: column; + align-items: center; + } +} + +.home-banner__illustration { + width: 25em; + max-width: 100%; + margin-right: 4em; + + @media (max-width: 60em) { + width: 45%; + margin-right: 2em; + } + + @media (max-width: 44em) { + width: 20em; + margin-right: 0; + margin-bottom: 1em; + } +} + +.home-banner__description { + flex: 1; +} + +.home-banner__text { + font-size: -cdd-rem(24); + line-height: 1.55; + margin-bottom: 0.5em; +} diff --git a/codesignd/2-blocks/logo/logo.html.php b/codesignd/2-blocks/logo/logo.html.php new file mode 100644 index 0000000..8913ed0 --- /dev/null +++ b/codesignd/2-blocks/logo/logo.html.php @@ -0,0 +1,3 @@ + diff --git a/codesignd/2-blocks/logo/logo.scss b/codesignd/2-blocks/logo/logo.scss new file mode 100644 index 0000000..8b300d9 --- /dev/null +++ b/codesignd/2-blocks/logo/logo.scss @@ -0,0 +1,50 @@ +.logo__gear { + transition: transform 2s ease-in-out 2.3s; + + .logo:hover &, .logo:focus & { + transition-delay: 0.7s; + } +} +.logo__gear--left { + transform-origin: 261px 261px; + + .logo:hover &, .logo:focus & { + transform: rotate(-90deg); + } +} +.logo__gear--right { + transform-origin: 1100px 340px; + + .logo:hover &, .logo:focus & { + transform: rotate(90deg); + } +} + +.logo__esignd, .logo__gears { + opacity: 1; + transition: opacity 1s ease-in-out 1.4s; + + .logo:hover &, .logo:focus & { + opacity: 0; + transition-delay: 2.7s; + } +} + +.logo__leftd { + transition: transform 1s ease-in-out 0.7s; + + .logo:hover &, .logo:focus & { + transform: translateX(-470px); + transition-delay: 3.4s; + } +} + +.logo__tilde { + opacity: 0; + transition: opacity 1s ease-in-out; + + .logo:hover &, .logo:focus & { + opacity: 1; + transition-delay: 4.3s; + } +} diff --git a/codesignd/2-blocks/logo/logo.svg b/codesignd/2-blocks/logo/logo.svg new file mode 100644 index 0000000..803efce --- /dev/null +++ b/codesignd/2-blocks/logo/logo.svg @@ -0,0 +1 @@ +Homepage diff --git a/codesignd/2-blocks/service/service.config.php b/codesignd/2-blocks/service/service.config.php new file mode 100644 index 0000000..10f7463 --- /dev/null +++ b/codesignd/2-blocks/service/service.config.php @@ -0,0 +1,17 @@ + [ + 'illustration' => false, + 'title' => 'Lorem ipsum dolor', + 'coloredTitle' => true, + 'text' => '

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptas repellendus modi ea praesentium totam, earum, accusamus pariatur cumque.

' + ], + 'preview' => function() { + // Use a random service illustration if we have one + $page = page('services'); + $illustration = ($page)? $page->images()->shuffle()->first()->url() : false; + + return compact('illustration'); + } +]; diff --git a/codesignd/2-blocks/service/service.html.php b/codesignd/2-blocks/service/service.html.php new file mode 100644 index 0000000..f0a8b70 --- /dev/null +++ b/codesignd/2-blocks/service/service.html.php @@ -0,0 +1,10 @@ +
+ + + + +
+

+ +
+
diff --git a/codesignd/2-blocks/service/service.scss b/codesignd/2-blocks/service/service.scss new file mode 100644 index 0000000..35898cb --- /dev/null +++ b/codesignd/2-blocks/service/service.scss @@ -0,0 +1,24 @@ +.service { + // Make the illustrations overlap + &:not(:first-of-type) { + margin-top: -0.5em; + + @media (max-width: 50em) { + margin-top: -0.25em; + } + } +} + +.service__description { + .service:not(:last-of-type) & { + margin-bottom: 2em; + } + + :last-child { + margin-bottom: 0; + } +} + +.service__title--colored::first-letter { + color: $color--brand-secondary; +} diff --git a/codesignd/3-sugar/ajax/ajax.js b/codesignd/3-sugar/ajax/ajax.js new file mode 100644 index 0000000..03a9c8f --- /dev/null +++ b/codesignd/3-sugar/ajax/ajax.js @@ -0,0 +1,7 @@ +(function(app) { + 'use strict'; + + app.on('ajax.after', function(target, data) { + document.querySelector('.nav').innerHTML = data.nav; + }); +})(window.app = window.app || {}); diff --git a/codesignd/3-sugar/contact/contact.js b/codesignd/3-sugar/contact/contact.js new file mode 100644 index 0000000..dbac526 --- /dev/null +++ b/codesignd/3-sugar/contact/contact.js @@ -0,0 +1,70 @@ +//=require element-closest/closest.js +//=require whatwg-fetch/fetch.js + +(function(app) { + 'use strict'; + + // Listen on submit events on body (events from forms will bubble up) + document.body.addEventListener('submit', function(e) { + // Find closest form parent + var form = e.target.closest('.contact__form'); + + // Only continue if the form was found and if we have Promise support + if(!form || !Promise) return; + e.preventDefault(); + + // Disable the submit button and display the animated stamp + console.info('Sending form data'); + form._submit.disabled = true; + form.classList.add('form--sent'); + + // Get form data + // Explicitly add value of submit button (browser bug in Chrome/FF?) + var data = new FormData(form); + data.append('_submit', form._submit.value); + + // Send the form data via AJAX + var options = { + method: 'POST', + body: data, + credentials: 'same-origin', + headers: {'Accept': 'application/json'} + }; + var dataPromise = fetch(form.action, options) + .then(app.validateHttpStatus) + .then(app.parseJsonResponse); + + // Wait for the stamp animation + Promise.all([dataPromise, app.timerPromise(750)]) + .then(function(values) { + // Get the result of the data promise + var data = values[0]; + + // Mark the (in)valid fields + for(var field in data.fields) { + // Add the class if value is true, otherwise remove it + form[field].classList.toggle('input--invalid', data.fields[field]); + } + + // Check if the form submission was successful + if(data.success) { + form.querySelector('.form__message').innerText = ''; + document.querySelector('.contact__thank-you').innerText = data.message; + form.classList.add('form--success'); + } else { + // Throw message to catch it below, because apparently our code is a dog + throw data.message; + } + }) + .catch(function(err) { + console.error(err); + + // Display the error to the user + form.classList.remove('form--sent'); + form.querySelector('.form__message').innerText = err; + + // Enable the submit button again + form._submit.disabled = false; + }); + }); +})(window.app = window.app || {}); diff --git a/codesignd/codesignd.scss b/codesignd/codesignd.scss new file mode 100644 index 0000000..ef44265 --- /dev/null +++ b/codesignd/codesignd.scss @@ -0,0 +1,11 @@ +// Import site-specific color variables +@import "1-globals/colors/colors"; + +// Import shared styles +@import "../shared/shared"; + +// Import blocks in alphabetical order (they are strictly independent) +@import "2-blocks/contact/contact"; +@import "2-blocks/home-banner/home-banner"; +@import "2-blocks/logo/logo"; +@import "2-blocks/service/service"; diff --git a/etc/1-globals/typo-code/input-mono-narrow-light.eot b/etc/1-globals/typo-code/input-mono-narrow-light.eot new file mode 100644 index 0000000..a1ffe0f Binary files /dev/null and b/etc/1-globals/typo-code/input-mono-narrow-light.eot differ diff --git a/etc/1-globals/typo-code/input-mono-narrow-light.woff b/etc/1-globals/typo-code/input-mono-narrow-light.woff new file mode 100644 index 0000000..bc6b73b Binary files /dev/null and b/etc/1-globals/typo-code/input-mono-narrow-light.woff differ diff --git a/etc/1-globals/typo-code/input-mono-narrow-light.woff2 b/etc/1-globals/typo-code/input-mono-narrow-light.woff2 new file mode 100644 index 0000000..10dfbc4 Binary files /dev/null and b/etc/1-globals/typo-code/input-mono-narrow-light.woff2 differ diff --git a/etc/1-globals/typo-code/typo-code.html.php b/etc/1-globals/typo-code/typo-code.html.php new file mode 100644 index 0000000..3be62e8 --- /dev/null +++ b/etc/1-globals/typo-code/typo-code.html.php @@ -0,0 +1,21 @@ +
+

Code highlighting

+ +

Lorem ipsum dolor sit amet, $page->text()->kt() elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non + proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ +
roots()->index() . DS . 'gulpfile.js') ?>
+ +

Lorem ipsum dolor sit amet, $page->text()->kt() elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco ⌘ Cmd + ⇧ Shift + 3 + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non + proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ +
roots()->index() . DS . 'readme.md') ?>
+
diff --git a/etc/1-globals/typo-code/typo-code.js b/etc/1-globals/typo-code/typo-code.js new file mode 100644 index 0000000..0d0f598 --- /dev/null +++ b/etc/1-globals/typo-code/typo-code.js @@ -0,0 +1,15 @@ +//=require prismjs/prism.js +//=require prismjs/plugins/autoloader/prism-autoloader.js + +(function(app) { + 'use strict'; + + // Set autoloading path of the language definitions + Prism.plugins.autoloader.languages_path = '/assets/js/prism/'; + + // Re-run Prism.js on page change + app.on('ajax.after', function(target, data) { + console.info('Highlighting code blocks on new page'); + Prism.highlightAll(); + }); +})(window.app = window.app || {}); diff --git a/etc/1-globals/typo-code/typo-code.scss b/etc/1-globals/typo-code/typo-code.scss new file mode 100644 index 0000000..3aaef56 --- /dev/null +++ b/etc/1-globals/typo-code/typo-code.scss @@ -0,0 +1,120 @@ +// @font-face definitions +@include -cdd-font-face('Input Mono Narrow', 'input-mono-narrow-light', 300, normal); + +pre, code, kbd { + font-family: "Input Mono Narrow", Consolas, Monaco, "Andale Mono", monospace; + font-weight: 300; + font-size: -cdd-rem(16); + word-spacing: 0; +} + +pre { + tab-size: 4; + hyphens: none; + line-height: 1.5; + + padding: 1.5em; + border-radius: 0.3em; + + overflow: auto; + max-height: 30em; + margin-bottom: 1em; +} + +:not(pre) > code, kbd { + padding: 0.2em 0.3em 0.1em; + + border-radius: 0.3em; + white-space: normal; +} +kbd { + padding: 0.4em 0.5em 0.15em; + + background: $color--passive; + box-shadow: 0 2px 0 $color--passive-dark; +} + +/** + * okaidia theme for JavaScript, CSS and HTML + * Loosely based on Monokai textmate theme by http://www.monokai.nl/ + * @author ocodia + * + * Stripped from layout styling and other font styles + */ + +code, +pre { + color: #f8f8f2; + background: none; + text-shadow: 0 1px rgba(0, 0, 0, 0.3); +} + +:not(pre) > code, +pre { + background: #272822; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #f8f8f2; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.constant, +.token.symbol, +.token.deleted { + color: #f92672; +} + +.token.boolean, +.token.number { + color: #ae81ff; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #a6e22e; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string, +.token.variable { + color: #f8f8f2; +} + +.token.atrule, +.token.attr-value, +.token.function { + color: #e6db74; +} + +.token.keyword { + color: #66d9ef; +} + +.token.regex, +.token.important { + color: #fd971f; +} + +.token.entity { + cursor: help; +} diff --git a/etc/etc.scss b/etc/etc.scss new file mode 100644 index 0000000..fd2ddea --- /dev/null +++ b/etc/etc.scss @@ -0,0 +1,5 @@ +// Import shared styles +@import "../shared/shared"; + +// Import globals in correct order +@import "1-globals/typo-code/typo-code"; diff --git a/etc/readme.md b/etc/readme.md new file mode 100644 index 0000000..db4c78a --- /dev/null +++ b/etc/readme.md @@ -0,0 +1,3 @@ +# etc patterns + +This directory contains patterns that have been prepared but are currently not being used for any site. \ No newline at end of file diff --git a/license.md b/license.md new file mode 100644 index 0000000..6b23a9e --- /dev/null +++ b/license.md @@ -0,0 +1,23 @@ +# License for codesignd Patterns + +## Webfonts + +This repository contains webfont files of the [Input typeface](https://djr.com/input/). You may not use, copy, modify, merge, publish, distribute, sublicense and/or sell copies of these files if you don't have a valid font license (and even then you may only use the files that get provided to you directly). +Please support the work of David Jonathan Ross and buy a license if you want to use Input for your projects. You can find the [Input license terms](https://djr.com/license/) on David's website. + +## Design, CSS code and graphics + +Copyright (c) 2016 Lukas Bestle + +You may not use, copy, modify, merge, publish, distribute, sublicense and/or sell copies of the design, CSS code and graphics from this project without explicit permission by Lukas Bestle. + +## PHP and JS code + +**The MIT License (MIT)** +Copyright (c) 2016 Lukas Bestle + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..cff3b11 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "codesignd-patterns", + "description": "Pattern library for codesignd websites", + "homepage": "https://git.codesignd.com/sites/patterns", + "license": "SEE LICENSE IN license.md", + "private": true, + + "copyright": "2016 Lukas Bestle", + "licenseCSS": "See https://git.codesignd.com/sites/patterns/blob/master/license.md", + "licenseJS": "MIT" +} diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..6a2b0d2 --- /dev/null +++ b/readme.md @@ -0,0 +1,23 @@ +# codesignd Patterns + +Welcome to the pattern library that powers the codesignd websites! +Feel free to check out the building blocks I use and the code behind them. + +## Take a look at the full source code + +The source code of my sites is [hosted on my GitLab server](https://git.codesignd.com/groups/sites). Feel free to check that out too! + +## Contact me + +If you have any questions or if you would like to know more about the patterns, my sites or anything else, please don't hesitate to contact me: + +- [Email and contact form](https://codesignd.com/contact) +- [Follow me on Twitter](https://twitter.com/lukasbestle) +- Find me in the [Kirby Forum](https://forum.getkirby.com/users/lukasbestle) + +## License + +Design, CSS code and graphics: © 2016 Lukas Bestle +PHP and JS code: MIT License + +Full license terms in the [code repository](https://git.codesignd.com/sites/patterns/blob/master/license.md). diff --git a/shared/1-globals/colors/colors.html.php b/shared/1-globals/colors/colors.html.php new file mode 100644 index 0000000..32b6cd6 --- /dev/null +++ b/shared/1-globals/colors/colors.html.php @@ -0,0 +1,38 @@ +
+

Color previews

+ + + + +

Brand colors are specific to each site, so please also see the site-specific color previews.

+
diff --git a/shared/1-globals/colors/colors.scss b/shared/1-globals/colors/colors.scss new file mode 100644 index 0000000..c0b19d7 --- /dev/null +++ b/shared/1-globals/colors/colors.scss @@ -0,0 +1,104 @@ +$color--pagebg: #f2f2f2 !default; +$color--text: #000 !default; +$color--warn: #e63a16 !default; + +// Passive colors include some primary brand color +$color--passive: mix($color--brand-primary, #ddd, 3%) !default; +$color--passive-dark: darken($color--passive, 10%) !default; +$color--passive-light: lighten($color--passive, 5%) !default; + +// Mixin for the page pattern background +@mixin background--pagepattern { + background-color: $color--pagebg; + background: -cdd-img-url('pagepattern.svg'), none; +} + +// Color helper classes +.color--pagebg { + color: $color--pagebg; +} +.background--pagebg { + background: $color--pagebg; +} + +.background--pagepattern { + @include background--pagepattern; +} + +.color--text { + color: $color--text; +} +.background--text { + background: $color--text; +} + +.color--warn { + color: $color--warn; +} +.background--warn { + background: $color--warn; +} + +.color--passive { + color: $color--passive; +} +.background--passive { + background: $color--passive; +} + +.color--passive-dark { + color: $color--passive-dark; +} +.background--passive-dark { + background: $color--passive-dark; +} + +.color--passive-light { + color: $color--passive-light; +} +.background--passive-light { + background: $color--passive-light; +} + +.color--brand-primary { + color: $color--brand-primary; +} +.background--brand-primary { + background: $color--brand-primary; +} + +.color--brand-primary-alternate { + color: $color--brand-primary-alternate; +} +.background--brand-primary-alternate { + background: $color--brand-primary-alternate; +} + +.color--brand-secondary { + color: $color--brand-secondary; +} +.background--brand-secondary { + background: $color--brand-secondary; +} + +.color--brand-secondary-alternate { + color: $color--brand-secondary-alternate; +} +.background--brand-secondary-alternate { + background: $color--brand-secondary-alternate; +} + +// Set the main colors on body +body { + color: $color--text; + @include background--pagepattern; + + @media print { + background: none; + } +} + +// Selection background +::selection { + background: lighten($color--brand-primary, 30%); +} diff --git a/shared/1-globals/colors/pagepattern.svg b/shared/1-globals/colors/pagepattern.svg new file mode 100644 index 0000000..b29d463 --- /dev/null +++ b/shared/1-globals/colors/pagepattern.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/shared/1-globals/helpers/helpers.js b/shared/1-globals/helpers/helpers.js new file mode 100644 index 0000000..61366ea --- /dev/null +++ b/shared/1-globals/helpers/helpers.js @@ -0,0 +1,89 @@ +(function(app) { + 'use strict'; + + // Store for the event handlers + var handlers = {}; + var hasOwnProperty = handlers.hasOwnProperty; + + /** + * Registers an event handler for a specified event + * + * @param {string} event Event name + * @param {Function} callback + * @return {object} Object with a remove() method to unsubscribe from events + */ + app.on = function(event, callback) { + // Create event array if not already existing + if(!hasOwnProperty.call(handlers, event)) handlers[event] = []; + + // Add the callback to the array + var index = handlers[event].push(callback) - 1; + + // Return function to delete handler again + return { + remove: function() { + delete handlers[event][index]; + } + }; + }; + + /** + * Triggers an event with a given event argument + * + * @param {string} event Event name + * @param {mixed} ... Arbitrary arguments to pass to every callback + */ + app.emit = function(event) { + if(!hasOwnProperty.call(handlers, event)) return; + + var args = Array.prototype.slice.call(arguments, 1); + handlers[event].forEach(function(handler) { + handler.apply(undefined, args); + }); + }; + + /** + * Returns a promise that resolves after the specified time + * + * @param {integer} time Time in milliseconds + * @return {Promise} + */ + app.timerPromise = function(time) { + return new Promise(function(resolve, reject) { + setTimeout(resolve, time); + }); + }; + + /** + * Validates that a fetch() request has a HTTP status code in the 200 range + * + * @param {Response} response fetch() response + * @return {Response} Same response object to allow for chaining + */ + app.validateHttpStatus = function(response) { + if(response.status >= 200 && response.status < 300) { + return response; + } else { + var error = new Error('HTTP response with status: ' + response.status + ' ' + response.statusText); + error.response = response; + throw error; + } + }; + + /** + * Converts a fetch() response to JSON + * + * @param {Response} response fetch() response + * @return {Promise} + */ + app.parseJsonResponse = function(response) { + // Validate that the response is JSON + var contentType = response.headers.get('Content-Type'); + if(contentType.indexOf('application/json') !== 0) { + throw new Error('Got content type "' + contentType + '", expected JSON.'); + } + + // Convert response to JSON + return response.json(); + }; +})(window.app = window.app || {}); diff --git a/shared/1-globals/helpers/helpers.scss b/shared/1-globals/helpers/helpers.scss new file mode 100644 index 0000000..7a697a9 --- /dev/null +++ b/shared/1-globals/helpers/helpers.scss @@ -0,0 +1,50 @@ +/// +// Converts a pixel value to ems with a base font size of 18 px +// +// @param {int} $px Target pixel value +// @return {value} Pixel value converted to ems +/// +@function -cdd-em($px) { + @return ($px / 18) * 1em; +} + +/// +// Converts a pixel value to rems with a base font size of 18 px +// +// @param {int} $px Target pixel value +// @return {value} Pixel value converted to rems +/// +@function -cdd-rem($px) { + @return ($px / 18) * 1rem; +} + +/// +// Returns the correct url() to an image in assets/img +// +// @param {string} $name Filename of the image +// @return {value} +/// +@function -cdd-img-url($name) { + @return url(-cdd-cachebuster('/assets/img/' + $name)); +} + +/// +// Helper to embed @font-face declarations +// Inspired by https://gist.github.com/jonathantneal/d0460e5c2d5d7f9bc5e6 +// +// @param {string} $name Font name (human-readable) +// @param {string} $file Name of the font file +// @param {int} $weight font-weight value of the font file +// @param {string} $style font-style value of the font file +/// +@mixin -cdd-font-face($name, $file, $weight: normal, $style: normal) { + @font-face { + font-family: quote($name); + font-style: $style; + font-weight: $weight; + src: url(-cdd-cachebuster('/assets/fonts/' + $file + '.eot')); // IE < 9 + src: url(-cdd-cachebuster('/assets/fonts/' + $file + '.eot') + '?#') format('embedded-opentype'), // IE 9 + url(-cdd-cachebuster('/assets/fonts/' + $file + '.woff2')) format('woff2'), + url(-cdd-cachebuster('/assets/fonts/' + $file + '.woff')) format('woff'); + } +} diff --git a/shared/1-globals/layout/layout.scss b/shared/1-globals/layout/layout.scss new file mode 100644 index 0000000..2cf2d94 --- /dev/null +++ b/shared/1-globals/layout/layout.scss @@ -0,0 +1,57 @@ +body { + // Make sure that the footer is always at the bottom of the page + min-height: 100vh; + display: flex; + flex-direction: column; + + // Hide horizontal overflow (required for animated contact forms) + overflow-x: hidden; +} + +.main { + flex: 1; + + // Fallback as IE does not respect min-height flex containers + flex-basis: auto; +} + +// Page padding for print +@media print { + @page { + margin: 1.5cm; + } +} + +// Visually hidden +.vh { + position: absolute; + top: -9999px; + left: -9999px; +} + +// Container mixins +@mixin container { + width: 100%; + padding: 0 1.5rem; + margin: 0 auto; + + @media (max-width: 30em) { + padding: 0 1rem; + } + + @media print { + padding: 0; + } +} + +@mixin container--full { + @include container; + + max-width: 60rem; +} + +@mixin container--text { + @include container; + + max-width: 42rem; +} diff --git a/shared/1-globals/media/media.scss b/shared/1-globals/media/media.scss new file mode 100644 index 0000000..6847285 --- /dev/null +++ b/shared/1-globals/media/media.scss @@ -0,0 +1,4 @@ +img, svg { + max-width: 100%; + height: auto; +} diff --git a/shared/1-globals/reset/reset.scss b/shared/1-globals/reset/reset.scss new file mode 100644 index 0000000..241c9bf --- /dev/null +++ b/shared/1-globals/reset/reset.scss @@ -0,0 +1,38 @@ +html { + // Use border-box box sizing + box-sizing: border-box; + + // Disable text size adjustment on device rotation + text-size-adjust: 100%; + + // Always display vertical scrollbar + overflow-y: scroll; +} + +*, *::before, *::after { + // Reset all spacing + margin: 0; + padding: 0; + + // Inherit box-sizing from html element + box-sizing: inherit; + + // Disable default styling for certain elements + list-style: none; + border: none; + box-shadow: none; +} + +// Disable all vertical margins for first and last childs of a container +:first-child { + margin-top: 0; +} +:last-child { + margin-bottom: 0; +} + +// Make old browsers understand HTML5 elements +article, aside, details, figcaption, figure, +footer, header, main, menu, nav, section, summary { + display: block; +} diff --git a/shared/1-globals/typo/generator_config.txt b/shared/1-globals/typo/generator_config.txt new file mode 100644 index 0000000..d9915c9 --- /dev/null +++ b/shared/1-globals/typo/generator_config.txt @@ -0,0 +1,5 @@ +# Font Squirrel Font-face Generator Configuration File +# Upload this file to the generator to recreate the settings +# you used to create these fonts. + +{"mode":"expert","formats":["woff","woff2","eotz"],"tt_instructor":"keep","fix_gasp":"xy","fix_vertical_metrics":"N","metrics_ascent":"","metrics_descent":"","metrics_linegap":"","add_spaces":"Y","add_hyphens":"Y","fallback":"none","fallback_custom":"100","webonly":"Y","options_subset":"advanced","subset_range":["macroman","typographics","math","english","german"],"subset_custom":"","subset_custom_range":"","subset_ot_features_list":"","css_stylesheet":"stylesheet.css","filename_suffix":"","spacing_adjustment":"0","rememberme":"Y"} \ No newline at end of file diff --git a/shared/1-globals/typo/input-sans-narrow-bold.eot b/shared/1-globals/typo/input-sans-narrow-bold.eot new file mode 100644 index 0000000..1953705 Binary files /dev/null and b/shared/1-globals/typo/input-sans-narrow-bold.eot differ diff --git a/shared/1-globals/typo/input-sans-narrow-bold.woff b/shared/1-globals/typo/input-sans-narrow-bold.woff new file mode 100644 index 0000000..615b6ed Binary files /dev/null and b/shared/1-globals/typo/input-sans-narrow-bold.woff differ diff --git a/shared/1-globals/typo/input-sans-narrow-bold.woff2 b/shared/1-globals/typo/input-sans-narrow-bold.woff2 new file mode 100644 index 0000000..f02f570 Binary files /dev/null and b/shared/1-globals/typo/input-sans-narrow-bold.woff2 differ diff --git a/shared/1-globals/typo/input-sans-narrow-italic.eot b/shared/1-globals/typo/input-sans-narrow-italic.eot new file mode 100644 index 0000000..d11dccc Binary files /dev/null and b/shared/1-globals/typo/input-sans-narrow-italic.eot differ diff --git a/shared/1-globals/typo/input-sans-narrow-italic.woff b/shared/1-globals/typo/input-sans-narrow-italic.woff new file mode 100644 index 0000000..e6b7671 Binary files /dev/null and b/shared/1-globals/typo/input-sans-narrow-italic.woff differ diff --git a/shared/1-globals/typo/input-sans-narrow-italic.woff2 b/shared/1-globals/typo/input-sans-narrow-italic.woff2 new file mode 100644 index 0000000..4a089e4 Binary files /dev/null and b/shared/1-globals/typo/input-sans-narrow-italic.woff2 differ diff --git a/shared/1-globals/typo/input-sans-narrow-regular.eot b/shared/1-globals/typo/input-sans-narrow-regular.eot new file mode 100644 index 0000000..181d0e9 Binary files /dev/null and b/shared/1-globals/typo/input-sans-narrow-regular.eot differ diff --git a/shared/1-globals/typo/input-sans-narrow-regular.woff b/shared/1-globals/typo/input-sans-narrow-regular.woff new file mode 100644 index 0000000..23eaab1 Binary files /dev/null and b/shared/1-globals/typo/input-sans-narrow-regular.woff differ diff --git a/shared/1-globals/typo/input-sans-narrow-regular.woff2 b/shared/1-globals/typo/input-sans-narrow-regular.woff2 new file mode 100644 index 0000000..7dc5238 Binary files /dev/null and b/shared/1-globals/typo/input-sans-narrow-regular.woff2 differ diff --git a/shared/1-globals/typo/input-serif-narrow-bold.eot b/shared/1-globals/typo/input-serif-narrow-bold.eot new file mode 100644 index 0000000..6522a90 Binary files /dev/null and b/shared/1-globals/typo/input-serif-narrow-bold.eot differ diff --git a/shared/1-globals/typo/input-serif-narrow-bold.woff b/shared/1-globals/typo/input-serif-narrow-bold.woff new file mode 100644 index 0000000..91bf2ff Binary files /dev/null and b/shared/1-globals/typo/input-serif-narrow-bold.woff differ diff --git a/shared/1-globals/typo/input-serif-narrow-bold.woff2 b/shared/1-globals/typo/input-serif-narrow-bold.woff2 new file mode 100644 index 0000000..ce5b18b Binary files /dev/null and b/shared/1-globals/typo/input-serif-narrow-bold.woff2 differ diff --git a/shared/1-globals/typo/typo.html.php b/shared/1-globals/typo/typo.html.php new file mode 100644 index 0000000..c51998b --- /dev/null +++ b/shared/1-globals/typo/typo.html.php @@ -0,0 +1,65 @@ + +
+

Typography preview

+

Lorem Ipsum

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptas repellendus modi ea praesentium totam, earum, accusamus pariatur cumque. Ä, quia, dolore! Reiciendis, odio iure accusamus consequatur eveniet voluptates quibusdam consequuntur!

+ +

Dolor sit amet

+

Lorem ipsum dolor sit amet.

+ +

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+
    +
  1. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
  2. +
  3. Üt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
  4. +
  5. Duis aute irure dolor in reprehenderit!
  6. +
+

Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ +

Consectetur adipisicing elit

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptas repellendus modi ea praesentium totam, earum, accusamus pariatur cumque. Ä, quia, dolore! Reiciendis, odio iure accusamus consequatur eveniet voluptates quibusdam consequuntur!

+
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+ +

Voluptas repellendus modi

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptas repellendus modi ea praesentium totam, earum, accusamus pariatur cumque. Ä, quia, dolore! Reiciendis, odio iure accusamus consequatur eveniet voluptates quibusdam consequuntur!

+ +
+ +

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. +

+

Heading 1

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. +

+

Heading 2

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. +

+

Heading 3

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. +

+

Heading 4

+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. +

+
Heading 5
+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. +

+
Heading 6
+

+ Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. +

+
diff --git a/shared/1-globals/typo/typo.scss b/shared/1-globals/typo/typo.scss new file mode 100644 index 0000000..1fb7286 --- /dev/null +++ b/shared/1-globals/typo/typo.scss @@ -0,0 +1,119 @@ +// @font-face definitions +@include -cdd-font-face('Input Sans Narrow', 'input-sans-narrow-regular', normal, normal); +@include -cdd-font-face('Input Sans Narrow', 'input-sans-narrow-italic', normal, italic); +@include -cdd-font-face('Input Sans Narrow', 'input-sans-narrow-bold', bold, normal); +@include -cdd-font-face('Input Serif Narrow', 'input-serif-narrow-bold', bold, normal); + +:root { + font-size: 112.5%; + line-height: 1.7; + font-family: "Input Sans Narrow", Tahoma, Helvetica, sans-serif; + word-spacing: -0.1em; + + // Make everything slightly smaller on small screens + @media (max-width: 30em) { + font-size: 100%; + } +} + +h1, h2, h3, h4, h5, h6 { + font-family: "Input Serif Narrow", "Hoefler Text", Palatino, serif; + line-height: 1.35; + text-rendering: optimizeLegibility; + + margin-top: 1.3em; + margin-bottom: 0.9em; + + @media print { + page-break-after: avoid; + } +} +h1 { + font-size: -cdd-rem(36); +} +h2 { + font-size: -cdd-rem(27); +} +h3 { + font-size: -cdd-rem(20); + + margin-bottom: 0.6em; +} +h4 { + font-size: -cdd-rem(18); +} +h5 { + font-size: -cdd-rem(18); + font-variant: small-caps; +} +h6 { + font-size: -cdd-rem(14); + text-transform: uppercase; + + margin-top: 1.6em; +} + +a { + transition: color 0.2s ease; + + &:link, &:visited { + text-decoration: none; + color: $color--brand-primary; + } + &:hover, &:focus, &:active { + color: $color--brand-primary-alternate; + } +} + +hr { + height: 0; + margin-top: 2em; + margin-bottom: 2em; + + border-top: -cdd-rem(2) solid $color--passive; + + @media print { + page-break-after: avoid; + } +} + +small { + font-size: -cdd-rem(14); +} + +// Content within Kirbytext +.text { + &-container { + @include container--text; + } + + p:not(:last-child), ul:not(:last-child), + ol:not(:last-child), blockquote:not(:last-child) { + margin-bottom: 1em; + } + + ul, ol { + padding-left: 40px; + } + ul li { + list-style: disc; + } + ol li { + list-style: decimal; + } + li:not(:last-child) { + margin-bottom: 0.1em; + } + + a:visited { + color: $color--brand-primary-alternate; + } + + blockquote { + padding: 0.5em 1em; + + background: $color--passive-light; + border-left: 0.7em solid $color--passive; + border-radius: 0 0.3em 0.3em 0; + } +} diff --git a/shared/2-blocks/button/button.config.php b/shared/2-blocks/button/button.config.php new file mode 100644 index 0000000..52ab7f6 --- /dev/null +++ b/shared/2-blocks/button/button.config.php @@ -0,0 +1,11 @@ + [ + 'text' => 'Learn more', + 'label' => false, + 'link' => url(), + 'modifiers' => [], + 'class' => false + ] +]; diff --git a/shared/2-blocks/button/button.html.php b/shared/2-blocks/button/button.html.php new file mode 100644 index 0000000..b8dfe82 --- /dev/null +++ b/shared/2-blocks/button/button.html.php @@ -0,0 +1,12 @@ + + aria-label=""> diff --git a/shared/2-blocks/button/button.scss b/shared/2-blocks/button/button.scss new file mode 100644 index 0000000..7323c28 --- /dev/null +++ b/shared/2-blocks/button/button.scss @@ -0,0 +1,45 @@ +.button { + display: inline-block; + text-align: center; + + font: inherit; + line-height: inherit; + background: none; + cursor: pointer; + + padding: 0.3em 0.5em 0.2em; + border: 1px solid $color--brand-primary; + border-radius: -cdd-em(4); + + & + & { + margin-top: 0.5em; + } + + transition: color 0.2s ease, border-color 0.2s ease; + + &, &:link, &:visited { + color: $color--brand-primary; + } + + &:hover, &:focus, &:not(&--novisited):visited { + border-color: $color--brand-primary-alternate; + color: $color--brand-primary-alternate; + } + + &--secondary { + &, &:link, &:visited { + border-color: $color--brand-secondary; + color: $color--brand-secondary; + } + + &:hover, &:focus, &:not(.button--novisited):visited { + border-color: $color--brand-secondary-alternate; + color: $color--brand-secondary-alternate; + } + } + + &:disabled, &--disabled { + border-color: $color--passive-dark; + color: $color--passive-dark; + } +} diff --git a/shared/2-blocks/cta/cta.config.php b/shared/2-blocks/cta/cta.config.php new file mode 100644 index 0000000..969f32d --- /dev/null +++ b/shared/2-blocks/cta/cta.config.php @@ -0,0 +1,9 @@ + [ + 'text' => '

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptas repellendus modi ea praesentium totam, earum, accusamus pariatur cumque.

', + 'button' => 'Learn more', + 'link' => url() + ] +]; diff --git a/shared/2-blocks/cta/cta.html.php b/shared/2-blocks/cta/cta.html.php new file mode 100644 index 0000000..52d559c --- /dev/null +++ b/shared/2-blocks/cta/cta.html.php @@ -0,0 +1,4 @@ +
+
+ $button, 'link' => $link, 'modifiers' => 'novisited', 'class' => 'cta__button']) ?> +
diff --git a/shared/2-blocks/cta/cta.scss b/shared/2-blocks/cta/cta.scss new file mode 100644 index 0000000..4e4c537 --- /dev/null +++ b/shared/2-blocks/cta/cta.scss @@ -0,0 +1,26 @@ +.cta { + display: flex; + align-items: center; + + font-size: -cdd-rem(20); +} + +.cta__text { + flex: 1; + margin-right: 1em; +} + +@media (max-width: 40em) { + .cta { + flex-direction: column; + } + + .cta__text { + margin-right: 0; + margin-bottom: 0.7em; + } + + .cta__button { + width: 100%; + } +} diff --git a/shared/2-blocks/field/field.html.php b/shared/2-blocks/field/field.html.php new file mode 100644 index 0000000..a7cd2d1 --- /dev/null +++ b/shared/2-blocks/field/field.html.php @@ -0,0 +1,16 @@ +
+
+ + +
+ +
+ + +
+ +
+ + +
+
diff --git a/shared/2-blocks/field/field.scss b/shared/2-blocks/field/field.scss new file mode 100644 index 0000000..e385d9a --- /dev/null +++ b/shared/2-blocks/field/field.scss @@ -0,0 +1,47 @@ +.field { + position: relative; + + background: white; + border: 2px solid $color--passive; + border-radius: 0.2rem; + + width: 100%; + @media (min-width: 35em) { + &--small { + width: 50%; + } + } +} + +.field__label { + font-size: -cdd-rem(14); + + position: absolute; + top: 0; + left: 0; + z-index: 1; + + display: block; + padding: 0.3rem 0.4rem; + + .field--required &::after { + padding-left: 0.1em; + content: '*'; + color: $color--warn; + } +} + +.field__input { + font: inherit; + border-radius: 0.2rem; + + display: block; + width: 100%; + padding: 0.3rem 0.4rem; + padding-top: 1.7rem; +} + +// Prevent horizontal resizing +.field textarea { + resize: vertical; +} diff --git a/shared/2-blocks/footer/footer.config.php b/shared/2-blocks/footer/footer.config.php new file mode 100644 index 0000000..a58f95f --- /dev/null +++ b/shared/2-blocks/footer/footer.config.php @@ -0,0 +1,7 @@ + [ + 'pSite' => 'patterns' + ] +]; diff --git a/shared/2-blocks/footer/footer.html.php b/shared/2-blocks/footer/footer.html.php new file mode 100644 index 0000000..1a0c29f --- /dev/null +++ b/shared/2-blocks/footer/footer.html.php @@ -0,0 +1,13 @@ + diff --git a/shared/2-blocks/footer/footer.scss b/shared/2-blocks/footer/footer.scss new file mode 100644 index 0000000..3605bb9 --- /dev/null +++ b/shared/2-blocks/footer/footer.scss @@ -0,0 +1,48 @@ +.footer { + @include container--full; + margin-top: 3rem; + margin-bottom: 2.5rem; + + display: flex; + justify-content: space-between; + + font-size: -cdd-rem(14); + + @media (max-width: 69em) { + margin-bottom: 1.5rem; + } + + @media (max-width: 35em) { + flex-direction: column; + align-items: center; + } + + @media print { + margin-bottom: 0; + } +} + +.footer__top { + display: none; + + @media (max-width: 35em) { + display: block; + margin-bottom: 0.8em; + } + + @media print { + display: none; + } +} + +.footer__nav li { + display: inline-block; + + &:not(:last-child)::after { + content: '·'; + display: inline-block; + padding: 0 0.25em; + + color: $color--passive-dark; + } +} diff --git a/shared/2-blocks/form/form.html.php b/shared/2-blocks/form/form.html.php new file mode 100644 index 0000000..5cfd15b --- /dev/null +++ b/shared/2-blocks/form/form.html.php @@ -0,0 +1,12 @@ +
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, + quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse + cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non + proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

+ +
Lorem ipsum dolor sit amet, consectetur adipisicing elit.
+ + +
diff --git a/shared/2-blocks/form/form.scss b/shared/2-blocks/form/form.scss new file mode 100644 index 0000000..496d7f0 --- /dev/null +++ b/shared/2-blocks/form/form.scss @@ -0,0 +1,29 @@ +.form { + display: flex; + flex-wrap: wrap; + + padding: 1rem; + background: $color--passive; + border-radius: 0.3rem; + + transition: visibility 0s linear 0.7s, transform 0.7s cubic-bezier(0.8, -0.1, 0.5, 0); + + &--success { + visibility: hidden; + transform: translate(100vw); + } +} + +.form__message { + width: 100%; + + &:not(:empty) { + margin-top: 1rem; + } + + color: $color--warn; +} + +.form__submit { + margin-top: 1rem; +} diff --git a/shared/2-blocks/header/header.config.php b/shared/2-blocks/header/header.config.php new file mode 100644 index 0000000..95212ca --- /dev/null +++ b/shared/2-blocks/header/header.config.php @@ -0,0 +1,8 @@ + [ + 'pSite' => 'codesignd', + 'navData' => [] + ] +]; diff --git a/shared/2-blocks/header/header.html.php b/shared/2-blocks/header/header.html.php new file mode 100644 index 0000000..288e911 --- /dev/null +++ b/shared/2-blocks/header/header.html.php @@ -0,0 +1,6 @@ +
+
+ + +
+
diff --git a/shared/2-blocks/header/header.scss b/shared/2-blocks/header/header.scss new file mode 100644 index 0000000..3ed4908 --- /dev/null +++ b/shared/2-blocks/header/header.scss @@ -0,0 +1,28 @@ +.header { + background: url(/assets/img/baromator.svg); + background-repeat: repeat-x; + + padding-top: 55px; + margin-bottom: 3rem; + + @media (max-width: 40em) { + margin-bottom: 2rem; + } + + @media print { + background: none; + padding-top: 0; + } +} + +.header__inner { + @include container--full; + + display: flex; + justify-content: space-between; + + @media (max-width: 40em) { + flex-direction: column; + align-items: center; + } +} diff --git a/shared/2-blocks/illustrated-text/illustrated-text.config.php b/shared/2-blocks/illustrated-text/illustrated-text.config.php new file mode 100644 index 0000000..cc25dac --- /dev/null +++ b/shared/2-blocks/illustrated-text/illustrated-text.config.php @@ -0,0 +1,9 @@ + [ + 'image' => 'https://placekitten.com/400/600', + 'alt' => 'Picture of a cat', + 'text' => '

I\'m apparently a cat!

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

' + ] +]; diff --git a/shared/2-blocks/illustrated-text/illustrated-text.html.php b/shared/2-blocks/illustrated-text/illustrated-text.html.php new file mode 100644 index 0000000..28b91b8 --- /dev/null +++ b/shared/2-blocks/illustrated-text/illustrated-text.html.php @@ -0,0 +1,9 @@ +
+ + +
+ +
+
diff --git a/shared/2-blocks/illustrated-text/illustrated-text.scss b/shared/2-blocks/illustrated-text/illustrated-text.scss new file mode 100644 index 0000000..fa8aeee --- /dev/null +++ b/shared/2-blocks/illustrated-text/illustrated-text.scss @@ -0,0 +1,46 @@ +.illustrated-text { + display: flex; + align-items: flex-start; + + &:not(&--decorative) { + @media (max-width: 30em) { + flex-direction: column-reverse; + } + } +} + +.illustrated-text__sidebar { + width: 14em; + margin-right: 2em; + + @media (max-width: 60em) { + width: 10em; + margin-right: 1.5em; + } + + @media (max-width: 50em) { + width: 5em; + margin-right: 1em; + } + + @media (max-width: 41em) { + .illustrated-text--decorative & { + display: none; + } + } + + @media (max-width: 30em) { + width: 100%; + margin-right: 0; + margin-top: 1em; + } + + * { + width: 100%; + display: block; + } +} + +.illustrated-text__main { + flex: 1; +} diff --git a/shared/2-blocks/input/input.html.php b/shared/2-blocks/input/input.html.php new file mode 100644 index 0000000..3b737f7 --- /dev/null +++ b/shared/2-blocks/input/input.html.php @@ -0,0 +1,16 @@ +
+
+ + +
+ +
+ + +
+ +
+ + +
+
diff --git a/shared/2-blocks/input/input.scss b/shared/2-blocks/input/input.scss new file mode 100644 index 0000000..9460418 --- /dev/null +++ b/shared/2-blocks/input/input.scss @@ -0,0 +1,16 @@ +.input { + background: -cdd-img-url('warn.svg'); + background-size: 1.5rem; + background-repeat: no-repeat; + + background-position: calc(100% + 1.5rem + 1px) center; + transition: background-position 0.2s ease; + + // Duplicated styles for browsers that don't support :placeholder-shown + &:invalid:not(:focus):not(:placeholder-shown) { + background-position: calc(100% - 0.7rem) center; + } + &--invalid { + background-position: calc(100% - 0.7rem) center; + } +} diff --git a/shared/2-blocks/input/warn.svg b/shared/2-blocks/input/warn.svg new file mode 100644 index 0000000..5ab1377 --- /dev/null +++ b/shared/2-blocks/input/warn.svg @@ -0,0 +1 @@ + diff --git a/shared/2-blocks/logo/logo.scss b/shared/2-blocks/logo/logo.scss new file mode 100644 index 0000000..8648333 --- /dev/null +++ b/shared/2-blocks/logo/logo.scss @@ -0,0 +1,11 @@ +.logo { + width: 20em; + max-width: 100%; + flex-shrink: 0; + display: inline-block; + line-height: 1; +} + +.logo__image { + width: 100%; +} diff --git a/shared/2-blocks/main/main.scss b/shared/2-blocks/main/main.scss new file mode 100644 index 0000000..1e58b32 --- /dev/null +++ b/shared/2-blocks/main/main.scss @@ -0,0 +1,3 @@ +.main { + @include container--full; +} diff --git a/shared/2-blocks/nav/nav.config.php b/shared/2-blocks/nav/nav.config.php new file mode 100644 index 0000000..ca5dce7 --- /dev/null +++ b/shared/2-blocks/nav/nav.config.php @@ -0,0 +1,17 @@ + [ + 'wrapper' => true, + 'languages' => [], + 'items' => [] + ], + 'preview' => function() { + $site = site(); + + return [ + 'languages' => $site->languages(), + 'items' => $site->pages()->visible() + ]; + } +]; diff --git a/shared/2-blocks/nav/nav.html.php b/shared/2-blocks/nav/nav.html.php new file mode 100644 index 0000000..e75496d --- /dev/null +++ b/shared/2-blocks/nav/nav.html.php @@ -0,0 +1,16 @@ + diff --git a/shared/2-blocks/nav/nav.scss b/shared/2-blocks/nav/nav.scss new file mode 100644 index 0000000..d749aa7 --- /dev/null +++ b/shared/2-blocks/nav/nav.scss @@ -0,0 +1,54 @@ +.nav { + display: flex; + flex-direction: column; + justify-content: space-between; + + margin-left: 4rem; +} + +.nav__section { + text-align: right; + + &--languages { + line-height: 1; + margin-bottom: 0.5rem; + + @media (max-width: 40em) { + margin-bottom: 0.8rem; + } + } + + &--pages { + line-height: 1.4; + font-size: 1.2rem; + } +} + +.nav__item { + display: inline-block; + + &:not(:first-child) { + margin-left: 0.5em; + } + + &--compact:not(:first-child) { + margin-left: 0.25em; + } + + &--active .nav__link { + color: $color--brand-secondary; + pointer-events: none; + } +} + +@media (max-width: 40em) { + .nav { + margin: 0; + margin-top: 1.5rem; + width: 100%; + } + + .nav__section { + text-align: center; + } +} diff --git a/shared/3-sugar/ajax/ajax.js b/shared/3-sugar/ajax/ajax.js new file mode 100644 index 0000000..85d87ff --- /dev/null +++ b/shared/3-sugar/ajax/ajax.js @@ -0,0 +1,169 @@ +//=require element-closest/closest.js +//=require whatwg-fetch/fetch.js +//=require flexismooth/flexismooth.js + +(function(app) { + 'use strict'; + + // Cache for successful requests + var cache = {}; + var hasOwnProperty = cache.hasOwnProperty; + + /** + * Navigates to another page using AJAX + * + * @param {Element/string} target Anchor element or URL string to navigate to + * @param {string} mode Either 'normal' or 'popstate', defaults to 'normal' + * @return {boolean} Whether the event will be handled by this function + * May be used to prevent default browser behavior + */ + app.go = function(target, mode) { + if(mode === undefined) mode = 'normal'; + + // Refuse to do anything if the History API is not supported + if(!history.pushState) return false; + + // Validate params + if(typeof target !== 'string' && target.nodeType !== 1) { + throw new TypeError('Invalid parameter target.'); + } + if(mode !== 'normal' && mode !== 'popstate') { + throw new TypeError('Invalid parameter mode.'); + } + + // Convert to anchor element if param is a string + if(typeof target === 'string') { + var link = document.createElement('a'); + link.href = target; + target = link; + } + + // Only do something if: + // - The user clicked on a link + // - The link is internal + // - The link doesn't contain a file extension + var targetOrigin, windowOrigin; + if(target.origin) { + targetOrigin = target.origin; + windowOrigin = window.location.origin; + } else { + targetOrigin = target.protocol + '//' + target.hostname; + windowOrigin = window.location.protocol + '//' + window.location.hostname; + } + if(target.nodeName !== 'A' || + targetOrigin !== windowOrigin || + target.pathname.indexOf('.') !== -1) return false; + + // Just scroll to the top/element if the link points to the current page + // In this case, we also don't want to reload, so we return true + if(target.pathname === window.location.pathname) { + var element; + if(target.hash) { + if(mode === 'normal' && target.hash !== '#top') { + history.pushState({}, document.title, target.href); + } + element = document.getElementById(target.hash.substr(1)); + } + + Flexismooth(element || 0, 500); + return true; + } + + // Success, we will navigate using AJAX + // Hide the content using CSS and trigger event + document.body.classList.add('ajax-transition'); + app.emit('ajax.before', target); + + // Scroll to the top of the page and ignore interruption + var scrollPromise = Flexismooth(0, 500).catch(function() {}); + + // Check if the resource is in cache + var dataPromise; + if(hasOwnProperty.call(cache, target.href)) { + console.info('Loading new page ' + target.href + ' (cache)'); + + dataPromise = Promise.resolve(cache[target.href]); + } else { + console.info('Loading new page ' + target.href + ' (ajax)'); + + var options = { + credentials: 'same-origin', + headers: {'Accept': 'application/json'} + }; + dataPromise = fetch(target.href, options) + .then(app.validateHttpStatus) + .then(app.parseJsonResponse) + .then(function(data) { + // Cache data if the page explicitly agrees + if(data.cachable === true) { + cache[data.url] = data; + } + + return data; + }); + } + + // Prefetch external resources + dataPromise = dataPromise.then(function(data) { + var container = document.createElement('div'); + container.innerHTML = data.main; + + return data; + }); + + // Wait until both data fetching and scrolling are done + // Wait at least 600 ms for the page transition fading even if scrolling is interrupted + Promise.all([dataPromise, scrollPromise, app.timerPromise(600)]) + .then(function(values) { + // Get the result of the data promise + var data = values[0]; + + // Set browser metadata + if(mode === 'normal') history.pushState({}, data.title, data.url + target.hash); + document.title = data.title; + + // Update content blocks + document.querySelector('.main').innerHTML = data.main; + + // Trigger event + app.emit('ajax.after', target, data); + + // Display the content again + document.body.classList.remove('ajax-transition'); + + // If a hash was given, scroll to that element + if(target.hash) { + var element = document.getElementById(target.hash.substr(1)); + if(element) Flexismooth(element, 500); + } + }) + .catch(function(err) { + console.error(err); + + // Fall back to normal browser behavior + window.location.href = target.href; + }); + + return true; + }; + + // Listen on click events on body (events from links will bubble up) + document.body.addEventListener('click', function(e) { + // Only continue if no modifier was used (open in new tab etc.) + if(e.ctrlKey || e.shiftKey || e.metaKey || (e.button && e.button === 1)) return; + + // Find closest link parent + var link = e.target.closest('a'); + + // Only continue if the link was found + if(!link) return; + + // Prevent the browser from navigating if app.go() wants to be responsible for the event + if(app.go(link)) e.preventDefault(); + }); + + // Listen on the popstate event on window + window.addEventListener('popstate', function(e) { + if(e.state !== null) app.go(window.location.href, 'popstate'); + }); +})(window.app = window.app || {}); diff --git a/shared/3-sugar/ajax/ajax.scss b/shared/3-sugar/ajax/ajax.scss new file mode 100644 index 0000000..6c62228 --- /dev/null +++ b/shared/3-sugar/ajax/ajax.scss @@ -0,0 +1,11 @@ +.ajax-transition { + cursor: progress; +} + +.main { + transition: opacity 0.5s ease; + + .ajax-transition & { + opacity: 0; + } +} diff --git a/shared/shared.scss b/shared/shared.scss new file mode 100644 index 0000000..d7836b7 --- /dev/null +++ b/shared/shared.scss @@ -0,0 +1,23 @@ +// Import globals in correct order +@import "1-globals/helpers/helpers"; +@import "1-globals/reset/reset"; +@import "1-globals/layout/layout"; +@import "1-globals/colors/colors"; +@import "1-globals/typo/typo"; +@import "1-globals/media/media"; + +// Import blocks in alphabetical order (they are strictly independent) +@import "2-blocks/button/button"; +@import "2-blocks/cta/cta"; +@import "2-blocks/field/field"; +@import "2-blocks/footer/footer"; +@import "2-blocks/form/form"; +@import "2-blocks/header/header"; +@import "2-blocks/illustrated-text/illustrated-text"; +@import "2-blocks/input/input"; +@import "2-blocks/logo/logo"; +@import "2-blocks/main/main"; +@import "2-blocks/nav/nav"; + +// Import sugar in alphabetical order +@import "3-sugar/ajax/ajax"; diff --git a/theme.css b/theme.css new file mode 100644 index 0000000..c7ccf9e --- /dev/null +++ b/theme.css @@ -0,0 +1,38 @@ +/* Wrapper for abstract patterns like colors and typography */ +.preview-canvas { + max-width: 42rem; + margin: 0 auto; + padding: 3rem; +} + +/* Color palette to demonstrate colors */ +.palette { + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + + margin-bottom: 0.5rem; +} + +.palette__color { + width: 5.3rem; + margin-right: 0.3rem; + margin-bottom: 0.3rem; + padding: 0.25rem; + + border: 1px solid #ddd; + background: white; +} + +.palette__swatch { + width: 100%; + padding-bottom: 100%; /* Make the element square */ + margin-bottom: 0.4rem; +} + +.palette__label { + font-size: 0.7rem; + text-align: center; +}