Skip to content

Commit a658f31

Browse files
committed
fixup! feat!: Paragon 23 and External CSS support
1 parent e08c07a commit a658f31

File tree

6 files changed

+33
-71
lines changed

6 files changed

+33
-71
lines changed
-1.47 MB
Binary file not shown.

docs/how_tos/theming.md

Lines changed: 22 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
>
1010
> Information on the design tokens project:
1111
>
12-
> - <https://github.com/openedx/paragon/blob/master/docs/decisions/0019-scaling-styles-with-design-tokens.rst>
13-
> - <https://github.com/openedx/paragon/tree/alpha?tab=readme-ov-file#design-tokens>
12+
> - <https://github.com/openedx/paragon/blob/release-23.x/docs/decisions/0019-scaling-styles-with-design-tokens.rst>
13+
> - <https://github.com/openedx/paragon/tree/release-23.x?tab=readme-ov-file#design-tokens>
1414
1515
## Overview
1616

@@ -19,19 +19,20 @@ theming with Paragon by loading branded CSS externally (e.g., from a CDN).
1919

2020
To do this, configured URLs pointing to relevant CSS files from
2121
`@openedx/brand-openedx` are loaded and injected to the HTML document at
22-
runtime. This differs from importing the styles from `@openedx/brand-openedx`
23-
directly, which includes these styles in the application's production assets.
22+
runtime. This differs from the deprecated method of importing the styles from
23+
`@openedx/brand-openedx` directly, which includes these styles in the
24+
application's production assets.
2425

2526
This override mechanism works by compiling the design tokens defined in
2627
`@openedx/brand-openedx` with the core Paragon tokens to generate overrides to
2728
Paragon's default CSS variables and then compiling the output CSS with any SCSS
2829
theme customizations not possible through a design token override.
2930

3031
The CSS urls for `@openedx/brand-openedx` overrides will be applied after the
31-
core Paragon theme urls load, thus overriding any previously set CSS variables
32+
Paragon base styles load, thus overriding any previously set CSS variables
3233
and/or styles.
3334

