Thanks to visit codestin.com
Credit goes to github.com

Skip to content
This repository was archived by the owner on Sep 1, 2021. It is now read-only.

Editorial Palette #313

Merged
merged 5 commits into from
May 18, 2020
Merged

Editorial Palette #313

merged 5 commits into from
May 18, 2020

Conversation

JamieB-gu
Copy link
Contributor

@JamieB-gu JamieB-gu commented May 6, 2020

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 the Format type.

Changes

  • 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

Addendum

Updated by @gtrufitt to add this doc that 'summarises' the discussions here: https://docs.google.com/document/d/1nkntFJUunqrwNYszTrc2RBfyYUd1bEAeQh76yVFOLjo/edit#heading=h.av4lby7ua1bp

Copy link

@oliverlloyd oliverlloyd left a 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?


// ----- Functions ----- //

const headlineFont = (format: Format): Colour => {

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

@JamieB-gu
Copy link
Contributor Author

As discussed offline, will look into making this an object.

@JamieB-gu
Copy link
Contributor Author

JamieB-gu commented May 7, 2020

Following discussions with @oliverlloyd it looks like creating an object keyed on Format would be complex and come with a lot of boilerplate. Here's a small sample of what that might look like:

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 editorialStyles module; the editorialPalette module now just exports functions that generate hex strings.

I've also added a brief example of a Palette type, which we may or may not want to use. Let me know what you think @oliverlloyd @SiAdcock @gtrufitt @liywjl @webb04.

Comment on lines 86 to 126
const palette = (format: Format): Palette =>
({
headlineFont: headlineFont(format),
headlineBackground: headlineBackground(format),
border: border(format),
});

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.

Copy link
Contributor Author

@JamieB-gu JamieB-gu May 7, 2020

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.

Comment on lines 18 to 21
interface Colour {
light: string;
dark: string;
}

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'...

Copy link

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?

Copy link
Contributor Author

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.

@JamieB-gu JamieB-gu marked this pull request as ready for review May 7, 2020 14:56
@gtrufitt
Copy link
Contributor

Love it, I'd be really keen to start using this and evolve it together!

}

interface Palette {
headlineFont: Colour;
Copy link
Contributor

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea! Updated.

Copy link
Contributor

@SiAdcock SiAdcock May 12, 2020

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.

Copy link
Contributor Author

@JamieB-gu JamieB-gu May 12, 2020

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:

  1. What does the dot signify in the hierarchy (I know it represents a method or property lookup, but why at that level)?
  2. 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: ...,
};

Copy link
Contributor

@SiAdcock SiAdcock May 12, 2020

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:

Copy link
Contributor Author

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?

Copy link
Contributor

@SiAdcock SiAdcock May 13, 2020

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.

Copy link
Contributor Author

@JamieB-gu JamieB-gu May 13, 2020

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.

Copy link
Contributor

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 🚒

Copy link
Contributor Author

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.

@JamieB-gu JamieB-gu force-pushed the editorial-palette branch from d16a0a9 to 45be279 Compare May 12, 2020 15:46
import StarRating from './starRating';
import { Display, Design } from 'format';
import { border } from 'editorialPalette';
Copy link
Contributor

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?

Copy link
Contributor Author

@JamieB-gu JamieB-gu May 13, 2020

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?

Copy link
Contributor

@SiAdcock SiAdcock May 13, 2020

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.

Copy link
Contributor Author

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 or color 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:

  1. The editorialPalette module would contain a colour token, called either border or line, which is just a hex colour.

  2. 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 πŸ‘.

Copy link
Contributor

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 πŸ‘

JamieB-gu added 4 commits May 15, 2020 16:28
- 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
Copy link

@alexduf alexduf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ‘

@JamieB-gu JamieB-gu merged commit e723c56 into master May 18, 2020
@JamieB-gu JamieB-gu deleted the editorial-palette branch May 18, 2020 11:23
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants