Skip to content

Commit 90e0af4

Browse files
committed
docs(ui-themes): add interactive example on how to use brand theme variables
TEST PLAN: Play with the values in the example
1 parent 9b32dfb commit 90e0af4

File tree

2 files changed

+213
-5
lines changed

2 files changed

+213
-5
lines changed

docs/guides/using-theme-overrides.md

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,3 +180,209 @@ type: example
180180
</div>
181181
</InstUISettingsProvider>
182182
```
183+
184+
### Branding (user customizable theming)
185+
186+
The `canvas` theme has specific theme variables that are meant as a basis to provide end users a customizability of this theme, e.g. a university can use their own colors throughout the UI. This is used by [Canvas's theme editor](https://community.canvaslms.com/t5/Admin-Guide/How-do-I-create-a-theme-for-an-account-using-the-Theme-Editor/ta-p/242).
187+
188+
> `canvas-high-contrast` does not have this functionality, so a11y color contrast requirements (e.g. [WCAG](https://webaim.org/articles/contrast/)) are always met
189+
190+
```ts
191+
---
192+
type: example
193+
---
194+
const Example = () => {
195+
// global stuff
196+
const [icBrandPrimary, setIcBrandPrimary] = useState(canvas['ic-brand-primary'])
197+
const [icBrandFontColorDark, setIcBrandFontColorDark] = useState(canvas['ic-brand-font-color-dark'])
198+
// Link
199+
const [icLinkColor, setIcLinkColor] = useState(canvas['ic-link-color'])
200+
const [icLinkDecoration, setIcLinkDecoration] = useState(canvas['ic-link-decoration'])
201+
// Button
202+
const [icBrandButtonPrimaryBgd, setIcBrandButtonPrimaryBgd] = useState(canvas['ic-brand-button--primary-bgd'])
203+
const [icBrandButtonPrimaryText, setIcBrandButtonPrimaryText] = useState(canvas['ic-brand-button--primary-text'])
204+
const [icBrandButtonSecondaryBgd, setIcBrandButtonSecondaryBgd] = useState(canvas['ic-brand-button--secondary-bgd'])
205+
const [icBrandButtonSecondaryText, setIcBrandButtonSecondaryText] = useState(canvas['ic-brand-button--secondary-text'])
206+
// SideNavBar
207+
const [icBrandGlobalNavBgd, setIcBrandGlobalNavBgd] = useState(canvas['ic-brand-global-nav-bgd'])
208+
const [icGlobalNavLinkHover, setIcGlobalNavLinkHover] = useState(canvas['ic-global-nav-link-hover'])
209+
const [icBrandGlobalNavIcIconSvgFill, setIcBrandGlobalNavIcIconSvgFill] = useState(canvas['ic-brand-global-nav-ic-icon-svg-fill'])
210+
const [icBrandGlobalNavIcIconSvgFillActive, setIcBrandGlobalNavIcIconSvgFillActive] = useState(canvas['ic-brand-global-nav-ic-icon-svg-fill--active'])
211+
const [icBrandGlobalNavMenuItemTextColor, setIcBrandGlobalNavMenuItemTextColor] = useState(canvas['ic-brand-global-nav-menu-item__text-color'])
212+
const [icBrandGlobalNavMenuItemTextColorActive, setIcBrandGlobalNavMenuItemTextColorActive] = useState(canvas['ic-brand-global-nav-menu-item__text-color--active'])
213+
214+
return (
215+
<div>
216+
<h3>Common variables</h3>
217+
<Flex gap="small large">
218+
<Flex.Item size="50%">
219+
<TextInput renderLabel="ic-brand-primary" value={icBrandPrimary} onChange={(e, v) => setIcBrandPrimary(v)}
220+
messages={[{text:'used for border/background/shadow/focus colors in many places',type:'hint'}]} />
221+
</Flex.Item>
222+
<Flex.Item size="50%">
223+
<TextInput renderLabel="ic-brand-font-color-dark" value={icBrandFontColorDark} onChange={(e, v) => setIcBrandFontColorDark(v)}
224+
messages={[{text:'used in lots of places for text color',type:'hint'}]} />
225+
</Flex.Item>
226+
</Flex>
227+
228+
<h3><code>Button</code> branding</h3>
229+
<Flex gap="small large">
230+
<Flex.Item size="50%">
231+
<TextInput renderLabel="ic-brand-button--primary-bgd" value={icBrandButtonPrimaryBgd} onChange={(e, v) => setIcBrandButtonPrimaryBgd(v)}
232+
messages={[{text:"Used by 'primary' color buttons for background",type:'hint'}]} />
233+
<br/>
234+
<TextInput renderLabel="ic-brand-button--primary-text" value={icBrandButtonPrimaryText} onChange={(e, v) => setIcBrandButtonPrimaryText(v)}
235+
messages={[{text:"Used by 'primary' color buttons for text color",type:'hint'}]} />
236+
</Flex.Item>
237+
<Flex.Item size="50%">
238+
<TextInput renderLabel="ic-brand-button--secondary-bgd" value={icBrandButtonSecondaryBgd} onChange={(e, v) => setIcBrandButtonSecondaryBgd(v)}
239+
messages={[{text:'Unused in InstUI',type:'hint'}]} />
240+
<br/>
241+
<TextInput renderLabel="ic-brand-button--secondary-text" value={icBrandButtonSecondaryText} onChange={(e, v) => setIcBrandButtonSecondaryText(v)}
242+
messages={[{text:'Unused in InstUI',type:'hint'}]}/>
243+
</Flex.Item>
244+
</Flex>
245+
<div style={{display: 'flex', gap: '2rem', marginTop: '3rem', flexDirection: 'column'}}>
246+
<InstUISettingsProvider theme={{...canvas, ...{
247+
'ic-brand-primary': icBrandPrimary,
248+
'ic-brand-font-color-dark': icBrandFontColorDark,
249+
'ic-link-color': icLinkColor,
250+
'ic-link-decoration': icLinkDecoration,
251+
'ic-brand-button--primary-bgd': icBrandButtonPrimaryBgd,
252+
'ic-brand-button--primary-text': icBrandButtonPrimaryText,
253+
'ic-brand-button--secondary-bgd': icBrandButtonSecondaryBgd,
254+
'ic-brand-button--secondary-text': icBrandButtonSecondaryText,
255+
'ic-brand-global-nav-bgd': icBrandGlobalNavBgd,
256+
'ic-global-nav-link-hover': icGlobalNavLinkHover,
257+
'ic-brand-global-nav-ic-icon-svg-fill': icBrandGlobalNavIcIconSvgFill,
258+
'ic-brand-global-nav-ic-icon-svg-fill--active': icBrandGlobalNavIcIconSvgFillActive,
259+
'ic-brand-global-nav-menu-item__text-color': icBrandGlobalNavMenuItemTextColor,
260+
'ic-brand-global-nav-menu-item__text-color--active': icBrandGlobalNavMenuItemTextColorActive
261+
}}}>
262+
<hr style={{width:'100%'}}/>
263+
<Flex gap="small large">
264+
<Flex.Item size="50%">
265+
<Button color="primary">I'm a 'primary' color button</Button>
266+
<TextInput renderLabel="TextInput" placeholder="ic-brand-primary sets focus color"/>
267+
</Flex.Item>
268+
<Flex.Item size="50%">
269+
<Button color="secondary">I'm a 'secondary' color button</Button>
270+
<TextArea label="TextArea" placeholder="ic-brand-primary sets focus color"/>
271+
</Flex.Item>
272+
</Flex>
273+
274+
<Tabs>
275+
<Tabs.Panel id="tabA" renderTitle="Tab A" isSelected={true}></Tabs.Panel>
276+
<Tabs.Panel id="tabB" renderTitle="Disabled Tab" isDisabled></Tabs.Panel>
277+
<Tabs.Panel id="tabC" renderTitle="Tab C"></Tabs.Panel>
278+
<Tabs.Panel id="tabD" renderTitle="Tab D"></Tabs.Panel>
279+
</Tabs>
280+
281+
<hr style={{width:'100%'}}/>
282+
<h3>Link colors used by <code>Link</code> and <code>Billboard</code>:</h3>
283+
<Flex gap="small large">
284+
<Flex.Item size="50%">
285+
<TextInput renderLabel="ic-link-color" value={icLinkColor} onChange={(e, v) => setIcLinkColor(v)}
286+
messages={[{text:'Used for non-inverse Link and clickable Billboard',type:'hint'}]} />
287+
</Flex.Item>
288+
<Flex.Item size="50%">
289+
<TextInput renderLabel="ic-link-decoration" value={icLinkDecoration} onChange={(e, v) => setIcLinkDecoration(v)}
290+
messages={[{text:'Unused in InstUI',type:'hint'}]}/>
291+
</Flex.Item>
292+
</Flex>
293+
<hr style={{width:'100%'}}/>
294+
<Flex gap="small large">
295+
<Flex.Item size="50%">
296+
<Link href="https://instructure.github.io/instructure-ui/">normal link</Link>
297+
</Flex.Item>
298+
<Flex.Item size="50%">
299+
<View background="primary-inverse" as="div">
300+
<Link color="link-inverse" href="https://instructure.github.io/instructure-ui/">inverse link</Link>
301+
</View>
302+
</Flex.Item>
303+
</Flex>
304+
<Flex gap="small large">
305+
<Flex.Item size="50%">
306+
<Billboard
307+
margin="small"
308+
message="Billboard with link"
309+
href="http://instructure.com"
310+
hero={(size) => <IconGradebookLine size={size} />}
311+
/>
312+
</Flex.Item>
313+
<Flex.Item size="50%">
314+
<Billboard
315+
margin="small"
316+
message="Billboard without link"
317+
hero={(size) => <IconGradebookLine size={size} />}
318+
/>
319+
</Flex.Item>
320+
</Flex>
321+
322+
<hr style={{width:'100%'}}/>
323+
<h3><code>SideNavBar</code> branding</h3>
324+
<Flex gap="small large">
325+
<Flex.Item size="50%">
326+
<TextInput renderLabel="ic-brand-global-nav-bgd" value={icBrandGlobalNavBgd} onChange={(e, v) => setIcBrandGlobalNavBgd(v)}/>
327+
<TextInput renderLabel="ic-global-nav-link-hover" value={icGlobalNavLinkHover} onChange={(e, v) => setIcGlobalNavLinkHover(v)}/>
328+
<TextInput renderLabel="ic-brand-global-nav-ic-icon-svg-fill" value={icBrandGlobalNavIcIconSvgFill} onChange={(e, v) => setIcBrandGlobalNavIcIconSvgFill(v)}/>
329+
</Flex.Item>
330+
<Flex.Item size="50%">
331+
<TextInput renderLabel="ic-brand-global-nav-menu-item__text-color" value={icBrandGlobalNavMenuItemTextColor} onChange={(e, v) => setIcBrandGlobalNavMenuItemTextColor(v)}/>
332+
<TextInput renderLabel="ic-brand-global-nav-menu-item__text-color--active" value={icBrandGlobalNavMenuItemTextColorActive} onChange={(e, v) => setIcBrandGlobalNavMenuItemTextColorActive(v)}/>
333+
<TextInput renderLabel="ic-brand-global-nav-ic-icon-svg-fill--active" value={icBrandGlobalNavIcIconSvgFillActive} onChange={(e, v) => setIcBrandGlobalNavIcIconSvgFillActive(v)}/>
334+
</Flex.Item>
335+
</Flex>
336+
<hr style={{width:'100%'}}/>
337+
<SideNavBar
338+
label="Main navigation"
339+
toggleLabel={{
340+
expandedLabel: 'Minimize SideNavBar',
341+
minimizedLabel: 'Expand SideNavBar'
342+
}}
343+
>
344+
<SideNavBar.Item
345+
icon={<IconUserLine />}
346+
label={<ScreenReaderContent>Home</ScreenReaderContent>}
347+
href="#"
348+
/>
349+
<SideNavBar.Item
350+
icon={<Avatar name="Ziggy Marley" size="x-small" src={avatarSquare} showBorder="always"/>}
351+
label="Account"
352+
onClick={() => { this.loadSubNav('account') }}
353+
/>
354+
<SideNavBar.Item
355+
icon={<IconAdminLine />}
356+
label="Admin"
357+
href="#"
358+
/>
359+
<SideNavBar.Item selected
360+
icon={<IconDashboardLine />}
361+
label="Dashboard"
362+
href="#"
363+
/>
364+
<SideNavBar.Item
365+
icon={<Badge count={99}
366+
formatOutput={function (formattedCount) {
367+
return (
368+
<AccessibleContent alt={`You have ${formattedCount} unread messages.`}>
369+
{formattedCount}
370+
</AccessibleContent>
371+
)
372+
}}
373+
><IconInboxLine /></Badge>}
374+
label="Inbox"
375+
href="#"
376+
/>
377+
<SideNavBar.Item icon={<IconUserLine />}
378+
label="Supercalifragilistic"
379+
href="#" />
380+
</SideNavBar>
381+
</InstUISettingsProvider>
382+
</div>
383+
</div>
384+
)
385+
}
386+
387+
render(<Example/>)
388+
```

packages/ui-themes/src/themes/canvas/index.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,19 @@ const key = 'canvas'
3131

3232
const brandVariables = {
3333
/* Defaults for Canvas account branding variables: */
34+
// used for border/background/shadow colors in many places
3435
'ic-brand-primary': colors?.contrasts?.blue4570,
36+
// used in lots of places for text color
3537
'ic-brand-font-color-dark': colors?.contrasts?.grey125125,
36-
38+
// used by Link and links in Billboard
3739
'ic-link-color': colors?.contrasts?.blue4570,
3840
'ic-link-decoration': 'none',
39-
41+
// Used by BaseButton and its subcomponents
4042
'ic-brand-button--primary-bgd': colors?.contrasts?.blue4570,
4143
'ic-brand-button--primary-text': colors?.contrasts?.white1010,
42-
'ic-brand-button--secondary-bgd': colors?.contrasts?.grey125125,
43-
'ic-brand-button--secondary-text': colors?.contrasts?.white1010,
44-
44+
'ic-brand-button--secondary-bgd': colors?.contrasts?.grey125125, // unused!
45+
'ic-brand-button--secondary-text': colors?.contrasts?.white1010, // unused!
46+
// these are used only by SideNavBar
4547
'ic-brand-global-nav-bgd': colors?.contrasts?.grey100100,
4648
'ic-global-nav-link-hover': colors?.contrasts?.grey125125,
4749
'ic-brand-global-nav-ic-icon-svg-fill': colors?.contrasts?.white1010,

0 commit comments

Comments
 (0)