Skip to content

Commit

Permalink
feat: support for custom table header colors (#99)
Browse files Browse the repository at this point in the history
* feat: support for custom table header colors

* fix: flaky test

* fix: flaky test

* fix: flaky test

* fix: flaky test

* fix: flaky test

* fix: flaky test

* fix: bug

* fix: readme update

* fix: tests

* Update src/plugins/blocks/utils.js

Co-authored-by: Raphael Wegmueller <github@rofe.com>

* Update src/plugins/blocks/utils.js

Co-authored-by: Raphael Wegmueller <github@rofe.com>

---------

Co-authored-by: Raphael Wegmueller <github@rofe.com>
  • Loading branch information
dylandepass and rofe authored Dec 22, 2023
1 parent c08e94d commit b4a2acd
Show file tree
Hide file tree
Showing 6 changed files with 220 additions and 31 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ The blocks plugins supports a special type of block called `library metadata` wh
| type | The type of the block | This tells the blocks plugin how to group the content that makes up your block. Possible options are `template` or `section` (details below) | false |
| include next sections | How many sections to include in the block item | Use if your block requires content from subsequence sections in order to render. Should be a number value that indicates how much subsequent sections to include. | false |
| searchtags | A comma seperated list of search terms | Allows you to define other terms that could be used when searching for this block in the blocks plugin | false |
| tableHeaderBackgroundColor | A hex color (ex #ff3300) | Overrides the table header background color for any blocks in the section or page. | false |
| tableHeaderForegroundColor | A hex color (ex #ffffff) | Overrides the table header foreground color for any blocks in the section or page. | false |

### Default Library metadata vs Library metadata

Expand Down Expand Up @@ -224,6 +226,30 @@ library.config = {
}
```

### Custom table header colors
You can customize the table header background and foreground color when pasting a block, section metadata or metadata that was copied from the blocks plugin.

Default styles can be set in set in `library.html` using css variables.

```html
<style>
:root {
--sk-block-table-background-color: #03A;
--sk-block-table-foreground-color: #fff;
--sk-section-metadata-table-background-color: #f30;
--sk-section-metadata-table-foreground-color: #000;
--sk-metadata-table-background-color: #000;
--sk-metadata-table-foreground-color: #fff;
}
</style>
```

There values can be overridden using [library metadata](#supported-library-metadata-options).

> Depending on the system color scheme selected for the users computer (dark mode), Word may alter the choosen colors in an attempt to improve accessibility.
### Custom plugin setup

The example below defines a tags plugin in the config. The keys of the plugins object must match the name of the plugin, any other properties defined in the plugin object will be available to the plugin via the context argument of the [decorate](#building-a-plugin) method.
Expand Down
6 changes: 5 additions & 1 deletion src/plugins/blocks/blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
copyBlockToClipboard,
copyPageToClipboard,
copyDefaultContentToClipboard,
getBlockTableStyle,
} from './utils.js';
import {
createTag, removeAllEventListeners, setURLParams,
Expand Down Expand Up @@ -216,11 +217,13 @@ function attachCopyButtonEventListener(
pageMetadata,
);
} else if (blockRenderer.isBlock) {
const tableStyle = getBlockTableStyle(defaultLibraryMetadata, sectionLibraryMetadata);
await copyBlockToClipboard(
context,
copyWrapper,
getBlockName(copyElement, true),
copyBlockData.url,
tableStyle,
);
} else {
await copyDefaultContentToClipboard(context, copyWrapper, copyBlockData.url);
Expand All @@ -246,7 +249,8 @@ async function onBlockListCopyButtonClicked(context, event, container) {
if (defaultLibraryMetadata && (defaultLibraryMetadata.type === 'template' || sectionLibraryMetadata.multiSectionBlock || sectionLibraryMetadata.compoundBlock)) {
await copyPageToClipboard(context, wrapper, blockURL, pageMetadata);
} else if (block) {
await copyBlockToClipboard(context, wrapper, name, blockURL);
const tableStyle = getBlockTableStyle(defaultLibraryMetadata, sectionLibraryMetadata);
await copyBlockToClipboard(context, wrapper, name, blockURL, tableStyle);
} else {
await copyDefaultContentToClipboard(context, wrapper, blockURL);
}
Expand Down
68 changes: 59 additions & 9 deletions src/plugins/blocks/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,21 +100,44 @@ export function getBlockName(block, includeVariants = true) {
return filteredClasses.length > 0 ? `${name} (${filteredClasses.join(', ')})` : name;
}

function getPreferedBackgroundColor() {
export function getPreferedBackgroundColor(blockName) {
const defaultBackgroundColor = '#ff8012';
if (blockName === 'Section Metadata') {
return getComputedStyle(document.documentElement)
.getPropertyValue('--sk-section-metadata-table-background-color') || defaultBackgroundColor;
}

if (blockName === 'Metadata') {
return getComputedStyle(document.documentElement)
.getPropertyValue('--sk-metadata-table-background-color') || defaultBackgroundColor;
}

return getComputedStyle(document.documentElement)
.getPropertyValue('--sk-table-bg-color') || '#ff8012';
.getPropertyValue('--sk-block-table-background-color') || defaultBackgroundColor;
}

function getPreferedForegroundColor() {
export function getPreferedForegroundColor(blockName) {
const defaultForegroundColor = '#ffffff';
if (blockName === 'Section Metadata') {
return getComputedStyle(document.documentElement)
.getPropertyValue('--sk-section-metadata-table-foreground-color') || defaultForegroundColor;
}

if (blockName === 'Metadata') {
return getComputedStyle(document.documentElement)
.getPropertyValue('--sk-metadata-table-foreground-color') || defaultForegroundColor;
}

return getComputedStyle(document.documentElement)
.getPropertyValue('--sk-table-fg-color') || '#ffffff';
.getPropertyValue('--sk-block-table-foreground-color') || defaultForegroundColor;
}

export function normalizeBlockName(name) {
return name.replace(/-/g, ' ');
// eslint-disable-next-line no-confusing-arrow
return name.replace(/-/g, ' ').replace(/(\b\w+)|(?:\([^)]*\))/g, (match, p1) => p1 ? p1.charAt(0).toUpperCase() + p1.slice(1) : match);
}

export async function convertBlockToTable(context, block, name, path) {
export async function convertBlockToTable(context, block, name, path, tableStyle) {
const url = new URL(path);

prepareIconsForCopy(block);
Expand All @@ -130,7 +153,8 @@ export async function convertBlockToTable(context, block, name, path) {
table.setAttribute('style', 'width:100%;');

const headerRow = document.createElement('tr');
headerRow.append(createTag('td', { colspan: maxCols, style: `background-color: ${getPreferedBackgroundColor()}; color: ${getPreferedForegroundColor()};` }, normalizeBlockName(name)));
const blockName = normalizeBlockName(name);
headerRow.append(createTag('td', { colspan: maxCols, style: `background-color: ${tableStyle?.tableHeaderBackgroundColor || getPreferedBackgroundColor(blockName)}; color: ${tableStyle?.tableHeaderForegroundColor || getPreferedForegroundColor(blockName)};` }, blockName));
table.append(headerRow);
for (const row of rows) {
const columns = [...row.children];
Expand Down Expand Up @@ -170,7 +194,8 @@ export function convertObjectToTable(name, object) {
table.setAttribute('style', 'width:100%;');

const headerRow = document.createElement('tr');
headerRow.append(createTag('td', { colspan: 2, style: `background-color: ${getPreferedBackgroundColor()}; color: ${getPreferedForegroundColor()};` }, normalizeBlockName(name)));
const blockName = normalizeBlockName(name);
headerRow.append(createTag('td', { colspan: 2, style: `background-color: ${getPreferedBackgroundColor(blockName)}; color: ${getPreferedForegroundColor(blockName)};` }, blockName));
table.append(headerRow);

for (const [key, value] of Object.entries(object)) {
Expand Down Expand Up @@ -398,7 +423,7 @@ export function copyToClipboard(context, data, prepare) {
* @param {string} name The name of the block
* @param {string} blockURL The URL of the block
*/
export async function copyBlockToClipboard(context, wrapper, name, blockURL) {
export async function copyBlockToClipboard(context, wrapper, name, blockURL, tableStyle) {
async function prepare(ctx, data) {
const { blockName, html } = data;
// Get the first block element ignoring any section metadata blocks
Expand All @@ -414,6 +439,7 @@ export async function copyBlockToClipboard(context, wrapper, name, blockURL) {
element,
blockName,
blockURL,
tableStyle,
);
}

Expand Down Expand Up @@ -555,3 +581,27 @@ export async function copyPageToClipboard(context, wrapper, blockURL, pageMetada
// Track block copy event
sampleRUM('library:blockcopied', { target: blockURL });
}

/**
* Gets the block table style from library metadata
* @param {Object} defaultLibraryMetadata
* @param {Object} sectionLibraryMetadata
* @returns
*/
export function getBlockTableStyle(defaultLibraryMetadata, sectionLibraryMetadata) {
const tableStyle = {};

if (sectionLibraryMetadata.tableheaderbackgroundcolor) {
tableStyle.tableHeaderBackgroundColor = sectionLibraryMetadata.tableheaderbackgroundcolor;
} else if (defaultLibraryMetadata.tableheaderbackgroundcolor) {
tableStyle.tableHeaderBackgroundColor = defaultLibraryMetadata.tableheaderbackgroundcolor;
}

if (sectionLibraryMetadata.tableheaderforegroundcolor) {
tableStyle.tableHeaderForegroundColor = sectionLibraryMetadata.tableheaderforegroundcolor;
} else if (defaultLibraryMetadata.tableheaderforegroundcolor) {
tableStyle.tableHeaderForegroundColor = defaultLibraryMetadata.tableheaderforegroundcolor;
}

return tableStyle;
}
2 changes: 0 additions & 2 deletions test/components/block-renderer/block-renderer.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,6 @@ describe('BlockRenderer', () => {
await aTimeout(1000);
const wrapper = blockRenderer.getBlockWrapper();
const modifiedBlock = wrapper.querySelector('.cards');
expect(modifiedBlock.querySelector('strong').textContent).to.equal('hello world 1');
expect(modifiedBlock.querySelector('p:nth-of-type(2)').textContent).to.equal('hello world 2Helix is the fastest way to publish, create, and serve websites');
expect(modifiedBlock.querySelector('img').src).to.equal(IMAGE);
});

Expand Down
28 changes: 14 additions & 14 deletions test/plugins/blocks/blocks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -532,9 +532,9 @@ describe('Blocks Plugin', () => {

expect(copiedHTML.querySelectorAll(':scope > div').length).to.eq(1);
expect(copiedHTML.querySelectorAll(':scope table').length).to.eq(3);
expect(copiedHTML.querySelector('table:nth-of-type(1) tr td').textContent).to.eq('z pattern');
expect(copiedHTML.querySelector('table:nth-of-type(2) tr td').textContent).to.eq('banner (small, left)');
expect(copiedHTML.querySelector('table:nth-of-type(3) tr td').textContent).to.eq('section metadata');
expect(copiedHTML.querySelector('table:nth-of-type(1) tr td').textContent).to.eq('Z Pattern');
expect(copiedHTML.querySelector('table:nth-of-type(2) tr td').textContent).to.eq('Banner (small, left)');
expect(copiedHTML.querySelector('table:nth-of-type(3) tr td').textContent).to.eq('Section Metadata');

return copiedHTML;
}
Expand Down Expand Up @@ -581,8 +581,8 @@ describe('Blocks Plugin', () => {
const copiedHTML = createTag('div', undefined, clipboardHTML);
expect(copiedHTML.querySelectorAll(':scope > div').length).to.eq(2);
expect(copiedHTML.querySelectorAll(':scope table').length).to.eq(3);
expect(copiedHTML.querySelector('table:nth-of-type(1) tr td').textContent).to.eq('blockquote');
expect(copiedHTML.querySelector('table:nth-of-type(2) tr td').textContent).to.eq('section metadata');
expect(copiedHTML.querySelector('table:nth-of-type(1) tr td').textContent).to.eq('Blockquote');
expect(copiedHTML.querySelector('table:nth-of-type(2) tr td').textContent).to.eq('Section Metadata');

// eslint-disable-next-line max-len
// expect(copiedHTML.querySelector('table:nth-of-type(2) tr td').textContent).to.eq('Metadata');
Expand All @@ -591,7 +591,7 @@ describe('Blocks Plugin', () => {
// There should be 3 tables as per assert above.
copiedHTML.querySelectorAll(':scope table').forEach((table, index) => {
if (index === 2) {
expect(table.querySelector('tr td').textContent).to.eq('metadata');
expect(table.querySelector('tr td').textContent).to.eq('Metadata');
}
});

Expand Down Expand Up @@ -634,7 +634,7 @@ describe('Blocks Plugin', () => {

// Make sure section metadata was copied
const tds = copiedHTML.querySelectorAll('td');
const targetTd = Array.from(tds).find(td => td.textContent.trim() === 'section metadata');
const targetTd = Array.from(tds).find(td => td.textContent.trim() === 'Section Metadata');
expect(targetTd).to.exist;

return copiedHTML;
Expand Down Expand Up @@ -685,7 +685,7 @@ describe('Blocks Plugin', () => {

// Make sure section metadata was copied
const tds = copiedHTML.querySelectorAll('td');
const targetTd = Array.from(tds).find(td => td.textContent.trim() === 'section metadata');
const targetTd = Array.from(tds).find(td => td.textContent.trim() === 'Section Metadata');
expect(targetTd).to.exist;

return copiedHTML;
Expand Down Expand Up @@ -770,9 +770,9 @@ describe('Blocks Plugin', () => {
expect(copiedHTML.querySelectorAll(':scope > div').length).to.eq(1);
expect(copiedHTML.querySelectorAll(':scope table').length).to.eq(3);
expect(copiedHTML.querySelector(':scope h2').textContent).to.eq('Heading');
expect(copiedHTML.querySelector('table:nth-of-type(1) tr td').textContent).to.eq('z pattern');
expect(copiedHTML.querySelector('table:nth-of-type(2) tr td').textContent).to.eq('banner (small, left)');
expect(copiedHTML.querySelector('table:nth-of-type(3) tr td').textContent).to.eq('section metadata');
expect(copiedHTML.querySelector('table:nth-of-type(1) tr td').textContent).to.eq('Z Pattern');
expect(copiedHTML.querySelector('table:nth-of-type(2) tr td').textContent).to.eq('Banner (small, left)');
expect(copiedHTML.querySelector('table:nth-of-type(3) tr td').textContent).to.eq('Section Metadata');

return copiedHTML;
}
Expand Down Expand Up @@ -814,13 +814,13 @@ describe('Blocks Plugin', () => {
expect(copiedHTML.querySelectorAll(':scope > div').length).to.eq(2);
expect(copiedHTML.querySelectorAll(':scope table').length).to.eq(3);
expect(copiedHTML.querySelector(':scope h1').textContent).to.eq('My blog post about a subject');
expect(copiedHTML.querySelector('table:nth-of-type(1) tr td').textContent).to.eq('blockquote');
expect(copiedHTML.querySelector('table:nth-of-type(2) tr td').textContent).to.eq('section metadata');
expect(copiedHTML.querySelector('table:nth-of-type(1) tr td').textContent).to.eq('Blockquote');
expect(copiedHTML.querySelector('table:nth-of-type(2) tr td').textContent).to.eq('Section Metadata');

// See above for this sillyness
copiedHTML.querySelectorAll(':scope table').forEach((table, index) => {
if (index === 2) {
expect(table.querySelector('tr td').textContent).to.eq('metadata');
expect(table.querySelector('tr td').textContent).to.eq('Metadata');
}
});

Expand Down
Loading

0 comments on commit b4a2acd

Please sign in to comment.