From 9a3ec0658e0faf5869218376d845efffe3170073 Mon Sep 17 00:00:00 2001 From: Matthew Buckett Date: Thu, 25 Jan 2024 14:33:51 +0000 Subject: [PATCH] AB#71917 Fix LTIApplyTheme when a URL is defined. If the `url` prop is defined it wasn't setting the theme correctly. This also adds an example theme file which makes it easy to tell when it's loaded the theme ok. --- .storybook/main.js | 2 + public/theme-vars.json | 59 ++++++++++++++++++ src/components/applyTheme/LtiApplyTheme.js | 60 ++++++++++--------- .../applyTheme/LtiApplyTheme.stories.js | 35 ++++++++++- 4 files changed, 126 insertions(+), 30 deletions(-) create mode 100644 public/theme-vars.json diff --git a/.storybook/main.js b/.storybook/main.js index 1340f88..a35d284 100644 --- a/.storybook/main.js +++ b/.storybook/main.js @@ -21,4 +21,6 @@ module.exports = { features: { storyStoreV7: false, }, + + staticDirs: ['../public'], } \ No newline at end of file diff --git a/public/theme-vars.json b/public/theme-vars.json new file mode 100644 index 0000000..4e1dcf5 --- /dev/null +++ b/public/theme-vars.json @@ -0,0 +1,59 @@ +{ + "ic-brand-primary-darkened-5": "#076B9B", + "ic-brand-primary-darkened-10": "#076593", + "ic-brand-primary-darkened-15": "#06608B", + "ic-brand-primary-lightened-5": "#1377A7", + "ic-brand-primary-lightened-10": "#1F7EAC", + "ic-brand-primary-lightened-15": "#2C85B0", + "ic-brand-button--primary-bgd-darkened-5": "#076B9B", + "ic-brand-button--primary-bgd-darkened-15": "#06608B", + "ic-brand-button--secondary-bgd-darkened-5": "#2B3942", + "ic-brand-button--secondary-bgd-darkened-15": "#27333B", + "ic-brand-font-color-dark-lightened-15": "#4C5860", + "ic-brand-font-color-dark-lightened-30": "#6C757C", + "ic-link-color-darkened-10": "#006897", + "ic-link-color-lightened-10": "#1981AF", + "ic-brand-primary": "#111", + "ic-brand-font-color-dark": "#2D3B45", + "ic-link-color": "#0073A7", + "ic-brand-button--primary-bgd": "#0770A3", + "ic-brand-button--primary-text": "#ffffff", + "ic-brand-button--secondary-bgd": "#2D3B45", + "ic-brand-button--secondary-text": "#ffffff", + "ic-brand-global-nav-bgd": "#394B58", + "ic-brand-global-nav-ic-icon-svg-fill": "#ffffff", + "ic-brand-global-nav-ic-icon-svg-fill--active": "#0770A3", + "ic-brand-global-nav-menu-item__text-color": "#ffffff", + "ic-brand-global-nav-menu-item__text-color--active": "#0073A7", + "ic-brand-global-nav-avatar-border": "#ffffff", + "ic-brand-global-nav-menu-item__badge-bgd": "#ffffff", + "ic-brand-global-nav-menu-item__badge-bgd--active": "#0770A3", + "ic-brand-global-nav-menu-item__badge-text": "#000000", + "ic-brand-global-nav-menu-item__badge-text--active": "#ffffff", + "ic-brand-global-nav-logo-bgd": "#394B58", + "ic-brand-header-image": "/dist/images/canvas_logomark_only@2x-e197434829.png", + "ic-brand-mobile-global-nav-logo": "/dist/images/mobile-global-nav-logo-aff8453309.svg", + "ic-brand-watermark": "", + "ic-brand-watermark-opacity": "1.0", + "ic-brand-favicon": "/dist/images/favicon-e10d657a73.ico", + "ic-brand-apple-touch-icon": "/dist/images/apple-touch-icon-585e5d997d.png", + "ic-brand-msapplication-tile-color": "#0770A3", + "ic-brand-msapplication-tile-square": "/dist/images/windows-tile-eda8889e7b.png", + "ic-brand-msapplication-tile-wide": "/dist/images/windows-tile-wide-44d3cc1060.png", + "ic-brand-right-sidebar-logo": "", + "ic-brand-Login-body-bgd-color": "#394B58", + "ic-brand-Login-body-bgd-image": "", + "ic-brand-Login-body-bgd-shadow-color": "#2D3B45", + "ic-brand-Login-logo": "/dist/images/login/canvas-logo-5617606953.svg", + "ic-brand-Login-Content-bgd-color": "none", + "ic-brand-Login-Content-border-color": "none", + "ic-brand-Login-Content-inner-bgd": "none", + "ic-brand-Login-Content-inner-border": "none", + "ic-brand-Login-Content-inner-body-bgd": "none", + "ic-brand-Login-Content-inner-body-border": "none", + "ic-brand-Login-Content-label-text-color": "#ffffff", + "ic-brand-Login-Content-password-text-color": "#ffffff", + "ic-brand-Login-footer-link-color": "#ffffff", + "ic-brand-Login-footer-link-color-hover": "#ffffff", + "ic-brand-Login-instructure-logo": "#ffffff" +} \ No newline at end of file diff --git a/src/components/applyTheme/LtiApplyTheme.js b/src/components/applyTheme/LtiApplyTheme.js index d208379..42602b8 100644 --- a/src/components/applyTheme/LtiApplyTheme.js +++ b/src/components/applyTheme/LtiApplyTheme.js @@ -21,8 +21,8 @@ export class LtiApplyTheme extends React.Component { static defaultProps = { url: null, - highContrast: true, - maxRetries: 0 + highContrast: false, + maxRetries: 1 } loading = false @@ -31,35 +31,41 @@ export class LtiApplyTheme extends React.Component { } componentDidMount() { - this.loadTheme(0) + this.loadTheme() } - loadTheme = (retries) => { - if (!this.loading) { - this.loading = true - let newTheme - if (this.props.url) { - fetch(this.props.url) - .then(response => { - if (!response.ok) { - if (retries < this.props.maxRetries) { - this.loadTheme(retries + 1) - } else { + /** + * This fetches the custom theme variables for the instance. + */ + fetchVariables = async () => { + if (this.props.url) { + for (let attempt = 0; attempt <= this.props.maxRetries; attempt++) { + try { + const variables = await fetch(this.props.url) + .then(response => { + if (!response.ok) { throw new Error('Error loading theme (status: ' + response.status + ')') } - } - return response - }) - .then(response => response.json()) - .then((json) => { - // Apply the loaded theme. - newTheme = this.props.highContrast ? canvasHighContrast : { ...canvas, ...json } - }).catch(error => { - console.warn('Loading of theme ' + this.props.url + ' failed: ' + error) - }) - } else { - newTheme = this.props.highContrast ? canvasHighContrast : canvas + return response + }) + .then(response => response.json()) + return variables + } catch (e) { + console.warn('Loading of theme ' + this.props.url + ' failed: ' + e) + } } + console.warn('Giving up loading theme'); + } + return {} + } + + loadTheme = async () => { + console.debug('Loading theme') + if (!this.loading) { + this.loading = true + let newTheme + const variables = await this.fetchVariables() + newTheme = this.props.highContrast ? canvasHighContrast : { ...canvas, ...variables } this.setState({theme: newTheme}) this.loading = false } @@ -69,7 +75,7 @@ export class LtiApplyTheme extends React.Component { if (this.props.url !== prevProps.url || this.props.highContrast !== prevProps.highContrast ) { - this.loadTheme(0) + this.loadTheme() } } diff --git a/src/components/applyTheme/LtiApplyTheme.stories.js b/src/components/applyTheme/LtiApplyTheme.stories.js index af73925..68d69e4 100644 --- a/src/components/applyTheme/LtiApplyTheme.stories.js +++ b/src/components/applyTheme/LtiApplyTheme.stories.js @@ -11,10 +11,16 @@ export default { argTypes: { highContrast: { control: 'boolean' + }, + url: { + control: 'text' + }, + maxRetries: { + control: 'number' } }, - render: ({ highContrast }) => ( - + render: ( props ) => ( +
@@ -22,8 +28,13 @@ export default { + {/*The warning colour is different between normal and high contrast*/} - LtiApplyTheme test + Warning Text + + {/*The brand text is easy to re-colour in the theme variables*/} + + Brand Text
@@ -32,4 +43,22 @@ export default { export const NoArgs = { args: {} +} + +export const HighContrast = { + args: { + highContrast: true + } +} + +export const BadUrl = { + args: { + url: '/does/not/work' + } +} + +export const LoadingTheme = { + args: { + url: '/theme-vars.json' + } } \ No newline at end of file