2 | P R E F O R M A T T E D T E X T
3 | ! " # $ % & ' ( ) * + , - . /
4 | 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
5 | @ A B C D E F G H I J K L M N O
6 | P Q R S T U V W X Y Z [ \ ] ^ _
7 | ` a b c d e f g h i j k l m n o
8 | p q r s t u v w x y z { | } ~
9 |
A block quotation (also known as a long quotation or extract) is a quotation in a written document, that is set off from the main text as a paragraph, or block of text, and typically distinguished visually using indentation and a different typeface or smaller size quotation.
A block quotation (also known as a long quotation or extract) is a quotation in a written document, that is set off from the main text as a paragraph, or block of text, and typically distinguished visually using indentation and a different typeface or smaller size quotation.
A number of connected items or names written or printed consecutively, typically one below the other.
4 |
This is a term.
5 |
This is the definition of that term, which both live in a dl.
6 |
Here is another term.
7 |
And it gets a definition too, which is this line.
8 |
Here is term that shares a definition with the term below.
9 |
And it gets a definition too, which is this line.
10 |
--------------------------------------------------------------------------------
/patterns/atoms/forms/radio-buttons.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/contributing.md:
--------------------------------------------------------------------------------
1 | All contributions are welcome! If you like the project, _stars and tweets_ are a great way to show your support. If you want to take a more active role and help with documentation, writing unit tests, addressing issues or whatever seems interesting, please let us know, we'd be happy to help you get started!
2 |
3 | Also, we use [Verb](https://github.com/assemble/verb) for documentation, so don't edit the readme or other docs directly. Please edit the templates in the [docs directory](./docs) and then run `verb` to build them before you do a pull request. Thanks!
--------------------------------------------------------------------------------
/styles/scss/objects/_tabs.scss:
--------------------------------------------------------------------------------
1 | .tabs {
2 | overflow: hidden;
3 |
4 | ul {
5 | display: table;
6 | width: 100%;
7 | }
8 |
9 | li {
10 | display: table-cell;
11 | text-align: center;
12 | border-right: 1px solid $gray-light-3;
13 |
14 | &:last-child {
15 | border-right: 0;
16 | }
17 | }
18 |
19 | a {
20 | display: block;
21 | padding: $pad-half;
22 | background: $gray;
23 |
24 | &:hover, &:focus {
25 | background: $gray-light-3;
26 | }
27 |
28 | &.active {
29 | background: $gray-dark;
30 | color: $white;
31 | }
32 | }
33 | }
--------------------------------------------------------------------------------
/templates/includes/javascripts.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{> patternPaths }}
4 | {{> viewAllPaths }}
5 |
6 | {{> websockets }}
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/patterns/atoms/global/fonts.hbs:
--------------------------------------------------------------------------------
1 |
An unordered list is a list in which the sequence of items is not important. Sometimes, an unordered list is a bulleted list. And this is a long list item in an unordered list that can wrap onto a new line.
5 |
6 | Lists can be nested inside of each other
7 |
8 |
This is a nested list item
9 |
This is another nested list item in an unordered list
23 |
24 |
--------------------------------------------------------------------------------
/styles/scss/generic/_mixins.scss:
--------------------------------------------------------------------------------
1 | /*------------------------------------*\
2 | $MIXINS
3 | \*------------------------------------*/
4 |
5 | /* CSS Transition
6 | Usage: @include transition(width,0.3s,ease-out);
7 | */
8 | @mixin transition($transition-property, $transition-time, $method) {
9 | -webkit-transition: $transition-property $transition-time $method;
10 | -moz-transition: $transition-property $transition-time $method;
11 | -ms-transition: $transition-property $transition-time $method;
12 | -o-transition: $transition-property $transition-time $method;
13 | transition: $transition-property $transition-time $method;
14 | }
15 |
16 | /* Rem Unit font sizes with relative fallback http:/seesparkbox.com/foundry/scss_rem_mixin_now_with_a_better_fallback
17 | Usage: @include font-size(1, large);
18 | */
19 | @mixin font-size( $decimal-size, $keyword: null ) {
20 | @if $keyword{ font-size: $keyword; }
21 | @else { font-size: $decimal-size * $base-font-multiplier * 16px;}
22 | font-size: $decimal-size * 1rem;
23 | }
--------------------------------------------------------------------------------
/templates/layouts/default.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Pattern Lab Pattern
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | {{> body}}
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/patterns/atoms/forms/html5-inputs.hbs:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/usage.md:
--------------------------------------------------------------------------------
1 | The following patterns have been implements:
2 |
3 | * `atoms`: used in templates with `{{atoms "foo"}}`
4 | * `molecules`: used in templates with `{{molecules "foo"}}`
5 | * `organisms`: used in templates with `{{organisms "foo"}}`
6 | * `templates`: used in templates with `{{templates "foo"}}`
7 | * `pages`: Pages are specified using `src` property or `files` object/arrays in the Gruntfile config (see below)
8 |
9 | For any templates to actually be found during the build, you'll have to first tell Assemble where to find them in Gruntfile, like so:
10 |
11 | ```js
12 | assemble: {
13 | options: {
14 | // Pattern Lab templates
15 | patterns: {
16 | atoms: ['src/atoms/**/*.hbs'],
17 | molecules: ['src/molecules/**/*.hbs'],
18 | organisms: ['src/organisms/**/*.hbs'],
19 | templates: ['src/templates/**/*.hbs'],
20 | }
21 | },
22 | site: {
23 |
24 | // `pages` are defined here (you can use any of the Grunt files
25 | // patterns, e.g. src-dest, files object, files array, etc)
26 | files: {
27 | '_gh_pages/': ['src/pages/*.hbs']
28 | }
29 | }
30 | }
31 | ```
--------------------------------------------------------------------------------
/patterns/atoms/tables/table.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Table Heading 1
5 |
Table Heading 2
6 |
Table Heading 3
7 |
Table Heading 3
8 |
Table Heading 4
9 |
10 |
11 |
12 |
13 |
Table Footer 1
14 |
Table Footer 2
15 |
Table Footer 3
16 |
Table Footer 3
17 |
Table Footer 4
18 |
19 |
20 |
21 |
22 |
Table Cell 1
23 |
Table Cell 2
24 |
Table Cell 3
25 |
Table Cell 4
26 |
Table Cell 5
27 |
28 |
29 |
Table Cell 1
30 |
Table Cell 2
31 |
Table Cell 3
32 |
Table Cell 4
33 |
Table Cell 5
34 |
35 |
36 |
Table Cell 1
37 |
Table Cell 2
38 |
Table Cell 3
39 |
Table Cell 4
40 |
Table Cell 5
41 |
42 |
43 |
Table Cell 1
44 |
Table Cell 2
45 |
Table Cell 3
46 |
Table Cell 4
47 |
Table Cell 5
48 |
49 |
50 |
--------------------------------------------------------------------------------
/docs/overview.md:
--------------------------------------------------------------------------------
1 | This project uses [Assemble](https://github.com/assemble/assemble) to build projects with [pattern lab](http://pattern-lab.info/) conventions.
2 |
3 | Note that _this isn't 100% feature complete, and the focus was mostly on implementing the patterns - not the actual demo site_, but this project does implement the actual patterns, e.g. the important parts, and you can easily add (or [request](https://github.com/jonschlinkert/assemble-pattern-lab/issues)) any functionality you require.
4 |
5 | Also, there are a few differences in how this project handles templates. Instead of having to namespace partials, like `{{> organisms-latest-posts }}`, and then using a complex regex system for dynamically renaming these partials according to how they are organized in folders, here you can simply use `{{organism "latest-posts"}}`.
6 |
7 | This has several advantages:
8 |
9 | * Store your patterns wherever you want them, just tell Assemble where they are.
10 | * We're adhering to mustache/handlebars conventions instead of working around them.
11 | * We can easily extend and add new patterns, or allow metadata to be passed as context to templates and so on.
--------------------------------------------------------------------------------
/LICENSE-MIT:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-2014 Jon Schlinkert, Brian Woodward, Contributors.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/templates/_helpers/patterns.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Handlebars Helpers for Pattern Lab
3 | * Copyright (c) 2014 Jon Schlinkert
4 | * Licensed under the MIT License (MIT).
5 | */
6 | 'use strict';
7 |
8 | var path = require('path');
9 | var file = require('fs-utils');
10 | var _ = require('lodash');
11 |
12 |
13 | module.exports.register = function (Handlebars, options, params) {
14 | options = options || {};
15 | var config = _.extend(options, options.data || {});
16 |
17 | var patterns = ['atom', 'molecule', 'organism', 'template'];
18 |
19 | patterns.forEach(function(pattern) {
20 | var inflection = pattern + 's';
21 |
22 | file.expand(options.patterns[inflection]).map(function(filepath) {
23 | var name = pattern + '-' + file.base(filepath);
24 | var template = file.readFileSync(filepath);
25 | Handlebars.registerPartial(name, template);
26 | });
27 |
28 | Handlebars.registerHelper(pattern, function(name, context) {
29 | context = _.extend(config, this, context || {});
30 | var template = Handlebars.partials[pattern + '-' + name];
31 | var fn = Handlebars.compile(template);
32 | return new Handlebars.SafeString(fn(context));
33 | });
34 | });
35 | };
--------------------------------------------------------------------------------
/patterns/atoms/global/colors.hbs:
--------------------------------------------------------------------------------
1 |
49 |
--------------------------------------------------------------------------------
/styles/scss/objects/_blocks.scss:
--------------------------------------------------------------------------------
1 | /* Generic Placeholder Brick: REMOVE FOR PRODUCTION */
2 | .brick {
3 | background: #dcdddc;
4 | padding: $pad-double;
5 | text-align: center;
6 | font-weight: bold;
7 | border-bottom: 1px solid $gray-light-2;
8 | }
9 |
10 | /* Block */
11 | .block {
12 | overflow: hidden;
13 |
14 | p:last-child {
15 | margin-bottom: 0;
16 | }
17 | }
18 |
19 | .headline {
20 | line-height: 1.2;
21 | }
22 |
23 | /* Hero Block */
24 | .block-hero {
25 | margin-bottom: $space-half;
26 |
27 | .b-thumb {
28 | img {
29 | display: block;
30 | }
31 | }
32 |
33 | @media all and (min-width: $bp-large) {
34 | position: relative;
35 |
36 | .b-text {
37 | position: absolute;
38 | bottom: 0;
39 | left: 0;
40 | width: 100%;
41 | background: $dim;
42 | color: $white;
43 | padding: $pad-and-half;
44 | }
45 | }
46 | }
47 |
48 | /* Block Thumbnail with Headline */
49 | .block-thumb {
50 | display: table;
51 | width: 100%;
52 | border-collapse: collapse;
53 |
54 | .b-inner {
55 | display: table-row;
56 | vertical-align: top;
57 | overflow: hidden;
58 | }
59 |
60 | .b-thumb {
61 | @media all and (min-width: $bp-small-2) {
62 | display: table-cell;
63 | vertical-align: top;
64 | width: 30%;
65 | max-width: 10em;
66 |
67 | img {
68 | display: block;
69 | width: 100%;
70 | height: auto;
71 | }
72 | }
73 | }
74 |
75 | .b-text {
76 | @media all and (min-width: $bp-small-2) {
77 | display: table-cell;
78 | width: 70%;
79 | padding: 0 $pad;
80 | }
81 | }
82 | }
83 |
84 |
85 | /* Block Headline Summary */
86 | .block-headline-summary {
87 | a {
88 | display: block;
89 | padding: $pad-half;
90 | }
91 | }
92 |
93 | /* Block Inset */
94 | .block-inset {
95 | position: relative;
96 |
97 | .b-thumb {
98 | position: relative;
99 | z-index: 0;
100 |
101 | img {
102 | display: block;
103 | }
104 | }
105 | }
106 |
107 | /* Hero Block */
108 | .block-inset {
109 | margin-bottom: $space-half;
110 | position: relative;
111 |
112 | .headline {
113 | font-size: 1.1em;
114 | }
115 |
116 | .b-text {
117 | position: absolute;
118 | bottom: 0;
119 | left: 0;
120 | width: 100%;
121 | background: $dim;
122 | color: $white;
123 | padding: $pad-half;
124 | }
125 | }
126 |
127 | /* Block Thumb with Summary */
128 | .block-thumb-summary {
129 | .b-thumb {
130 | float: left;
131 | width: 50%;
132 | }
133 |
134 | .b-text {
135 | margin-left: 50%;
136 | padding: $pad-half;
137 | }
138 | }
--------------------------------------------------------------------------------
/styles/scss/style.scss:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | */
4 |
5 |
6 | /*------------------------------------*\
7 | $TABLE OF CONTENTS
8 | \*------------------------------------*/
9 | /**
10 | * VARIABLES..............................Declarations of Sass variables
11 | * .....Colors
12 | * .....Typography
13 | * .....Layout
14 | * .....Defaults
15 | * .....Breakpoints
16 | * MIXINS.................................Sass mixins
17 | * RESET..................................Set reset defaults
18 | * GLOBAL CLASSES.........................Set reset defaults
19 | * GLOBAL ELEMENTS........................Establish global styles
20 | * .....Main
21 | * .....Headings
22 | * .....Text-related elements (p, blockquote, lists)
23 | * .....Defaults
24 | * .....Breakpoints
25 | * TYPOGRAPHY------------------------------
26 | * MEDIA------------------------------
27 | * LAYOUT------------------------------
28 | * NAVIGATION------------------------------
29 | * TOC To Be Continued
30 | */
31 |
32 |
33 |
34 | @import "scss/generic/variables";
35 | @import "scss/generic/mixins";
36 | @import "scss/generic/reset";
37 |
38 |
39 |
40 |
41 |
42 | /*------------------------------------*\
43 | $GLOBAL ELEMENTS
44 | \*------------------------------------*/
45 | @import "scss/base/global-classes";
46 | @import "scss/base/main";
47 | @import "scss/base/links";
48 | @import "scss/base/headings";
49 | @import "scss/base/text";
50 | @import "scss/base/lists";
51 | @import "scss/base/media";
52 | @import "scss/base/forms";
53 | @import "scss/base/tables";
54 | @import "scss/base/animation";
55 |
56 |
57 |
58 |
59 |
60 | /*------------------------------------*\
61 | $LAYOUT
62 | \*------------------------------------*/
63 | @import "scss/objects/layout";
64 |
65 |
66 | /*------------------------------------*\
67 | $PAGE STRUCTURE
68 | \*------------------------------------*/
69 | @import "scss/objects/header";
70 | @import "scss/objects/nav";
71 | @import "scss/objects/main";
72 | @import "scss/objects/footer";
73 |
74 |
75 |
76 | /*------------------------------------*\
77 | $TEXT Styles
78 | \*------------------------------------*/
79 | @import "scss/objects/text";
80 |
81 |
82 | /*------------------------------------*\
83 | $COMPONENTS
84 | \*------------------------------------*/
85 | @import "scss/objects/icons";
86 | @import "scss/objects/buttons";
87 | @import "scss/objects/blocks";
88 | @import "scss/objects/lists";
89 | @import "scss/objects/tooltip";
90 | @import "scss/objects/accordion";
91 | @import "scss/objects/tabs";
92 | @import "scss/objects/sections";
93 | @import "scss/objects/article";
94 | @import "scss/objects/comments";
95 |
96 |
97 |
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | /*
2 | * assemble-pattern-lab
3 | *
4 | * Copyright (c) 2014 Jon Schlinkert, Brian Woodward, contributors.
5 | * Licensed under the MIT license.
6 | */
7 |
8 |
9 | module.exports = function(grunt) {
10 |
11 | 'use strict';
12 |
13 | // Project configuration.
14 | grunt.initConfig({
15 |
16 | // Project metadata
17 | pkg: grunt.file.readJSON('package.json'),
18 |
19 | // <%= site %> metadata comes from this file
20 | site: grunt.file.readYAML('.assemble.yml'),
21 |
22 | assemble: {
23 | options: {
24 | flatten: true,
25 | assets: '<%= site.assets %>',
26 |
27 | // Metadata
28 | pkg: '<%= pkg %>',
29 | site: '<%= site %>',
30 | data: ['<%= site.data %>/**/*.json'],
31 | helpers: ['<%= site.helpers %>/*.js'],
32 | plugins: '<%= site.plugins %>',
33 |
34 | // General templates
35 | partials: ['<%= site.includes %>/**/*.hbs'],
36 | layouts: '<%= site.layouts %>',
37 | layoutext: '<%= site.layoutext %>',
38 | layout: '<%= site.layout %>',
39 |
40 | // Pattern Lab templates
41 | patterns: {
42 | atoms: ['<%= site.atoms %>/**/*.hbs'],
43 | molecules: ['<%= site.molecules %>/**/*.hbs'],
44 | organisms: ['<%= site.organisms %>/**/*.hbs'],
45 | templates: ['<%= site.templates %>/**/*.hbs'],
46 | }
47 | },
48 |
49 | // 'pages' are specified in the src
50 | site: {
51 | src: ['<%= site.pages %>/*.hbs', 'src/*.hbs'],
52 | dest: '<%= site.dest %>/'
53 | },
54 |
55 | patterns: {
56 | options: {
57 | permalinks: {
58 | preset: 'pretty',
59 | structure: ':pattern-:group',
60 | patterns: [
61 | {
62 | pattern: /:pattern/,
63 | replacement: function(src) {
64 | return this.src.split('/')[1];
65 | }
66 | },
67 | {
68 | pattern: /:group/,
69 | replacement: function(src) {
70 | return this.src.split('/')[2];
71 | }
72 | }
73 | ]
74 | }
75 | },
76 | src: ['<%= site.patterns %>/**/*.hbs'],
77 | dest: '<%= site.dest %>/patterns/'
78 | }
79 | },
80 |
81 | clean: {
82 | examples: ['<%= assemble.examples.dest %>/**']
83 | }
84 | });
85 |
86 | // Load Assemble
87 | grunt.task.loadNpmTasks('assemble');
88 |
89 | // The default task to run with the `grunt` command
90 | grunt.registerTask('default', ['assemble']);
91 | };
--------------------------------------------------------------------------------
/data/data.json:
--------------------------------------------------------------------------------
1 | {
2 | "img": {
3 | "landscape-4x3": {
4 | "src": "images/fpo_4x3.png",
5 | "alt": "4x3 Image"
6 | },
7 | "landscape-16x9": {
8 | "src": "images/fpo_16x9.png",
9 | "alt": "16x9 Image"
10 | },
11 | "square": {
12 | "src": "images/fpo_square.png",
13 | "alt": "Square Thumbnail"
14 | },
15 | "avatar": {
16 | "src": "images/fpo_avatar.png",
17 | "alt": "Person Name"
18 | }
19 | },
20 | "headline": {
21 | "short": "Lorem ipsum dolor sit (37 characters)",
22 | "medium": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. (72 characters)"
23 | },
24 | "excerpt": {
25 | "short": "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam",
26 | "medium": "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.",
27 | "long": "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."
28 | },
29 | "description": "So, setting about it as methodically as men might smoke out a wasps' nest, the Martians spread this strange stifling vapour over the Londonward country. The horns of the crescent slowly moved apart, until at last they formed a line from Hanwell to Coombe and Malden. All night through their destructive tubes advanced.",
30 | "url": "http://www.fillerati.com",
31 | "name": {
32 | "first": "Lacy",
33 | "firsti": "L",
34 | "middle": "Tommie",
35 | "middlei": "T",
36 | "last": "Way",
37 | "lasti": "W"
38 | },
39 | "year": {
40 | "long": "2013",
41 | "short": "13"
42 | },
43 | "month": {
44 | "long": "February",
45 | "short": "Feb",
46 | "digit": "02"
47 | },
48 | "dayofweek": {
49 | "long": "Monday",
50 | "short": "Mon"
51 | },
52 | "day": {
53 | "long": "10",
54 | "short": "10",
55 | "ordinal": "th"
56 | },
57 | "hour": {
58 | "long": "01",
59 | "short": "1",
60 | "military": "13",
61 | "ampm": "pm"
62 | },
63 | "minute": {
64 | "long": "20",
65 | "short": "20"
66 | },
67 | "seconds": "31",
68 | "author": {
69 | "first-name": "Author",
70 | "last-name": "Name"
71 | }
72 | }
--------------------------------------------------------------------------------
/styles/scss/base/_forms.scss:
--------------------------------------------------------------------------------
1 | /*------------------------------------*\
2 | $FORMS
3 | \*------------------------------------*/
4 |
5 | form > div {
6 | margin-bottom: $space;
7 | }
8 |
9 | form ol, form ul {
10 | list-style: none;
11 | margin-left: 0;
12 | }
13 |
14 | fieldset {
15 | border: 0;
16 | padding: 0;
17 | margin: 0;
18 | }
19 |
20 | label {
21 | display: block;
22 | padding-bottom: $space-quarter;
23 | }
24 |
25 | button, input, select, textarea {
26 | font-family: inherit;
27 | font-size: 100%;
28 | margin: 0;
29 | }
30 |
31 | input, textarea {
32 | width: 100%;
33 | border: 1px solid $gray;
34 | padding: $pad-half 0.65rem;
35 | }
36 |
37 | input[type=text], input[type=search], input[type=url], input[type=number], textarea {
38 | -webkit-appearance: none;
39 | }
40 |
41 | button, input[type="submit"] {
42 | padding: $pad-half;
43 | background: $gray-dark;
44 | border: 1px solid $gray;
45 | cursor: pointer;
46 | }
47 |
48 | input[type="checkbox"],
49 | input[type="radio"] {
50 | width: auto;
51 | margin-right: 0.3em;
52 | }
53 |
54 | input[type="search"] {
55 | -webkit-appearance: none;
56 | border-radius: 0;
57 | }
58 |
59 | input[type="search"]::-webkit-search-cancel-button,
60 | input[type="search"]::-webkit-search-decoration {
61 | -webkit-appearance: none;
62 | }
63 |
64 | //Form Field Container
65 | .field-container {
66 | margin-bottom: $space;
67 | }
68 |
69 | .inline-form {
70 |
71 | fieldset, .inline-container {
72 | position: relative;
73 | }
74 |
75 | input[type=submit], button, .btn {
76 | font-size: $font-size-slightly-smaller;
77 | padding: 0.65rem 1.3rem;
78 | background: $gray-dark;
79 | position: absolute;
80 | top: 0;
81 | right: 0;
82 | z-index: 1;
83 | width: auto;
84 |
85 | &:hover, &:focus {
86 | background: $gray;
87 | color: $white;
88 | }
89 | }
90 | }
91 |
92 | // PK to clean this up
93 | .inline-search-results-form {
94 | width: 100%;
95 | @media all and (min-width: $bp-med) {
96 | width: 82%;
97 |
98 | }
99 |
100 | fieldset, .inline-container {
101 | position: relative;
102 | }
103 |
104 | input[type=submit], button {
105 | position: absolute;
106 | top: 0;
107 | right: 0;
108 | z-index: 1;
109 | width: auto;
110 | }
111 | }
112 |
113 | /* Validation */
114 | .has-error {
115 | border-color: $error;
116 | }
117 | .is-valid {
118 | border-color: $valid;
119 | }
120 |
121 |
122 |
123 |
124 | /*------------------------------------*\
125 | $SPECIFIC FORMS
126 | \*------------------------------------*/
127 |
128 | /* Search Form */
129 | .search-field {
130 | padding-right: 3em;
131 | }
132 | .inline-form .search-submit {
133 | background: none;
134 | padding: 0.78em 1em;
135 | border: 0;
136 | border-left: 1px solid $gray;
137 | color: $gray;
138 | }
--------------------------------------------------------------------------------
/data/blog.json:
--------------------------------------------------------------------------------
1 | {
2 | "latest-posts": [
3 | {
4 | "img": {
5 | "square": {
6 | "src": "images/sample/thumb-square-river.jpg",
7 | "alt": "Post Thumbnail"
8 | }
9 | },
10 | "headline": {
11 | "short": "Navigate the Allegheny River"
12 | },
13 | "exerpt": {
14 | "medium": "The Allegheny River is a principal tributary of the Ohio River; it is located in the Eastern United States. The Allegheny River joins with the Monongahela River to form the Ohio River at the Point of Point State Park in Downtown Pittsburgh, Pennsylvania."
15 | }
16 | },
17 | {
18 | "img": {
19 | "square": {
20 | "src": "images/sample/thumb-square-ivy.jpg",
21 | "alt": "Ivy"
22 | }
23 | },
24 | "headline": {
25 | "short": "How to detect and avoid poison ivy"
26 | },
27 | "exerpt": {
28 | "medium": "Toxicodendron radicans, commonly known as poison ivy is a poisonous North American plant that is well known for its production of urushiol"
29 | }
30 | },
31 | {
32 | "img": {
33 | "square": {
34 | "src": "images/sample/thumb-square-yosemite.jpg",
35 | "alt": "Yosemite"
36 | }
37 | },
38 | "headline": {
39 | "short": "Top 10 hiking mountains"
40 | },
41 | "exerpt": {
42 | "medium": "Yosemite National Park is a United States National Park spanning eastern portions of Tuolumne, Mariposa and Madera counties in the central eastern portion of the U.S. state of California."
43 | }
44 | },
45 | {
46 | "img": {
47 | "square": {
48 | "src": "images/sample/thumb-square-fire.jpg",
49 | "alt": "Fire"
50 | }
51 | },
52 | "headline": {
53 | "short": "How to build a campfire"
54 | },
55 | "exerpt": {
56 | "medium": "A campfire is a fire lit at a campsite, to serve the following functions: light, warmth, a beacon, an insect and/or apex predator deterrent, to cook, and for a psychological sense of security. "
57 | }
58 | },
59 | {
60 | "img": {
61 | "square": {
62 | "src": "images/sample/thumb-square-gear.jpg",
63 | "alt": "Camping Gear"
64 | }
65 | },
66 | "headline": {
67 | "short": "Pick the right camping gear"
68 | },
69 | "exerpt": {
70 | "medium": "The equipment used in camping varies with the particular type of camping. For instance, in survival camping the equipment consists of small items which have the purpose of helping the camper in providing food, heat and safety."
71 | }
72 | }
73 | ],
74 | "inset-blocks": [
75 | {
76 | "headline": "This is the headline for the inset block"
77 | }
78 | ],
79 | "latest-block": [
80 | {
81 | "headline": "This is the headline for the latest block"
82 | }
83 | ]
84 | }
--------------------------------------------------------------------------------
/assets/js/styleguide/postmessage.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Basic postMessage Support - v0.1
3 | *
4 | * Copyright (c) 2013 Dave Olsen, http://dmolsen.com
5 | * Licensed under the MIT license
6 | *
7 | * Handles the postMessage stuff in the pattern, view-all, and style guide templates.
8 | *
9 | */
10 |
11 | // alert the iframe parent that the pattern has loaded assuming this view was loaded in an iframe
12 | if (self != top) {
13 |
14 | // handle the options that could be sent to the parent window
15 | // - all get path
16 | // - pattern & view all get a pattern partial, styleguide gets all
17 | // - pattern shares lineage
18 | var options = { "path": window.location.toString() };
19 | options.patternpartial = (patternPartial != "") ? patternPartial : "all";
20 | if (lineage != "") {
21 | options.lineage = lineage;
22 | }
23 |
24 | var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host;
25 | parent.postMessage(options, targetOrigin);
26 |
27 | // find all links and add an onclick handler for replacing the iframe address so the history works
28 | var aTags = document.getElementsByTagName('a');
29 | for (a in aTags) {
30 | aTags[a].onclick = function(e) {
31 | e.preventDefault();
32 | window.location.replace(this.getAttribute("href"));
33 | };
34 | }
35 |
36 | }
37 |
38 | // if there are clicks on the iframe make sure the nav in the iframe parent closes
39 | var body = document.getElementsByTagName('body');
40 | body[0].onclick = function() {
41 | var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host;
42 | parent.postMessage( { "bodyclick": "bodyclick" }, targetOrigin)
43 | };
44 |
45 | // watch the iframe source so that it can be sent back to everyone else.
46 | function receiveIframeMessage(event) {
47 |
48 | // does the origin sending the message match the current host? if not dev/null the request
49 | if ((window.location.protocol != "file:") && (event.origin !== window.location.protocol+"//"+window.location.host)) {
50 | return;
51 | }
52 |
53 | // see if it got a path to replace
54 | if (event.data.path != undefined) {
55 |
56 | if (patternPartial != "") {
57 |
58 | // handle patterns and the view all page
59 | var re = /patterns\/(.*)$/;
60 | var path = window.location.protocol+"//"+window.location.host+window.location.pathname.replace(re,'')+event.data.path;
61 | window.location.replace(path);
62 |
63 | } else {
64 |
65 | // handle the style guide
66 | var path = window.location.protocol+"//"+window.location.host+window.location.pathname.replace("styleguide\/html\/styleguide.html","")+event.data.path;
67 | window.location.replace(path);
68 |
69 | }
70 |
71 | } else if (event.data.reload != undefined) {
72 |
73 | // reload the location if there was a message to do so
74 | window.location.reload();
75 | }
76 |
77 | }
78 | window.addEventListener("message", receiveIframeMessage, false);
79 |
--------------------------------------------------------------------------------
/assets/js/fitvids.js:
--------------------------------------------------------------------------------
1 | /*global jQuery */
2 | /*!
3 | * FitVids 1.0
4 | *
5 | * Copyright 2011, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com
6 | * Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/
7 | * Released under the WTFPL license - http://sam.zoy.org/wtfpl/
8 | *
9 | * Date: Thu Sept 01 18:00:00 2011 -0500
10 | */
11 |
12 | (function( $ ){
13 |
14 | $.fn.fitVids = function( options ) {
15 | var settings = {
16 | customSelector: null
17 | }
18 |
19 | var div = document.createElement('div'),
20 | ref = document.getElementsByTagName('base')[0] || document.getElementsByTagName('script')[0];
21 |
22 | div.className = 'fit-vids-style';
23 | div.innerHTML = '';
40 |
41 | ref.parentNode.insertBefore(div,ref);
42 |
43 | if ( options ) {
44 | $.extend( settings, options );
45 | }
46 |
47 | return this.each(function(){
48 | var selectors = [
49 | "iframe[src*='player.vimeo.com']",
50 | "iframe[src*='www.youtube.com']",
51 | "iframe[src*='www.kickstarter.com']",
52 | "object",
53 | "embed"
54 | ];
55 |
56 | if (settings.customSelector) {
57 | selectors.push(settings.customSelector);
58 | }
59 |
60 | var $allVideos = $(this).find(selectors.join(','));
61 |
62 | $allVideos.each(function(){
63 | var $this = $(this);
64 | if (this.tagName.toLowerCase() == 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; }
65 | var height = ( this.tagName.toLowerCase() == 'object' || $this.attr('height') ) ? $this.attr('height') : $this.height(),
66 | width = $this.attr('width') ? $this.attr('width') : $this.width(),
67 | aspectRatio = height / width;
68 | if(!$this.attr('id')){
69 | var videoID = 'fitvid' + Math.floor(Math.random()*999999);
70 | $this.attr('id', videoID);
71 | }
72 | $this.wrap('').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+"%");
73 | $this.removeAttr('height').removeAttr('width');
74 | });
75 | });
76 | }
77 | })( jQuery );
--------------------------------------------------------------------------------
/assets/js/styleguide/code-pattern.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Code View Support for Patterns - v0.3
3 | *
4 | * Copyright (c) 2013 Dave Olsen, http://dmolsen.com
5 | * Licensed under the MIT license
6 | *
7 | */
8 |
9 | var codePattern = {
10 |
11 | codeOverlayActive: false,
12 | codeEmbeddedActive: false,
13 |
14 | /**
15 | * toggle the annotation feature on/off
16 | * based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage
17 | * @param {Object} event info
18 | */
19 | receiveIframeMessage: function(event) {
20 |
21 | // does the origin sending the message match the current host? if not dev/null the request
22 | if ((window.location.protocol != "file:") && (event.origin !== window.location.protocol+"//"+window.location.host)) {
23 | return;
24 | }
25 |
26 | if (event.data.codeToggle != undefined) {
27 |
28 | // if this is an overlay make sure it's active for the onclick event
29 | codePattern.codeOverlayActive = false;
30 | codePattern.codeEmbeddedActive = false;
31 |
32 | // see which flag to toggle based on if this is a styleguide or view-all page
33 | var body = document.getElementsByTagName("body");
34 | if ((event.data.codeToggle == "on") && (body[0].classList.contains("sg-pattern-list"))) {
35 | codePattern.codeEmbeddedActive = true;
36 | } else if (event.data.codeToggle == "on") {
37 | codePattern.codeOverlayActive = true;
38 | }
39 |
40 | // if comments embedding is turned off make sure to hide the annotations div
41 | if (!codePattern.codeEmbeddedActive && (body[0].classList.contains("sg-pattern-list"))) {
42 | var els = document.getElementsByClassName("sg-code");
43 | for (var i = 0; i < els.length; i++) {
44 | els[i].style.display = "none";
45 | }
46 | }
47 |
48 | // if comments overlay is turned on add the has-comment class and pointer
49 | if (codePattern.codeOverlayActive) {
50 |
51 | var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host;
52 | obj = { "codeOverlay": "on", "lineage": lineage, "html": document.getElementById("sg-pattern-html").textContent, "css": document.getElementById("sg-pattern-css").textContent };
53 | parent.postMessage(obj,targetOrigin);
54 |
55 | } else if (codePattern.codeEmbeddedActive) {
56 |
57 | // if code embedding is turned on simply display them
58 | var els = document.getElementsByClassName("sg-code");
59 | for (var i = 0; i < els.length; ++i) {
60 | els[i].style.display = "block";
61 | }
62 |
63 | }
64 |
65 | }
66 |
67 | }
68 |
69 | };
70 |
71 | // add the onclick handlers to the elements that have an annotations
72 | window.addEventListener("message", codePattern.receiveIframeMessage, false);
73 |
74 | // before unloading the iframe make sure any active overlay is turned off/closed
75 | window.onbeforeunload = function() {
76 | var obj = { "codeOverlay": "off" };
77 | var targetOrigin = (window.location.protocol == "file:") ? "*" : window.location.protocol+"//"+window.location.host;
78 | parent.postMessage(obj,targetOrigin);
79 | };
--------------------------------------------------------------------------------
/patterns/organisms/article/article-body.hbs:
--------------------------------------------------------------------------------
1 |
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer fringilla sem a urna porttitor fringilla. Nulla eget justo felis.
2 |
3 |
Aliquam erat volutpat. Mauris vulputate scelerisque feugiat. Cras a erat a diam venenatis aliquam. Sed tempus, purus ac pretium varius, risus orci sagittis purus, quis auctor libero magna nec magna. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Maecenas eros dolor, rutrum eu sollicitudin eu, commodo at leo. Suspendisse potenti. Sed eu nibh sit amet quam auctor feugiat vel et risus. Maecenas eu urna adipiscing neque dictum mollis suscipit in augue. Praesent pulvinar condimentum sagittis. Maecenas laoreet neque non eros consectetur fringilla. Donec vitae risus leo, vitae pharetra ipsum. Sed placerat eros eget elit iaculis semper. Aliquam congue blandit orci ac pretium.
4 |
5 | {{ atom 'landscape-16x9' }}
6 |
7 |
Aliquam ultrices cursus mauris, eget volutpat justo mattis nec. Sed a orci turpis. Aliquam aliquet placerat dui, consectetur tincidunt leo tristique et. Vivamus enim nisi, blandit a venenatis quis, convallis et arcu. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris libero sapien, placerat in sodales eu, tempor quis dui. Vivamus egestas faucibus pulvinar. Maecenas eget diam nunc. Phasellus at sem eros, ac suscipit neque. Phasellus sollicitudin libero a odio dignissim scelerisque. Aliquam purus nulla, tempor eget ullamcorper quis, rhoncus non dui.
8 |
9 |
10 | {{ atom 'blockquote' }}
11 |
12 |
Cras at fringilla ipsum. Donec nec libero eget est blandit dignissim a eu ante. Morbi augue nulla, luctus eu sagittis vel, malesuada ut felis. Aliquam erat volutpat. Morbi malesuada augue ac massa hendrerit fermentum. Integer scelerisque lacus a dolor convallis lobortis. Curabitur mollis ante in massa ultricies dignissim.
13 |
14 |
15 | {{ atom 'unordered' }}
16 |
17 | {{ atom 'ordered' }}
18 |
19 |
Donec posuere fringilla nunc, vitae venenatis diam scelerisque vel. Nullam vitae mauris magna. Mauris et diam quis justo volutpat tincidunt congue nec magna. Curabitur vitae orci elit. Ut mollis massa id magna vestibulum consequat. Proin rutrum lectus justo, sit amet tincidunt est. Vivamus vitae lacinia risus.
20 |
21 |
22 | {{ molecule 'pullquote' }}
23 |
24 |
Donec venenatis imperdiet tortor, vitae blandit odio interdum ut. Integer orci metus, lobortis id lacinia eget, rutrum vitae justo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In pretium fermentum justo nec pharetra. Maecenas eget dapibus justo. Ut quis est risus. Nullam et eros at odio commodo venenatis quis et augue. Sed sed augue at tortor porttitor hendrerit nec ut nibh. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Proin sollicitudin enim consectetur mi commodo quis cursus ante pretium. Nunc gravida cursus nisi in gravida. Suspendisse eget tortor sed urna consequat tincidunt. Etiam eget convallis lectus. Suspendisse cursus rutrum massa ac faucibus.
25 |
26 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reiciendis, suscipit repellendus nulla accusantium deserunt sed explicabo voluptate sapiente ratione inventore molestiae nihil earum repellat quia odit vitae perspiciatis aliquam amet?
This is where a post about hiking trails would live. I'm not going to write an article about hiking trails. That would take a lot of time.
12 |
13 |
This is a link, possibly to an external resource. In a post about hiking trails, there would probably be talk about how to get to featured trails, what to pack, where to camp, and so on and so forth. I don't have any expertise in this subject matter so I'm not going to attempt to write about it.
14 |
15 | {{ atom 'landscape-16x9' }}
16 |
17 |
If I were to write about it, I'd probably do some research on the topic first. But even then, I probably Sed a orci turpis. Aliquam aliquet placerat dui, consectetur tincidunt leo tristique et. Vivamus enim nisi, blandit a venenatis quis, convallis et arcu. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris libero sapien, placerat in sodales eu, tempor quis dui. Vivamus egestas faucibus pulvinar. Maecenas eget diam nunc. Phasellus at sem eros, ac suscipit neque. Phasellus sollicitudin libero a odio dignissim scelerisque. Aliquam purus nulla, tempor eget ullamcorper quis, rhoncus non dui.
18 |
19 |
20 |
21 | This trail is amazing. I've never seen anything like it.
22 |
23 |
24 |
Cras at fringilla ipsum. Donec nec libero eget est blandit dignissim a eu ante. Morbi augue nulla, luctus eu sagittis vel, malesuada ut felis. Aliquam erat volutpat. Morbi malesuada augue ac massa hendrerit fermentum. Integer scelerisque lacus a dolor convallis lobortis. Curabitur mollis ante in massa ultricies dignissim.
25 |
26 |
27 | {{ atom 'unordered' }}
28 |
29 | {{ atom 'ordered' }}
30 |
31 |
Donec posuere fringilla nunc, vitae venenatis diam scelerisque vel. Nullam vitae mauris magna. Mauris et diam quis justo volutpat tincidunt congue nec magna. Curabitur vitae orci elit. Ut mollis massa id magna vestibulum consequat. Proin rutrum lectus justo, sit amet tincidunt est. Vivamus vitae lacinia risus.
32 |
33 |
34 | {{ molecule 'pullquote' }}
35 |
36 |
Donec venenatis imperdiet tortor, vitae blandit odio interdum ut. Integer orci metus, lobortis id lacinia eget, rutrum vitae justo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In pretium fermentum justo nec pharetra. Maecenas eget dapibus justo. Ut quis est risus. Nullam et eros at odio commodo venenatis quis et augue. Sed sed augue at tortor porttitor hendrerit nec ut nibh. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Proin sollicitudin enim consectetur mi commodo quis cursus ante pretium. Nunc gravida cursus nisi in gravida. Suspendisse eget tortor sed urna consequat tincidunt. Etiam eget convallis lectus. Suspendisse cursus rutrum massa ac faucibus.
37 |
38 |
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Reiciendis, suscipit repellendus nulla accusantium deserunt sed explicabo voluptate sapiente ratione inventore molestiae nihil earum repellat quia odit vitae perspiciatis aliquam amet?
Navigation for adaptive web experiences can be tricky. Top navigations are typical on desktop sites, but mobile screen sizes don't give us the luxury of space. We're dealing with this situation by creating a simple menu anchor that toggles the main navigation on small screens. This is just one method. Bagcheck and Contents Magazine add an anchor in the header that jumps users to the navigation which is placed in the footer. This solution works well because it doesn't require any Javascript in order to work. Other methods exist too. For example, ESPN's mobile navigation overlays the main content of the page.
The nav is only hidden when a certain level of javascript is supported in order to ensure that users with little/poor javascript support can still access the navigation. Once the screen size is large enough to accommodate the nav, we show the main navigation links and hide the menu anchor.
Search is an incredibly important priority, especially for mobile. It is a great idea to give users the ability to jump directly to what they are looking for without forcing them to wade through your site's navigation. Check out the Burton and Yelp mobile sites for great examples of experiences that prioritize search.
We're also using the HTML5 search input type, which is great for mobile devices that can bring up the appropriate virtual keyboard for many smartphones. And like the main header navigation, we're hiding the search form on small screens to save space. Clicking the search anchor toggles the form.
Instead of providing bullets, pagination or text-based image navigation, it's good e-commerce practice to show a preview of the various product views. By default the images simply link through to their larger counterparts, and if adequate javascript support exists, the images get loaded into the main image container.
The product image is the focal point of the page for good reason. It's typically what the user is there to see. The default markup simply includes the main product image, but that gets replaced with an image gallery if adequate javascript support exists.
We're also using Modernizr to detect if the browser supports touch events and if it does, we load in an excellent lightweight script called Swipe.js to create a touch-friendly image carousel. This allows users to swipe between product photos in a touch-friendly way. Because gestures are invisible, they might get overlooked, but clicking on the image navigation thumbnails animates the slideshow and hints to the user gestural interaction is available.
"
32 | },
33 | {
34 | "el": ".product-main header",
35 | "title" : "Product Overview",
36 | "comment": "The product overview appears in the markup before the image container in order to provide the user with the product name, how much it costs and how popular it is. Providing this information as soon as possible can help the user determine whether or not this is the product they're looking for without having to wait for the rest of the page to load."
37 | },
38 | {
39 | "el": ".star",
40 | "title" : "Rating Stars",
41 | "comment": "
We're using HTML special characters to display the product rating stars. We're using HTML characters instead of images to reduce the amount of images we're requesting and also maintaining crispness on high resolution screens. Not every device supports HTML special characters (Blackberry <=5.0 for example), but support is strong enough and the benefits are many.
"
42 | },
43 | {
44 | "el": ".review-count",
45 | "title" : "Review Count",
46 | "comment": "This is a simple anchor link that points to the review section of the page. This may seem like a small detail, but consider a mobile use case. Users can be in stores looking at the physical product, and 79% of smartphone consumers use their phones to help with shopping. They might be interested in buying in-store but turn to their phones to verify its popularity and quality. Making it easy for uses to read product reviews on small screens can help drive more sales, both online and offline.
While not incorporated yet, it would be easy to load the reviews for small screens on demand, thereby saving a step.
"
47 | },
48 | {
49 | "el": ".qty-field",
50 | "title" : "Quantity Field",
51 | "comment": "We're using the HTML5 number input type, which brings up the appropriate virtual keyboard for many mobile browsers. To increase usability, the input labels are using the \"for\" attribute, which focuses the cursor in the form field when clicked. However, iOS doesn't honor \"for\" default functionality, so we're adding \"cursor: pointer\" to the labels to get Mobile Safari to behave properly."
52 | },
53 | {
54 | "el": ".size-field",
55 | "title" : "Size Dropdown",
56 | "comment": "We're using a basic select menu to choose the size, which is commonplace for any e-commerce site. Select menus can be especially difficult to style and can vary greatly in behavior between platforms. Keep this in mind when creating "
57 | },
58 | {
59 | "el": ".submit-form",
60 | "title" : "Add to Cart button",
61 | "comment": "The add to cart button is the primary user action on the page. That's why it's large and in charge and very prominently placed on the page. The button is using box-shadows and rounded corners to create an attractive button that will hopefully get plenty of clicks."
62 | },
63 | {
64 | "el": ".share-btn",
65 | "title" : "Share button",
66 | "comment": "It seems like everything has a share button on it these days. And for good reason. Sharing content and products on social networks can be a great way to increase exposure. However, tacking on tons of social widgets adds a lot of overhead, which can be extremely detrimental to the site's performance. Including a simple share link that loads the heavy widgets only when requested is one way to keep pages fast and social. Check out Target's mobile site for an example of a site that isolates share functionality in a separate page fragment."
67 | },
68 | {
69 | "el": ".find-nearby",
70 | "title" : "Geolocation",
71 | "comment": "One of the most important aspects of the mobile context is location. We carry our mobile devices with us everywhere. Using geolocation we can tap into the user's location to deliver an enhanced experience. In this case we're giving them a chance to check out what stores nearby might sell this product. The geolocation API is well supported in mobile browsers as well as desktop browsers. We're using Modernizr to detect for geolocation support and if its support, we ask the user for their latitude and longitude. If the browser does not support geolocation, the default experience could take the user to a simple web form asking for a ZIP code. Check out Tiffany's mobile site store locator for an example of geolocation in action."
72 | },
73 | {
74 | "el": "#p-desc",
75 | "title" : "Product Description",
76 | "comment": "A product description is an essential part of any e-commerce experience. Descriptions offer tangible details that inform and persuade, and the tone can help support the physical product. Provide relevant information clearly and concisely. Check out the Android design guide for some tips on how to keep copy short and extremely effective."
77 | },
78 | {
79 | "el": "#related-products",
80 | "title" : "Related Products",
81 | "comment": "
Related products are obviously an important aspect of e-commerce sites as they drive awareness of other similar products and can lead to more purchases. However, including a lot of auxiliary content can bog down the site performance, which is especially crucial on mobile. On slow connections, the presence of this extra content might slow down the user experience enough that the user gives up.
By default, the related item link simply clicks through to an HTML fragment containing the related products. The content is still accessible, even on devices with poor or no javascript support. When the user clicks on the related products on small screens, the content gets dynamically loaded inline and the link becomes a toggler for the content. Once the experience reaches a certain width breakpoint, we then load in the content. However, screen size != fast connection, so we should keep our eyes on the emerging navigator.connection to better gauge real connection speed.
All these wonderful t-shirts are retired/rejected Busted Tees, graciously donated to this demo by Will Schneider.
"
82 | },
83 | {
84 | "el": "#reviews",
85 | "title" : "Reviews",
86 | "comment": "Reviews are incredibly influential on a user's decision to purchase a product or pass on it. Also, because we carry our mobile phones with us everywhere, we use them to inform our in-store purchased. 70% of smartphone owners use them while in brick and mortar stores, and often times they're looking for reviews to give them the green light to buy.
Only the primary product content gets loaded by default, and the reviews exist as their own separate HTML fragment. The reviews remain accessible and don't get loaded until we conditionally load them when the screen is large enough or small screen users click the reviews link. This keeps things nimble while still providing access to the valuable reviews.
All reviews aren't loaded by default in order to keep the site performance in top shape. Ultimately, this button could be replaced with a lazy-loading solution to remove the need for the button.
Repetition of elements isn't a bad thing, especially with potentially long scrolling pages on mobile. Providing access to the main site navigation is a good way for the user to jump off to another section and avoids leaving them with a dead end. Also, some mobile sites like Bagcheck and Contents Magazine keep the primary navigation at the footer and simply link to it with an anchor in the header. That way the nav stays accessible but the focus stays on on the core page content.
We sometimes forget that mobile phones can make phone calls. Whether a user is having trouble with the site or simply has some questions about the product he's about to buy, it's a smart decision to provide a clickable phone number to facilitate that call. What happens when desktops and other non-phone devices click on the tel link? Well, some devices (like iPads and other tablets) ask the user if they'd like to add the number to their contact list, other desktops open 3rd party VoIP programs like Skype, and others simply give an error message.
Back to top links are simple yet underrated. They provide users with an easy way back up to the top of the page with minimum effort. This is especially helpful on mobile devices, which tend to have long scrolling pages.
We're using an HTML character for the back to top arrow in order to reduce image elements and keep things looking crisp on high res displays.
{{name.first}} {{name.last}}
5 |