Skip to content
79 changes: 79 additions & 0 deletions pattern-library/source/sass/06-examples/00-page.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,85 @@
padding: size(2) size(1);
}

/**
* A wider shell for an example that has to show two things beside each
* other, such as what a reader typed and what came back.
*
* 800px is a comfortable measure for reading a column of prose, which is
* what most examples are. It is far too narrow once a page puts two
* columns or a table of controls inside it, because the columns then
* halve it and every control in them collapses and truncates.
*
* Everything inside takes the full width. Prose that would otherwise run
* to an unreadable measure goes in c-eg-intro or c-eg-columns below,
* which divide the width into readable columns rather than leaving half
* the page empty.
*/
.c-eg-page--wide {
max-width: 1400px;
}

/**
* The notes an example opens with, laid across the width rather than
* stacked down the left of it.
*
* A wide page fits three columns of prose beside each other, so what an
* example has to say before it starts takes one band and the example
* itself is on screen without scrolling. Each column keeps a readable
* measure because the columns divide the width, rather than one
* paragraph stretching across all of it.
*/
.c-eg-intro {
display: grid;
grid-template-columns: 1fr;
gap: 0 size(2);
margin-bottom: size(2);

@include respond-to(md) {
grid-template-columns: 1fr 1fr;
}

@include respond-to(xl) {
grid-template-columns: repeat(3, 1fr);
}

> p {
margin-top: 0;
}
}

/**
* The head of an example, being the logo beside the title and the line
* that says what the example is for.
*
* The logo sits beside the words rather than above them, because a logo
* on its own line costs every reader the height of it before anything
* they came for.
*/
.c-eg-masthead {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: size(0) size(3);
margin-bottom: size(2);

> img {
flex: 0 0 auto;
}

&__words {
flex: 1 1 20rem;

> :first-child {
margin-top: 0;
}

> :last-child {
margin-bottom: 0;
}
}
}

.c-eg-page__title {
@include make-text-heading-2();
}
Expand Down
163 changes: 163 additions & 0 deletions pattern-library/source/sass/06-examples/08-fields.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
/**
* Fields for an example that takes input, rather than one that only
* shows what an engine returned.
*
* Almost every example we ship reports data and asks for nothing, so the
* system grew a rich set of ways to display a result and nothing for a
* reader to type into. An example that does take input was left composing
* .b-input with whatever it could find, which reads as a different
* control on the same page. These are the two fields such an example
* needs, being a single line control and a multi line editor, sharing one
* treatment so they look like a set.
*/

/**
* What both fields share on top of the design system input. The border
* softens and the corners round, so a field reads as an area to work in
* rather than as a bordered rectangle, and a focus ring says which field
* holds the caret.
*
* The ring is on :focus-visible, so a keyboard user gets it and a
* pointer user clicking straight into the field does not.
*/
@mixin make-example-field {
@include make-input();
border-color: $colour-grey-light;
border-radius: $rounded;
background-color: $colour-grey-lighter;

&:focus-visible {
outline: 2px solid $colour-blue;
outline-offset: 1px;
border-color: $colour-blue;
}
}

/**
* A single line control, being a text box or a list. Filling its
* container is not enough on its own, because a control in a narrow
* table column would collapse to the column and truncate what it holds,
* so it asks for a width the column has to give it.
*/
.c-eg-control {
@include make-example-field();
width: 100%;
min-width: size(11);
}

/**
* A table of fields, being one row for each thing a reader sets.
*
* Everything inside it is one size. The system sizes each piece for the
* place it usually appears, so a control carries the body size it needs
* standing alone in a form, and the code face is a step smaller because
* it usually sits inside running prose. Put the two in one row with
* ordinary cell text and a reader sees three sizes and reads three
* different things rather than one row.
*
* The control also loses its form padding, because a row of them is
* dense by nature and padding sized for a lone box makes the table tall
* enough to scroll for no reason.
*/
.c-eg-fields {
.c-eg-control,
.b-text--code {
font-size: inherit;
}

.c-eg-control {
padding: size(-3) size(-2);
}

/* A table aligns to the top, which is right where a cell holds a
paragraph and the row is as tall as the longest one. Here the tall
cells are controls, which centre what they hold, so a name aligned
to the top sits above the control beside it and nothing in the row
lines up. */
.c-eg-table__cell {
vertical-align: middle;
}
}

