Skip to content

Commit

Permalink
Merge pull request #421 from sitevision/ENV-279-Envision-for-Dashboar…
Browse files Browse the repository at this point in the history
…d-Widgets

Env 279 envision for dashboard widgets
  • Loading branch information
henrikekelof authored Dec 15, 2023
2 parents 9e7f128 + f089a42 commit 3fe7d1d
Show file tree
Hide file tree
Showing 20 changed files with 1,506 additions and 8 deletions.
12 changes: 12 additions & 0 deletions packages/envision-docs/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ module.exports = {
title: 'Getting started',
slug: 'getting-started',
},
{
title: 'Dashboard',
slug: 'dashboard',
},
{
title: 'Branding',
slug: 'ui',
Expand Down Expand Up @@ -50,6 +54,13 @@ module.exports = {
superscript_types: /(SuperType)/,
},
},
{
language: 'css-no-expand',
extend: 'css',
definition: {
superscript_types: /(SuperType)/,
},
},
{
language: 'js-no-expand',
extend: 'javascript',
Expand Down Expand Up @@ -79,6 +90,7 @@ module.exports = {
list: 'doc-list',
listItem: 'doc-list__item',
image: 'doc-image',
table: 'doc-table',
},
},
},
Expand Down
5 changes: 3 additions & 2 deletions packages/envision-docs/src/components/Header/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import PropTypes from 'prop-types';
import Link from '../Link';
import ThemePicker from '../ThemePicker';

