-
Notifications
You must be signed in to change notification settings - Fork 1
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the approach I had in mind for DCR to do this was to have a function that took Format
(same as you've got here) but to then return a simple object with colour properties. A bit like:
{
headlineBackground: ${background.primary},
headline: ${pillar.dark},
pageBorder: ${border.primary},
pageBackground: #abc,
}
We'd then possibly set that as a theme (or perhaps import it directly) and use it in the css. I'm leaning towards a theme because it will make the refactor a lot simpler and create less noise.
My concern with exporting css is it creates a coupling which could make maintenance harder and generally make it harder to share this logic between platforms. Maybe we could define a simple, pure object exporting function to start with, and then you could have another, app specific, function that imports that and exports app specific css?
src/editorialPalette.ts
Outdated
|
||
// ----- Functions ----- // | ||
|
||
const headlineFont = (format: Format): Colour => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. This basically how our logic in DCR looks. We check for display first and then use a switch to branch on Design.
At a later stage this could extend to a nested switch statement if the number of use cases grows but with this model that's a simple refactor
As discussed offline, will look into making this an object. |
Following discussions with @oliverlloyd it looks like creating an object keyed on const defaultPalette = {
headlineFont: {
light: text.primary,
dark: neutral[86],
},
};
const immersiveHeadlineFont = {
...defaultPalette.headlineFont,
light: neutral[100],
};
const palette: { [ k: string ]: typeof defaultPalette } = {
[ [ Design.Feature, Display.Immersive, Pillar.News ].toString() ]: {
...defaultPalette,
headlineFont: immersiveHeadlineFont,
},
[ [ Design.Feature, Display.Immersive, Pillar.Opinion ].toString() ]: {
...defaultPalette,
headlineFont: immersiveHeadlineFont,
},
[ [ Design.Feature, Display.Immersive, Pillar.Sport ].toString() ]: {
...defaultPalette,
headlineFont: immersiveHeadlineFont,
},
[ [ Design.Feature, Display.Immersive, Pillar.Culture ].toString() ]: {
...defaultPalette,
headlineFont: immersiveHeadlineFont,
},
[ [ Design.Feature, Display.Immersive, Pillar.Lifestyle ].toString() ]: {
...defaultPalette,
headlineFont: immersiveHeadlineFont,
},
} Instead, I've decided to stick with functions for now, and looked instead at addressing Oliver's other concern: exporting CSS. I've split out any CSS-related functions into an I've also added a brief example of a |
src/editorialPalette.ts
Outdated
const palette = (format: Format): Palette => | ||
({ | ||
headlineFont: headlineFont(format), | ||
headlineBackground: headlineBackground(format), | ||
border: border(format), | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This. It's funny how it looks so simple when you see it here now but I guess the solutions that seem simple are the best ones!
One nitpick, I wouldn't name the function the same as the property it is setting, I normally go for some kind of prefix like decideHeadlineBackground()
or getHeadlineBackground()
but that's maybe because I lean a lot on using CMD+D
to select similar text when editing. Defo not a blocker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the more complex the code that I write gets, the less comfortable I am that it's the best way of doing it π
I suspect DCR might make use of this (with a theme), and AR might make use of the individual functions/CSS declarations.
One nitpick
Yeah we should discuss the API, this is a draft PR for a reason π. On this, I try to make function names as simple as I can because I find the longer they are a) there's more brainpower required to parse them, and b) longer names can muddy what the function is actually doing. I think ideally the type should be able to work in tandem with the name to tell you a function's purpose. This is subjective, happy to be told otherwise.
src/editorialPalette.ts
Outdated
interface Colour { | ||
light: string; | ||
dark: string; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be a bit restrictive for DCR. I don't have a specific example but my feeling is we often stray outside the bounds of 'neat'...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am assuming this is for dark mode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am assuming this is for dark mode?
Yep, many colours have a dark mode variant, the most prominent examples being the article background and body copy colour.
Love it, I'd be really keen to start using this and evolve it together! |
src/editorialPalette.ts
Outdated
} | ||
|
||
interface Palette { | ||
headlineFont: Colour; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: I might suggest headlineText
for better consistency with Source.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea! Updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's worth spending a bit of time thinking about how the naming system will scale. I know @oliverlloyd has pointed to the potential problem with the Colour
abstraction defining a light
and a dark
mode. This could become a bit verbose or restrictive for DCR that only has a light mode. There might be ways for DCR to abstract this away in their application, but it's worth bearing in mind.
I'll give you a peek at Source's colour token naming system:
[theme][property].[component][variant][state][mode]
- theme: the colour theme to which this token applies
- property: the style property for which this token is intended
- component: the design system component to which this token is applied
- variant: there are sometimes multiple variants of each token. For example, text in a component may be primary or supporting
- state: user interaction that may have affected the appearance, such as hover or checked
- mode: the colour mode (i.e. inverse represents dark mode)
Note that in most cases, not all of these parts will be present.
Examples:
text.primary
This is a text colour, for primary text. There is no theme specified, so we assume itβs for the default theme. Note that itβs not for a specific component. βPrimaryβ is the variant, telling us it should be applied to the most important or core text. There is no state, so we assume there has been no user interaction. There is no mode, so we assume the default colour mode ("light mode")
brandBackground.cardArticleHover
This is a background colour on brand theme, for the article card, in the hover state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is very thorough, thanks!
Two questions:
- What does the dot signify in the hierarchy (I know it represents a method or property lookup, but why at that level)?
- How would you define the property for text in a headline? Would it be
headlineText.primary
? Or do you see headline styles coming as a bundle so that it would be something like:headline.text.primary
?
const headline = {
text: ...,
background: ...,
brandAltText: ...,
brandAltBackground: ...,
};
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The position of the dot was my best guess at where to split the palette to make it more treeshakable. It's likely that most applications won't be using multiple themes on one page, and those that used multiple themes might not want all the colours for each theme. I think you can ignore this consideration for your purpose.
In your example text
is the property... it represents the CSS property to which this token will be applied (well, technically it's the CSS color
property, but color
is a bit vague!)
I think headlineText
is a good name. Abstracted it's [component][property]
whereas Source goes with [property][component]
but I don't think it matters too much.
There's only one headline per article, so you won't have variants like "primary headline" and "supporting headline".
It's worth taking a look at other design systems to see how they name their tokens. Then write down what your system is, so you can (attempt to!) keep it consistent:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sorry, yes that's also an API we'd want. With the above I was asking which one of those four we should go with for individual colour lookups. I think we'd want the palette
API to exist in addition to that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My preference would be option 1. It's similar to Source and I kinda like the ergonomics. Also there's some value in consistency as people would be able to switch between the Source palette and the Editorial palette without having to think too much.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, sounds good, I'm happy with the API.
My only concern is that we'd be generating a lot of unused colours with every call to the text
function. For example, if we use it in the Headline
component, we're only going to pull out one or two colours. We could solve this with memoisation, or by dependency injecting the full palette as DCR are planning to do.
I wonder if a fifth option that looks a lot like (1) would be preferable:
text.headlinePrimary(format)
That way we're doing the minimum amount of work at each call site, just enough to derive a single colour.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh gosh, yes. More performant and preserves the ergonomics. I'm on board π’
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I've updated the code to use this new API.
d16a0a9
to
45be279
Compare
import StarRating from './starRating'; | ||
import { Display, Design } from 'format'; | ||
import { border } from 'editorialPalette'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you intend to move border
to editorialStyles
also?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't planning to move it π€, but we could generate CSS declarations for it there as well. Would have to be border-color
specifically rather than border
I think?
Now that you've flagged this it occurs to me we could also name it something more generic in the palette
module, like line
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would have to be border-color specifically rather than border I think
Yeah, maybe. I was gonna suggest dropping colour
or color
from names because colour is implied by the fact it's in the editorial palette. It's up to you though, maybe there will be non-colour tokens here also (spacing, border radiuses)? In which case, specific is better.
we could also name it something more generic in the palette module, like line
I think there's a distinction between border
and line
. Borders border elements, lines divide elements. Borders are encapsulated within a component, lines are defined at the layout level. I don't think we should conflate these concepts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was gonna suggest dropping
colour
orcolor
from names because colour is implied by the fact it's in the editorial palette
Sorry, I was probably unclear there. I was thinking something along these lines:
-
The
editorialPalette
module would contain a colour token, called eitherborder
orline
, which is just a hex colour. -
The
editorialStyles
module could contain a CSS declaration of the form:
const border = css`
border-color: ${palette.border};
`;
When I said border-color
I meant the CSS property rather than the name for the variable in our code π. I think you're right, this is just for colours.
Borders border elements, lines divide elements
Ok, we have a semantic distinction between them so we should provide different names to avoid confusion, sounds good π.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, yeah, me got confused there! Only 3 cups of tea this morning. You makes a lot of sense π
- Created editorialPalette module - Functions to get headlineFont, headlineBackground and border colours - Functions to apply color and background declarations - Applied new palette functions to headline component
e4de710
to
3adc7db
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π
Why are you doing this?
A speculative PR based on our conversation about an editorial colour palette. I'm not sure about the API here so I'd appreciate some feedback π
This creates some simple functions to lookup headline font and background colours, and the border colour based on the
Format
type. I've also added some functions to generate the next level above this, i.e. CSS declarations for font and background colour based on theFormat
type.Changes
Headline
componentAddendum
Updated by @gtrufitt to add this doc that 'summarises' the discussions here: https://docs.google.com/document/d/1nkntFJUunqrwNYszTrc2RBfyYUd1bEAeQh76yVFOLjo/edit#heading=h.av4lby7ua1bp