theme-vir
Version:
Create an entire web theme.
274 lines (262 loc) • 11.3 kB
JavaScript
import { check } from '@augment-vir/assert';
import { VirColorPair } from '@electrovir/color';
import { defineBookPage } from 'element-book';
import { css, html, listen, unsafeCSS } from 'element-vir';
import { noNativeSpacing, viraTheme } from 'vira';
import { buildColorTheme, groupColors, } from './build-color-theme.js';
import { createColorThemeBookPages } from './color-theme-book-pages.js';
import { themeDefaultKey } from './color-theme.js';
const blackWhiteCells = [
{
title: 'Black',
fontWeight: 400,
foreground: viraTheme.colors[themeDefaultKey].foreground,
},
{
title: 'Black',
fontWeight: 700,
foreground: viraTheme.colors[themeDefaultKey].foreground,
},
{
title: 'White',
fontWeight: 400,
foreground: viraTheme.colors[themeDefaultKey].background,
},
{
title: 'White',
fontWeight: 700,
foreground: viraTheme.colors[themeDefaultKey].background,
},
{
title: 'Black',
fontWeight: 400,
background: viraTheme.colors[themeDefaultKey].foreground,
},
{
title: 'Black',
fontWeight: 700,
background: viraTheme.colors[themeDefaultKey].foreground,
},
{
title: 'White',
fontWeight: 400,
background: viraTheme.colors[themeDefaultKey].background,
},
{
title: 'White',
fontWeight: 700,
background: viraTheme.colors[themeDefaultKey].background,
},
];
/**
* Create multiple element-book pages to showcase a bunch of color CSS variables.
*
* @category Color Theme
* @see `createColorThemeBookPages` for creating full color theme pages.
*/
export function createColorPaletteBookPages({ colors, parent, title, includeContrast, includeTheme, useVerticalTheme, options, }) {
const colorGroups = groupColors(colors);
const topColorsPage = defineBookPage({
parent,
title,
});
const colorPalettePage = defineBookPage({
parent: topColorsPage,
title: 'Palette',
defineExamples({ defineExample }) {
defineExample({
title: 'All Colors',
styles: css `
:host {
display: flex;
flex-direction: row;
}
p {
${noNativeSpacing}
}
.color-column {
display: flex;
flex-direction: column;
}
.column-title {
text-align: center;
font-size: 12px;
padding-bottom: 4px;
border-bottom: 1px solid
${viraTheme.colors['vira-grey-foreground-decoration'].foreground.value};
margin-bottom: 4px;
color: ${viraTheme.colors['vira-grey-foreground-non-body'].foreground
.value};
}
.swatch-wrapper {
display: flex;
gap: 4px;
align-items: center;
& .swatch {
width: 50px;
height: 50px;
cursor: pointer;
}
& .color-details {
display: none;
font-family: monospace;
font-size: 12px;
color: ${viraTheme.colors['vira-grey-foreground-non-body'].foreground
.value};
}
&.expanded .color-details {
display: block;
}
& .color-value {
margin-left: 1ch;
}
}
`,
render() {
return Object.entries(colorGroups).map(([groupName, colors,]) => {
return html `
<div class="color-column">
<p class="column-title">${groupName}</p>
${colors.map((color) => {
return html `
<div class="swatch-wrapper">
<div
class="swatch"
style=${css `
background-color: ${unsafeCSS(color.definition.default)};
`}
${listen('click', (event) => {
const wrapper = event.currentTarget.parentElement;
wrapper?.classList.toggle('expanded');
})}
></div>
<p class="color-details">
<span>${color.cssVarName}</span>
<br />
<span class="color-value">
${color.definition.default}
</span>
</p>
</div>
`;
})}
</div>
`;
});
},
});
},
});
const contrastsPage = defineBookPage({
parent: topColorsPage,
title: 'Palette Contrast',
});
function createContrastPage(contrastPageTitle, contrastCellsInput) {
return defineBookPage({
parent: contrastsPage,
title: `${title} ${contrastPageTitle}`,
defineExamples({ defineExample }) {
Object.entries(colorGroups).forEach(([groupName, colors,]) => {
const contrastCells = check.isArray(contrastCellsInput)
? contrastCellsInput
: contrastCellsInput(colors);
defineExample({
title: groupName,
styles: css `
:host {
display: flex;
flex-direction: column;
gap: 24px;
}
p {
${noNativeSpacing}
}
.darkness-level {
text-align: center;
font-size: 12px;
color: ${viraTheme.colors['vira-grey-foreground-header']
.foreground.value};
}
td {
padding: 4px;
min-width: 170px;
}
`,
render() {
const colorRowTemplates = colors.map((color) => {
const cellTemplates = contrastCells.map((cell) => {
return html `
<td>
<p class="darkness-level">${color.suffix}</p>
<${VirColorPair.assign({
color: {
background: cell.background || color.definition,
foreground: cell.foreground || color.definition,
},
showVarValues: true,
showVarNames: false,
showContrast: true,
fontWeight: cell.fontWeight,
})}></${VirColorPair}>
</td>
`;
});
return html `
<tr>${cellTemplates}</tr>
`;
});
const headerCells = contrastCells.map((cell) => {
const layerText = cell.background ? 'in back' : 'in front';
const title = [
cell.title,
`(${layerText})`,
`(${cell.fontWeight})`,
].join(' ');
return html `
<th>${title}</th>
`;
});
return html `
<table cellspacing="0" cellpadding="0">
<thead><tr>${headerCells}</tr></thead>
<tbody>${colorRowTemplates}</tbody>
</table>
`;
},
});
});
},
});
}
const blackWhiteContrastPage = createContrastPage('Contrast Black White', blackWhiteCells);
function createSelfContrastPage(fontWeight) {
return createContrastPage(`Contrast Self ${fontWeight}`, (colors) => colors.map((color) => {
return {
fontWeight,
title: color.suffix || '',
foreground: color.definition,
};
}));
}
function createThemePages() {
const generatedTheme = buildColorTheme(colors, options);
return createColorThemeBookPages({
parent: topColorsPage,
title: 'Theme (auto)',
theme: generatedTheme.defaultLight,
hideInverseColors: true,
useVerticalLayout: useVerticalTheme,
prefixGroupByCount: 2,
overrides: [generatedTheme.darkOverride],
});
}
return [
topColorsPage,
colorPalettePage,
includeContrast ? contrastsPage : undefined,
includeContrast ? blackWhiteContrastPage : undefined,
includeContrast ? createSelfContrastPage(400) : undefined,
includeContrast ? createSelfContrastPage(700) : undefined,
...(includeTheme ? createThemePages() : []),
].filter(check.isTruthy);
}