const Header = ({ title, menuItems }) => {
const Header = ({ title, bodyClass, menuItems }) => {
return (
<>
<Helmet>
<Helmet bodyAttributes={{ class: bodyClass }}>
<html lang="en" className="sv-js" />
<meta charset="utf-8" />
<meta
Expand Down Expand Up @@ -54,6 +54,7 @@ const Header = ({ title, menuItems }) => {

Header.propTypes = {
title: PropTypes.string,
bodyClass: PropTypes.string,
menuItems: PropTypes.array,
};

Expand Down
3 changes: 3 additions & 0 deletions packages/envision-docs/src/components/Theme/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ const ThemeProvider = ({ children }) => {
}, []);

React.useEffect(() => {
if (document.body.classList.contains('env-dashboard-theme')) {
return;
}
let oldTheme = window.localStorage.getItem('env-theme');
document.body.classList.remove(oldTheme);
if (theme) {
Expand Down
58 changes: 58 additions & 0 deletions packages/envision-docs/src/hooks/colorUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
const WCAG_CONTRAST_RATIO = {
AA_LARGE: 1 / 3,
AA_NORMAL: 1 / 4.5,
AAA_LARGE: 1 / 4.5,
AAA_NORMAL: 1 / 7,
};

export const DASHBOARD_COLORS = [
'red',
'pink',
'purple',
'deep-purple',
'indigo',
'blue',
'light-blue',
'cyan',
'teal',
'green',
'light-green',
'lime',
'yellow',
'orange',
'brown',
'gray',
];
export const DASHBOARD_COLOR_VARIANTS = ['05', '20', '50', '90'];

export const passesWCAG = (ratio, level) => {
level = level || WCAG_CONTRAST_RATIO.AA_NORMAL;
return 1 / ratio < level;
};

const hexToRgb = (hex) => {
const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
const rgbRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i;
hex = hex.replace(shorthandRegex, function (m, r, g, b) {
return r + r + g + g + b + b;
});
const result = rgbRegex.exec(hex);
const r = parseInt(result[1], 16);
const g = parseInt(result[2], 16);
const b = parseInt(result[3], 16);
return result ? [r, g, b] : null;
};

const luminance = (rgb) => {
const a = rgb.map(function (v) {
v /= 255;
return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
};

export const getContrastRatio = (hex1, hex2) => {
const lum1 = luminance(hexToRgb(hex1));
const lum2 = luminance(hexToRgb(hex2));
return (Math.max(lum1, lum2) + 0.05) / (Math.min(lum1, lum2) + 0.05);
};
29 changes: 29 additions & 0 deletions packages/envision-docs/src/hooks/copyExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,35 @@ export const useCopyExample = (content) => {
});
});

// Wrap Dashboard specific Envision styling
// so it doesn't leak into other doc pages.
const DASHBOARD_THEME = 'env-dashboard-theme';
const wrapDashboardRule = (s) => {
const a = s.split(',');
a.forEach((s2, i) => {
a[i] = `.${DASHBOARD_THEME} ${s2}`.replace(/\s\s+/g, ' ');
});
return a.join(', ');
};

for (let i = 0; i < document.styleSheets.length; i++) {
if (document.styleSheets[i].href.includes('dashboard')) {
const ruleList = document.styleSheets[i].cssRules;
for (let j = 0; j < ruleList.length; j++) {
if (ruleList[j].selectorText.includes('p.env-text')) {
if (!ruleList[j].selectorText.includes(DASHBOARD_THEME)) {
ruleList[j].selectorText = wrapDashboardRule(
ruleList[j].selectorText
);
}
break;
}
}

break;
}
}

// To initialize Image slider examples,
// load method must be triggered again in gatsby.
window.dispatchEvent(new Event('load'));
Expand Down
85 changes: 85 additions & 0 deletions packages/envision-docs/src/hooks/dashboardExample.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import * as React from 'react';
import {
DASHBOARD_COLOR_VARIANTS,
DASHBOARD_COLORS,
getContrastRatio,
passesWCAG,
} from './colorUtils';
import { toTitleCase } from './demoUtils';

const TEXT_CONTRAST_ICON =
'<svg class="env-icon example-dashboard-color-list-icon">' +
'<use xlink:href="/images/docs-icons.svg#text"></use></svg>';

const listItem = (options) => {
const o = Object.assign({}, options);
return `<li class="env-dashboard-color-bg-${o.bgClassName} env-dashboard-color-txt-${o.txtClassName}">
<div><span>${o.name}</span>
<span>${o.hex}</span>
</div></li>`;
};

export const useDashboardExample = (content) => {
React.useEffect(() => {
const colorList = document.getElementById('dashboard-color-list');
if (colorList) {
const compStyleBody = getComputedStyle(document.body);
const bodyBgColor = compStyleBody.getPropertyValue(
`--env-dashboard-color-gray-05`
);
const blackColor = compStyleBody.getPropertyValue(
`--env-dashboard-color-black`
);
const whiteColor = compStyleBody.getPropertyValue(
`--env-dashboard-color-white`
);

DASHBOARD_COLORS.forEach((colorName) => {
const gridEl = document.createElement('div');
gridEl.innerHTML = `<h2 class="env-ui-text-subheading">${toTitleCase(
colorName.replace('-', ' ')
)}</h2>`;

const listEl = document.createElement('ul');
listEl.classList.add('example-dashboard-color-list');

DASHBOARD_COLOR_VARIANTS.forEach((variantName) => {
let txtClassName = 'black';
let variantText = variantName;
const bgClassName = `${colorName}-${variantName}`;
const bgColor = compStyleBody.getPropertyValue(
`--env-dashboard-color-${colorName}-${variantName}`
);

if (bgColor) {
const contrastBody = getContrastRatio(bgColor, bodyBgColor);
const contrastSection = getContrastRatio(bgColor, whiteColor);
const passesAAonWhite = passesWCAG(contrastSection);
const passesAAonBody = passesWCAG(contrastBody);
const canHaveBlackText = passesWCAG(
getContrastRatio(blackColor, bgColor)
);
if (!canHaveBlackText) {
txtClassName = 'white';
}
if (passesAAonWhite) {
variantText += TEXT_CONTRAST_ICON;
if (passesAAonBody) {
variantText += '*';
}
}
}

listEl.innerHTML += listItem({
bgClassName: bgClassName,
txtClassName: txtClassName,
name: variantText,
hex: bgColor,
});
});
gridEl.appendChild(listEl);
colorList.appendChild(gridEl);
});
}
}, [content]);
};
9 changes: 9 additions & 0 deletions packages/envision-docs/src/hooks/demoUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export const toTitleCase = (str) => {
return str
.toLowerCase()
.split(' ')
.map(function (word) {
return word.charAt(0).toUpperCase() + word.slice(1);
})
.join(' ');
};
Loading

0 comments on commit 3fe7d1d

Please sign in to comment.