Style guide
Every element the theme styles, on one page. Use it to check a change against the whole surface rather than the page you happened to be editing.
Headings
Heading one
Heading two
Heading three
Heading four
Heading five
Heading six
Text
Body copy is IBM Plex Sans at 15px with a 1.6 line height. Bold resolves to weight 500, because
the type scale has no weight above it — there is no 600 or 700 anywhere in Norn. Italic is a real
italic cut, not a synthesised oblique. Inline code is IBM Plex Mono, one step down, on a raised
surface with a hairline border.
Links look like this and underline on hover. A link with code inside keeps the link
colour.
Press ⌘ K to search, C to create an issue, J and K to move the cursor.
A blockquote sits behind a two-pixel rule in
--line-strong. It carries secondary ink, so it reads as an aside rather than as emphasis.
Lists
- Unordered items sit on a tight rhythm
- Nested lists inherit it
- Second level
- Second level
- Back to the first level
- Ordered lists are used for sequences
- Upgrade steps, install steps, request flows
- Anything where the number carries meaning
Admonitions
The default. A neutral rule in --ink-400, for a remark that does not change what you would do.
Cyan, the same hue as the focus ring. Context worth having.
Green. A better way to do the thing you are already doing.
Amber. Something that will bite if ignored.
Red. Data loss, lockout, or an irreversible action.
Code
func (s *service) Create(ctx context.Context, in entity.NewIssue) (*entity.Issue, error) {
if err := in.Validate(); err != nil {
return nil, err
}
var created *entity.Issue
err := s.tx.WithTx(ctx, func(ctx context.Context) error {
issue, err := s.issues.Create(ctx, in)
if err != nil {
return err
}
created = issue
return nil
})
return created, err
}
Line highlighting marks the line that matters:
import createClient from 'openapi-fetch';
import type {paths} from './dashboard.gen';
export const api = createClient<paths>({baseUrl: '/v1'});
Shell, without a title:
make gen && make wire
go build ./...
Tabs
- curl
- TypeScript
- Go
curl https://norn.example.com/v1/accounts/me \
-H "Authorization: Bearer $NORN_TOKEN"
const {data, error} = await api.GET('/accounts/me');
if (error) throw new Error(error.title);
res, err := client.GetCurrentAccount(ctx)
if err != nil {
return err
}
Tables
Headers are mono, uppercase, and tracked out — the same treatment the application gives a column
header. Rows separate on --line-subtle and lift on hover.
| Token | Value | Used for |
|---|---|---|
--paper-0 | #0f1116 | Page background |
--paper-1 | #14171d | Cards, sidebar, code blocks |
--paper-2 | #1a1e25 | Popovers, inline code |
--ink-900 | #e8ebf2 | Headings and primary fill |
--ink-800 | #d3d8e2 | Body copy |
--ink-500 | #7e8698 | Muted copy |
--line-subtle | #1c2028 | Row separators |
--line-default | #262b34 | Component borders |
--line-strong | #384050 | Inputs, raised edges |
--ring | #35b7d6 | Focus ring |
Details
What is in a collapsed block
Anything a page can hold — prose, code, another table. It is closed by default, so it is the right home for the case that only some readers need.
norn jobs --help
Images
An image picks up a hairline border and the standard five-pixel radius, so a screenshot sits on the page the same way a card does.