Skip to content

Commit 1808303

Browse files
gadenbuiecpsievert
andauthored
feat(theme): Branded theming via brand_yml (#1743)
Co-authored-by: Carson Sievert <cpsievert1@gmail.com>
1 parent 8a60787 commit 1808303

File tree

15 files changed

+1354
-21
lines changed

15 files changed

+1354
-21
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2929

3030
* Added [narwhals](https://posit-dev.github.io/py-narwhals) support for `@render.table`. This allows for any eager data frame supported by narwhals to be returned from a `@render.table` output method. (#1570)
3131

32+
* Shiny now supports theming via [brand.yml](https://posit-dev.github.io/brand-yml) with a single `_brand.yml` file. Call `ui.Theme.from_brand()` with `__file__` or the path to a `_brand.yml` file and pass the resulting theme to the `theme` argument of `express.ui.page_opts()` (Shiny Express) or `ui.page_*()` functions (Shiny Core) to apply the brand theme to the entire app. (#1743)
33+
3234
* `chat_ui()` and `Chat.ui()` gain a `messages` parameter for providing starting messages. (#1736)
3335

3436
### Other changes

docs/_quarto.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,6 @@ interlinks:
4444
url: https://matplotlib.org/stable/
4545
python:
4646
url: https://docs.python.org/3/
47+
brand-yml:
48+
url: https://posit-dev.github.io/brand-yml/
49+
inv: objects.txt

examples/brand/Monda-OFL.txt

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
Copyright 2021 The Monda Project Authors (https://github.com/googlefonts/mondaFont)
2+
3+
This Font Software is licensed under the SIL Open Font License, Version 1.1.
4+
This license is copied below, and is also available with a FAQ at:
5+
https://openfontlicense.org
6+
7+
8+
-----------------------------------------------------------
9+
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10+
-----------------------------------------------------------
11+
12+
PREAMBLE
13+
The goals of the Open Font License (OFL) are to stimulate worldwide
14+
development of collaborative font projects, to support the font creation
15+
efforts of academic and linguistic communities, and to provide a free and
16+
open framework in which fonts may be shared and improved in partnership
17+
with others.
18+
19+
The OFL allows the licensed fonts to be used, studied, modified and
20+
redistributed freely as long as they are not sold by themselves. The
21+
fonts, including any derivative works, can be bundled, embedded,
22+
redistributed and/or sold with any software provided that any reserved
23+
names are not used by derivative works. The fonts and derivatives,
24+
however, cannot be released under any other type of license. The
25+
requirement for fonts to remain under this license does not apply
26+
to any document created using the fonts or their derivatives.
27+
28+
DEFINITIONS
29+
"Font Software" refers to the set of files released by the Copyright
30+
Holder(s) under this license and clearly marked as such. This may
31+
include source files, build scripts and documentation.
32+
33+
"Reserved Font Name" refers to any names specified as such after the
34+
copyright statement(s).
35+
36+
"Original Version" refers to the collection of Font Software components as
37+
distributed by the Copyright Holder(s).
38+
39+
"Modified Version" refers to any derivative made by adding to, deleting,
40+
or substituting -- in part or in whole -- any of the components of the
41+
Original Version, by changing formats or by porting the Font Software to a
42+
new environment.
43+
44+
"Author" refers to any designer, engineer, programmer, technical
45+
writer or other person who contributed to the Font Software.
46+
47+
PERMISSION & CONDITIONS
48+
Permission is hereby granted, free of charge, to any person obtaining
49+
a copy of the Font Software, to use, study, copy, merge, embed, modify,
50+
redistribute, and sell modified and unmodified copies of the Font
51+
Software, subject to the following conditions:
52+
53+
1) Neither the Font Software nor any of its individual components,
54+
in Original or Modified Versions, may be sold by itself.
55+
56+
2) Original or Modified Versions of the Font Software may be bundled,
57+
redistributed and/or sold with any software, provided that each copy
58+
contains the above copyright notice and this license. These can be
59+
included either as stand-alone text files, human-readable headers or
60+
in the appropriate machine-readable metadata fields within text or
61+
binary files as long as those fields can be easily viewed by the user.
62+
63+
3) No Modified Version of the Font Software may use the Reserved Font
64+
Name(s) unless explicit written permission is granted by the corresponding
65+
Copyright Holder. This restriction only applies to the primary font name as
66+
presented to the users.
67+
68+
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69+
Software shall not be used to promote, endorse or advertise any
70+
Modified Version, except to acknowledge the contribution(s) of the
71+
Copyright Holder(s) and the Author(s) or with their explicit written
72+
permission.
73+
74+
5) The Font Software, modified or unmodified, in part or in whole,
75+
must be distributed entirely under this license, and must not be
76+
distributed under any other license. The requirement for fonts to
77+
remain under this license does not apply to any document created
78+
using the Font Software.
79+
80+
TERMINATION
81+
This license becomes null and void if any of the above conditions are
82+
not met.
83+
84+
DISCLAIMER
85+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88+
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89+
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90+
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91+
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92+
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93+
OTHER DEALINGS IN THE FONT SOFTWARE.

examples/brand/Monda.ttf

163 KB
Binary file not shown.

examples/brand/_brand.yml

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
meta:
2+
name:
3+
full: "Retro Arcade Brand"
4+
short: "RetroArc"
5+
link:
6+
home: https://retroarc.example.com
7+
mastodon: https://mastodon.social/@retroarc
8+
github: https://github.com/retroarc
9+
linkedin: https://linkedin.com/company/retroarc
10+
twitter: https://twitter.com/retroarc
11+
facebook: https://facebook.com/retroarc
12+
13+
# logo:
14+
# images:
15+
# icon-light: logos/retroarc-icon-light.png
16+
# icon-dark: logos/retroarc-icon-dark.png
17+
# wide-light: logos/retroarc-wide-light.png
18+
# wide-dark: logos/retroarc-wide-dark.png
19+
# tall-light: logos/retroarc-tall-light.png
20+
# tall-dark: logos/retroarc-tall-dark.png
21+
# small:
22+
# light: logos/retroarc-icon-light.png
23+
# dark: logos/retroarc-icon-dark.png
24+
# medium:
25+
# light: logos/retroarc-wide-light.png
26+
# dark: logos/retroarc-wide-dark.png
27+
# large:
28+
# light: logos/retroarc-tall-light.png
29+
# dark: logos/retroarc-tall-dark.png
30+
31+
color:
32+
palette:
33+
pink: "#E83E8C"
34+
blue: "#007BFF"
35+
cyan: "#17A2B8"
36+
teal: "#20C997"
37+
green: "#28A745"
38+
yellow: "#FFD700"
39+
orange: "#FF7F50"
40+
red: "#FF3333"
41+
purple: "#6F42C1"
42+
indigo: "#6610F2"
43+
black: "#1A1A1A"
44+
white: "#F8F8F8"
45+
foreground: black
46+
background: white
47+
primary: purple
48+
success: green
49+
info: cyan
50+
warning: yellow
51+
danger: orange
52+
light: white
53+
dark: black
54+
55+
typography:
56+
fonts:
57+
- family: Quantico
58+
source: google
59+
weight: [700]
60+
style: [normal, italic]
61+
display: swap
62+
- family: Monda
63+
source: file
64+
files:
65+
- path: Monda.ttf
66+
weight: 400..700
67+
- family: Share Tech Mono
68+
source: bunny
69+
weight: 400
70+
style: normal
71+
display: swap
72+
base:
73+
family: Monda
74+
size: 17px
75+
weight: 400
76+
line-height: 1.5
77+
headings:
78+
family: Quantico
79+
weight: 400
80+
line-height: 1.2
81+
style: normal
82+
monospace:
83+
family: Share Tech Mono
84+
size: 0.9em
85+
weight: 400
86+
monospace-inline:
87+
family: Share Tech Mono
88+
# size: 0.9em
89+
weight: 400
90+
color: yellow
91+
background-color: "#1a1a1add"
92+
monospace-block:
93+
family: Share Tech Mono
94+
size: 1.1em
95+
weight: 400
96+
color: green
97+
background-color: black
98+
line-height: 1.4
99+
link:
100+
weight: 400
101+
background-color: purple
102+
color: white
103+
decoration: "underline"
104+
105+
defaults:
106+
bootstrap:
107+
defaults:
108+
my-pink: "$brand-pink"
109+
shiny:
110+
theme:
111+
preset: shiny
112+
rules: |
113+
.navbar-brand { color: $my-pink }
114+
# TODO: Find an appropriate theme variable to set
115+
# navbar-bg: $brand-purple

examples/brand/_colors.scss

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// https://github.com/twbs/bootstrap/blob/v5.3.3/site/assets/scss/_colors.scss
2+
3+
.bd-blue-100 { color: color-contrast($blue-100); background-color: $blue-100; }
4+
.bd-blue-200 { color: color-contrast($blue-200); background-color: $blue-200; }
5+
.bd-blue-300 { color: color-contrast($blue-300); background-color: $blue-300; }
6+
.bd-blue-400 { color: color-contrast($blue-400); background-color: $blue-400; }
7+
.bd-blue-500 { color: color-contrast($blue-500); background-color: $blue-500; }
8+
.bd-blue-600 { color: color-contrast($blue-600); background-color: $blue-600; }
9+
.bd-blue-700 { color: color-contrast($blue-700); background-color: $blue-700; }
10+
.bd-blue-800 { color: color-contrast($blue-800); background-color: $blue-800; }
11+
.bd-blue-900 { color: color-contrast($blue-900); background-color: $blue-900; }
12+
13+
.bd-indigo-100 { color: color-contrast($indigo-100); background-color: $indigo-100; }
14+
.bd-indigo-200 { color: color-contrast($indigo-200); background-color: $indigo-200; }
15+
.bd-indigo-300 { color: color-contrast($indigo-300); background-color: $indigo-300; }
16+
.bd-indigo-400 { color: color-contrast($indigo-400); background-color: $indigo-400; }
17+
.bd-indigo-500 { color: color-contrast($indigo-500); background-color: $indigo-500; }
18+
.bd-indigo-600 { color: color-contrast($indigo-600); background-color: $indigo-600; }
19+
.bd-indigo-700 { color: color-contrast($indigo-700); background-color: $indigo-700; }
20+
.bd-indigo-800 { color: color-contrast($indigo-800); background-color: $indigo-800; }
21+
.bd-indigo-900 { color: color-contrast($indigo-900); background-color: $indigo-900; }
22+
23+
.bd-purple-100 { color: color-contrast($purple-100); background-color: $purple-100; }
24+
.bd-purple-200 { color: color-contrast($purple-200); background-color: $purple-200; }
25+
.bd-purple-300 { color: color-contrast($purple-300); background-color: $purple-300; }
26+
.bd-purple-400 { color: color-contrast($purple-400); background-color: $purple-400; }
27+
.bd-purple-500 { color: color-contrast($purple-500); background-color: $purple-500; }
28+
.bd-purple-600 { color: color-contrast($purple-600); background-color: $purple-600; }
29+
.bd-purple-700 { color: color-contrast($purple-700); background-color: $purple-700; }
30+
.bd-purple-800 { color: color-contrast($purple-800); background-color: $purple-800; }
31+
.bd-purple-900 { color: color-contrast($purple-900); background-color: $purple-900; }
32+
33+
.bd-pink-100 { color: color-contrast($pink-100); background-color: $pink-100; }
34+
.bd-pink-200 { color: color-contrast($pink-200); background-color: $pink-200; }
35+
.bd-pink-300 { color: color-contrast($pink-300); background-color: $pink-300; }
36+
.bd-pink-400 { color: color-contrast($pink-400); background-color: $pink-400; }
37+
.bd-pink-500 { color: color-contrast($pink-500); background-color: $pink-500; }
38+
.bd-pink-600 { color: color-contrast($pink-600); background-color: $pink-600; }
39+
.bd-pink-700 { color: color-contrast($pink-700); background-color: $pink-700; }
40+
.bd-pink-800 { color: color-contrast($pink-800); background-color: $pink-800; }
41+
.bd-pink-900 { color: color-contrast($pink-900); background-color: $pink-900; }
42+
43+
.bd-red-100 { color: color-contrast($red-100); background-color: $red-100; }
44+
.bd-red-200 { color: color-contrast($red-200); background-color: $red-200; }
45+
.bd-red-300 { color: color-contrast($red-300); background-color: $red-300; }
46+
.bd-red-400 { color: color-contrast($red-400); background-color: $red-400; }
47+
.bd-red-500 { color: color-contrast($red-500); background-color: $red-500; }
48+
.bd-red-600 { color: color-contrast($red-600); background-color: $red-600; }
49+
.bd-red-700 { color: color-contrast($red-700); background-color: $red-700; }
50+
.bd-red-800 { color: color-contrast($red-800); background-color: $red-800; }
51+
.bd-red-900 { color: color-contrast($red-900); background-color: $red-900; }
52+
53+
.bd-orange-100 { color: color-contrast($orange-100); background-color: $orange-100; }
54+
.bd-orange-200 { color: color-contrast($orange-200); background-color: $orange-200; }
55+
.bd-orange-300 { color: color-contrast($orange-300); background-color: $orange-300; }
56+
.bd-orange-400 { color: color-contrast($orange-400); background-color: $orange-400; }
57+
.bd-orange-500 { color: color-contrast($orange-500); background-color: $orange-500; }
58+
.bd-orange-600 { color: color-contrast($orange-600); background-color: $orange-600; }
59+
.bd-orange-700 { color: color-contrast($orange-700); background-color: $orange-700; }
60+
.bd-orange-800 { color: color-contrast($orange-800); background-color: $orange-800; }
61+
.bd-orange-900 { color: color-contrast($orange-900); background-color: $orange-900; }
62+
63+
.bd-yellow-100 { color: color-contrast($yellow-100); background-color: $yellow-100; }
64+
.bd-yellow-200 { color: color-contrast($yellow-200); background-color: $yellow-200; }
65+
.bd-yellow-300 { color: color-contrast($yellow-300); background-color: $yellow-300; }
66+
.bd-yellow-400 { color: color-contrast($yellow-400); background-color: $yellow-400; }
67+
.bd-yellow-500 { color: color-contrast($yellow-500); background-color: $yellow-500; }
68+
.bd-yellow-600 { color: color-contrast($yellow-600); background-color: $yellow-600; }
69+
.bd-yellow-700 { color: color-contrast($yellow-700); background-color: $yellow-700; }
70+
.bd-yellow-800 { color: color-contrast($yellow-800); background-color: $yellow-800; }
71+
.bd-yellow-900 { color: color-contrast($yellow-900); background-color: $yellow-900; }
72+
73+
.bd-green-100 { color: color-contrast($green-100); background-color: $green-100; }
74+
.bd-green-200 { color: color-contrast($green-200); background-color: $green-200; }
75+
.bd-green-300 { color: color-contrast($green-300); background-color: $green-300; }
76+
.bd-green-400 { color: color-contrast($green-400); background-color: $green-400; }
77+
.bd-green-500 { color: color-contrast($green-500); background-color: $green-500; }
78+
.bd-green-600 { color: color-contrast($green-600); background-color: $green-600; }
79+
.bd-green-700 { color: color-contrast($green-700); background-color: $green-700; }
80+
.bd-green-800 { color: color-contrast($green-800); background-color: $green-800; }
81+
.bd-green-900 { color: color-contrast($green-900); background-color: $green-900; }
82+
83+
.bd-teal-100 { color: color-contrast($teal-100); background-color: $teal-100; }
84+
.bd-teal-200 { color: color-contrast($teal-200); background-color: $teal-200; }
85+
.bd-teal-300 { color: color-contrast($teal-300); background-color: $teal-300; }
86+
.bd-teal-400 { color: color-contrast($teal-400); background-color: $teal-400; }
87+
.bd-teal-500 { color: color-contrast($teal-500); background-color: $teal-500; }
88+
.bd-teal-600 { color: color-contrast($teal-600); background-color: $teal-600; }
89+
.bd-teal-700 { color: color-contrast($teal-700); background-color: $teal-700; }
90+
.bd-teal-800 { color: color-contrast($teal-800); background-color: $teal-800; }
91+
.bd-teal-900 { color: color-contrast($teal-900); background-color: $teal-900; }
92+
93+
.bd-cyan-100 { color: color-contrast($cyan-100); background-color: $cyan-100; }
94+
.bd-cyan-200 { color: color-contrast($cyan-200); background-color: $cyan-200; }
95+
.bd-cyan-300 { color: color-contrast($cyan-300); background-color: $cyan-300; }
96+
.bd-cyan-400 { color: color-contrast($cyan-400); background-color: $cyan-400; }
97+
.bd-cyan-500 { color: color-contrast($cyan-500); background-color: $cyan-500; }
98+
.bd-cyan-600 { color: color-contrast($cyan-600); background-color: $cyan-600; }
99+
.bd-cyan-700 { color: color-contrast($cyan-700); background-color: $cyan-700; }
100+
.bd-cyan-800 { color: color-contrast($cyan-800); background-color: $cyan-800; }
101+
.bd-cyan-900 { color: color-contrast($cyan-900); background-color: $cyan-900; }
102+
103+
.bd-gray-100 { color: color-contrast($gray-100); background-color: $gray-100; }
104+
.bd-gray-200 { color: color-contrast($gray-200); background-color: $gray-200; }
105+
.bd-gray-300 { color: color-contrast($gray-300); background-color: $gray-300; }
106+
.bd-gray-400 { color: color-contrast($gray-400); background-color: $gray-400; }
107+
.bd-gray-500 { color: color-contrast($gray-500); background-color: $gray-500; }
108+
.bd-gray-600 { color: color-contrast($gray-600); background-color: $gray-600; }
109+
.bd-gray-700 { color: color-contrast($gray-700); background-color: $gray-700; }
110+
.bd-gray-800 { color: color-contrast($gray-800); background-color: $gray-800; }
111+
.bd-gray-900 { color: color-contrast($gray-900); background-color: $gray-900; }
112+
113+
.bd-white { color: color-contrast($white); background-color: $white; border: 2px solid $body-color;}
114+
.bd-black { color: color-contrast($black); background-color: $black; }
115+
.bd-foreground { color: $body-bg; background-color: $body-color; }
116+
.bd-background { color: $body-color; background-color: $body-bg; border: 2px solid $body-color;}

examples/brand/app-express.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
from shiny.express import input, render, ui
2+
3+
ui.page_opts(theme=ui.Theme.from_brand(__file__))
4+
5+
ui.input_slider("n", "N", 0, 100, 20)
6+
7+
8+
@render.code
9+
def txt():
10+
return f"n*2 is {input.n() * 2}"

0 commit comments

Comments
 (0)