34-
By serving brand CSS loaded externally, consuming applications of Paragon no
35+
By loading a theme's CSS externally, consuming applications of Paragon no
3536
longer need to be responsible for compiling the brand SCSS to CSS themselves
3637
and instead use a pre-compiled CSS file. In doing so, this allows making
3738
changes to the site theme without needing to necessarily re-build and re-deploy
@@ -68,51 +69,42 @@ supports having multiple or alternative `light` and/or `dark` theme variants.
6869
You can see the [Configuration options](#configuration-options) example for
6970
better understanding.
7071

71-
## Technical architecture
72-
73-
![overview of paragon theme loader](./images/paragon-theme-loader.png "Paragon theme loader")
74-
7572
## Development
7673

7774
### Configuration options
7875

79-
To enable `@openedx/brand-openedx` overrides, the `paragonThemeUrls` site
76+
To enable `@openedx/brand-openedx` overrides, the `theme` site
8077
configuration setting may be configured with the following:
8178

8279
| Property | Data Type | Description |
8380
| ----------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------- |
8481
| `core` | Object | Metadata about the core styles from `@openedx/brand-openedx`. |
85-
| `core.urls` | Object | URL(s) for the `core.css` files from `@openedx/brand-openedx`. |
86-
| `core.urls.brandOverride` | String | URL for the `core.css` file from `@openedx/brand-openedx`. |
82+
| `core.url` | String | URL for the `core.css` file from `@openedx/brand-openedx`. |
8783
| `defaults` | Object | Mapping of theme variants to Paragon's default supported light and dark theme variants. |
8884
| `defaults.light` | String | Default `light` theme variant from the theme variants in the `variants` object. |
8985
| `defaults.dark` | String | Default `dark` theme variant from the theme variants in the `variants` object. |
9086
| `variants` | Object | Metadata about each supported theme variant. |
9187
| `variants.light` | Object | Metadata about the light theme variant styles from `@openedx/brand-openedx`. |
92-
| `variants.light.urls` | Object | URL(s) for the `light.css` files from `@openedx/brand-openedx`. |
93-
| `variants.light.urls.brandOverride` | String | URL for the `light.css` file from `@openedx/brand-openedx`. |
88+
| `variants.light.url` | String | URL for the `light.css` file from `@openedx/brand-openedx`. |
9489
| `variants.dark` | Object | Metadata about the dark theme variant styles from `@openedx/brand-openedx`. |
95-
| `variants.dark.urls` | Object | URL(s) for the `dark.css` files from `@openedx/brand-openedx`. |
96-
| `variants.dark.urls.brandOverride` | String | URL for the `dark.css` file from `@openedx/brand-openedx`. |
90+
| `variants.dark.url` | String | URL for the `dark.css` file from `@openedx/brand-openedx`. |
9791

98-
The `dark` theme variant options are optional.
92+
The `dark` theme variant is optional.
9993

10094
A simple example:
10195

10296
```ts
10397
const siteConfig: SiteConfig = {
104-
paragonThemeUrls: {
98+
theme: {
10599
core: {
106-
urls: {
107-
brandOverride: "https://cdn.jsdelivr.net/npm/@my-brand/[email protected]/dist/core.min.css",
108-
},
100+
url: "https://cdn.jsdelivr.net/npm/@my-org/[email protected]/dist/core.min.css",
109101
},
110102
defaults: {
111103
light: "light",
112104
},
113105
variants: {
114106
light: {
115-
brandOverride: "https://cdn.jsdelivr.net/npm/@my-brand/brand[email protected]/dist/light.min.css",
107+
url: "https://cdn.jsdelivr.net/npm/@my-org/theme[email protected]/dist/light.min.css",
116108
},
117109
},
118110
},
@@ -125,41 +117,29 @@ A complete example, including custom variants:
125117
const siteConfig: SiteConfig = {
126118
paragonThemeUrls: {
127119
core: {
128-
urls: {
129-
brandOverride: "https://cdn.jsdelivr.net/npm/@my-brand/[email protected]/dist/core.min.css",
130-
},
120+
url: "https://cdn.jsdelivr.net/npm/@my-org/[email protected]/dist/core.min.css",
131121
},
132122
defaults: {
133123
light: "light",
134124
dark: "dark",
135125
},
136126
variants: {
137127
light: {
138-
urls: {
139-
brandOverride: "https://cdn.jsdelivr.net/npm/@my-brand/[email protected]/dist/light.min.css",
140-
},
128+
url: "https://cdn.jsdelivr.net/npm/@my-org/[email protected]/dist/light.min.css",
141129
},
142-
// Configure optional dark mode
130+
// Optional dark mode
143131
dark: {
144-
urls: {
145-
brandOverride: "https://cdn.jsdelivr.net/npm/@my-brand/[email protected]/dist/dark.min.css",
146-
},
132+
url: "https://cdn.jsdelivr.net/npm/@my-org/[email protected]/dist/dark.min.css",
147133
},
148134
// Configure any extra theme using a custom @openedx/brand-openedx package
149135
green: {
150-
urls: {
151-
brandOverride: "https://cdn.jsdelivr.net/npm/@my-brand/[email protected]/dist/green.min.css",
152-
},
136+
url: "https://cdn.jsdelivr.net/npm/@my-org/[email protected]/dist/green.min.css",
153137
},
154138
red: {
155-
urls: {
156-
brandOverride: "https://cdn.jsdelivr.net/npm/@my-brand/[email protected]/dist/red.min.css",
157-
},
139+
url: "https://cdn.jsdelivr.net/npm/@my-org/[email protected]/dist/red.min.css",
158140
},
159141
"high-contrast-dark": {
160-
urls: {
161-
brandOverride: "https://cdn.jsdelivr.net/npm/@my-brand/[email protected]/dist/high-contrast-dark.min.css",
162-
},
142+
url: "https://cdn.jsdelivr.net/npm/@my-org/[email protected]/dist/high-contrast-dark.min.css",
163143
},
164144
},
165145
},

runtime/react/hooks/paragon/useParagonTheme.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,17 @@ const useParagonTheme = () => {
112112
};
113113
const [themeState, dispatch] = useReducer(paragonThemeReducer, initialParagonThemeState);
114114

115-
const [isCoreThemeLoaded, setIsCoreThemeLoaded] = useState(false);
115+
const [isThemeCoreLoaded, setIsthemeCoreLoaded] = useState(false);
116116
const onLoadThemeCore = useCallback(() => {
117-
setIsCoreThemeLoaded(true);
117+
setIsthemeCoreLoaded(true);
118118
}, []);
119119

120120
const [hasLoadedThemeVariants, setHasLoadedThemeVariants] = useState(false);
121121
const onLoadThemeVariants = useCallback(() => {
122122
setHasLoadedThemeVariants(true);
123123
}, []);
124124

125-
// load the core theme CSS
125+
// load the theme's core CSS
126126
useParagonThemeCore({
127127
themeCore,
128128
onComplete: onLoadThemeCore,
@@ -165,15 +165,15 @@ const useParagonTheme = () => {
165165
}
166166

167167
// Return early if neither the core theme CSS nor any theme variant CSS is loaded.
168-
if (!isCoreThemeLoaded || !hasLoadedThemeVariants) {
168+
if (!isThemeCoreLoaded || !hasLoadedThemeVariants) {
169169
return;
170170
}
171171

172172
// All application theme URLs are loaded
173173
dispatch(paragonThemeActions.setParagonThemeLoaded(true));
174174
}, [
175175
themeState.isThemeLoaded,
176-
isCoreThemeLoaded,
176+
isThemeCoreLoaded,
177177
hasLoadedThemeVariants,
178178
themeCore?.urls,
179179
themeVariants,

runtime/react/hooks/paragon/useParagonThemeCore.ts

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,9 @@ import { logError } from '../../../logging';
44
import { removeExistingLinks } from './utils';
55

66
/**
7-
* Custom React hook that manages the loading and updating of the core Paragon theme CSS and the brand override
8-
* theme CSS. It ensures that the core theme CSS (both default and brand override) is added to the document
9-
* `<head>` as `<link>` elements.
10-
*
11-
* The function logs and handles fallback logic in case the core theme fails to load.
12-
*
13-
* @memberof module:React
14-
*
15-
* @param {Object} args - The arguments object containing theme and callback information.
16-
* @param {Object} args.themeCore - The core theme configuration.
17-
* @param {string} [args.themeCore.urls.brandOverride] - The URL to the brand override theme CSS (optional).
18-
* @param {Function} args.onComplete - A callback function that is called once both the core Paragon (default)
19-
* theme and brand override theme (if provided) are complete.
7+
* Custom React hook that manages the loading and updating of a theme's core
8+
* CSS, ensuring the theme's core CSS is added to the document `<head>` as a
9+
* `<link>` element.
2010
*/
2111
const useParagonThemeCore = ({
2212
themeCore,
@@ -37,15 +27,6 @@ const useParagonThemeCore = ({
3727
return;
3828
}
3929

40-
const brandCoreLink: HTMLAnchorElement | null = document.head.querySelector(`link[href='${themeCore.urls.brandOverride}']`);
41-
if (brandCoreLink) {
42-
brandCoreLink.rel = 'stylesheet';
43-
brandCoreLink.removeAttribute('as');
44-
brandCoreLink.dataset.brandThemeCore = 'true';
45-
setIsBrandThemeCoreComplete(true);
46-
return;
47-
}
48-
4930
if (themeCore.urls.brandOverride) {
5031
const brandCoreThemeLink = document.createElement('link');
5132
brandCoreThemeLink.href = themeCore.urls.brandOverride;

runtime/testing/mockMessages.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const messages = {
1818
ru: {},
1919
th: {},
2020
uk: {},
21+
vi: {},
2122
};
2223

2324
export default messages;

shell/app.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
@use "@openedx/paragon/dist/core.min.css" as paragonCore;
2-
@use "@openedx/paragon/dist/light.min.css" as paragonLight;
1+
@use "@openedx/paragon/dist/core.min.css";
2+
@use "@openedx/paragon/dist/light.min.css";
33

44
.flex-basis-0 {
55
flex-basis: 0 !important;

0 commit comments

Comments
 (0)