/**
* Output printed exactly as something produced it, such as a message a
* caller would meet or a canonical form.
*
* It scrolls sideways rather than stretching what is around it. A long
* line inside a bare pre widens its container, and in a page laid out in
* columns that pushes everything else out of shape, which is worse than
* a scrollbar.
*/
.c-eg-pre {
@include make-text-code();
background-color: $colour-grey-lighter;
border-radius: $rounded;
padding: size(0);
margin: 0 0 size(2);
max-width: 100%;
overflow-x: auto;
}

/**
* The same block for output that is prose rather than structure, such as
* a message. Prose is easier to read wrapped, whilst something with
* meaningful indentation is not, which is why this is a choice rather
* than the default.
*/
.c-eg-pre--wrap {
white-space: pre-wrap;
word-break: break-word;
}

/**
* A row of controls that belong together, such as a label, a list to
* choose from and the button that acts on it.
*
* c-eg-button-row sets margins and nothing else, which is all a row of
* buttons needs, and it leaves a control filling the line on its own so
* the button beside it falls underneath. This lays the row out.
*/
.c-eg-controls {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: size(0);
margin: size(1) 0 size(2);

/* A control in a row sizes to what it holds rather than filling the
line, which is the opposite of what it does in a table cell or a
column, so the row stays a row. */
.c-eg-control {
width: auto;
}
}

/**
* A multi line editor for something structured, such as a script, a
* configuration block or a request body. It adds to the single line
* control only what many lines need.
*/
.c-eg-editor {
@include make-example-field();
@include make-text-code();

width: 100%;
min-height: 340px;

/* make-input sets 1.2, which is right for one line of prose and too
tight for many lines of indented code. */
line-height: 1.5;

/* Only the height can be dragged. A reader widening one editor in a
two column layout would push the other out of the grid. */
resize: vertical;

/* The formats these examples show are indented two spaces, so a tab
that jumps eight columns makes pasted content look wrong. */
tab-size: 2;

/* Lines scroll sideways rather than wrap, because wrapping a
structured format hides the indentation that carries its meaning. */
white-space: pre;
overflow: auto;
}
65 changes: 65 additions & 0 deletions pattern-library/source/sass/06-examples/09-result.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* The answer an example exists to give, at the weight that deserves.
*
* An example computes one thing, and everything else on its page is
* there to explain that one thing. So the answer is what a reader looks
* for first and what they come back to after every change they make.
* Reported at the size of ordinary body text it reads as one more
* paragraph among the paragraphs explaining it, and a reader has to hunt
* for the part they came for.
*
* Put this above whatever a reader changes rather than below it, so that
* changing something and seeing what it did takes no scrolling.
*/

.c-eg-result {
background-color: $colour-grey-lighter;
border-radius: $rounded;
padding: size(2) size(3);
margin: size(1) 0 size(3);
}

/* What the answer is the answer to, said quietly above it, because the
reader already knows and only needs reminding. */
.c-eg-result__label {
@include make-text-heading-caps();
display: block;
margin: 0 0 size(-2);
}

/* The answer itself. It carries the code face because what an example
returns is a value rather than prose, and a size that makes it the
first thing on the page a reader sees. */
.c-eg-result__value {
@include make-text-code();
font-size: size(7);
line-height: 1.1;
color: $colour-black;
margin: 0;

/* A value can be a long string, and stretching the panel to fit one
would push the page out of shape. */
word-break: break-word;
}

/* How the answer should be read, said quietly below it. */
.c-eg-result__note {
margin: size(0) 0 0;
}

/**
* Where the example has no answer to give. The surface carries it rather
* than the value, because there is no value to colour, and a reader
* scanning for the answer needs to see at a glance that there is not
* one.
*/
.c-eg-result--none {
background-color: $colour-pink-light;
border: 1px solid $colour-red;

.c-eg-result__value {
@include make-text-default();
font-weight: $font-weight-bold;
color: $colour-red;
}
}
Loading