Skip to content

Commit

Permalink
feat: 🎸 Add feature to highlight column gaps in grid containers
Browse files Browse the repository at this point in the history
✅ Closes: #198
  • Loading branch information
phun-ky committed Aug 2, 2024
1 parent 01562a0 commit 2306cee
Show file tree
Hide file tree
Showing 7 changed files with 397 additions and 5 deletions.
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- [Subtle anatomy](#subtle-anatomy)
- [Curly brackets](#curly-brackets)
- [Element typography](#element-typography)
- [Grid spacing](#grid-spacing)
- [Mark elements](#mark-elements)
- [A11y notation](#a11y-notation)
- [Tab stops](#tab-stops)
Expand Down Expand Up @@ -306,9 +307,21 @@ In your component examples, use the following attribute.

This will place a box to display typography information. Default is `left`.

### Grid spacing

![Screenshot of grid feature](./public/grid.png)

This will highlight the grid spacing in a `display: grid;` element.

In your component examples, use the following attribute on your grid container.

```html
<div data-speccer-grid="grid" …>…</div>
```

### Mark elements

![Alt text](./public/mark.png)
![Screenshot of marked elements](./public/mark.png)

This will mark the given elements.

Expand Down Expand Up @@ -369,9 +382,9 @@ Allthough the styling works nicely with dark mode, you can use the provided CSS
--ph-speccer-typography-color-text: #57575b;
--ph-speccer-typography-color-value: var(--ph-speccer-color-contrast);
--ph-speccer-depth-opacity-400: 0.4;
--ph-speccer-font-family: 'Menlo for Powerline',
'Menlo Regular for Powerline', 'DejaVu Sans Mono', Consolas, Monaco,
'Andale Mono', 'Ubuntu Mono', monospace;
--ph-speccer-font-family: 'Menlo for Powerline', 'Menlo Regular for Powerline',
'DejaVu Sans Mono', Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono',
monospace;
--ph-speccer-font-size: 12px;
--ph-speccer-line-height: 12px;
--ph-speccer-pin-size: 24px;
Expand Down
188 changes: 188 additions & 0 deletions dev/grid.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
<!doctype html>
<html class="ph" lang="en">
<head>
<title>@phun-ky/speccer | grid</title>
<meta charset="utf-8" />
<meta http-equiv="Content-Language" content="no" />
<meta name="robots" content="none" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="application-name" content="@phun-ky/speccer" />
</head>
<body class="ph">
<div
data-speccer-grid="grid"
class="ph container"
style="
padding: 5rem;
display: grid;
grid-template-columns: repeat(5, 160px);
grid-template-rows: repeat(1, 160px);
grid-auto-flow: dense;
grid-gap: 1.5rem 1.5rem;
"
>
<div id="2202a8b8-b259-5dad-8008-3670de213cd8" class="ph box"></div>
<div
id="3ed666ed-7bb9-56ab-ae91-33058dc3b969"
class="ph box"
style="grid-column: span 2"
></div>
<div id="b19e19e9-ffef-5aff-9de4-d43e1a85536d" class="ph box"></div>
<div
id="ece5d053-0e88-5c17-8f40-07ccd229efe7"
class="ph box"
style="grid-column: span 4"
></div>
<div
id="06540269-8bc5-5215-9240-f2473f4cde16"
class="ph box"
style="grid-row: span 2"
></div>
<div id="cd907a63-0574-5a0f-bd04-b6d10245d74b" class="ph box"></div>
<div
id="14408f63-4b8d-5044-8b99-8ebcfed058a2"
class="ph box"
style="grid-column: span 3"
></div>
<div
id="d35b4ca7-8f87-52e2-9c70-9141e813207b"
class="ph box"
style="grid-row: span 5"
></div>
<div id="73079eb2-7552-5d3e-b425-96412fc4c0bf" class="ph box"></div>
<div id="4f840de9-968b-5355-aae1-0c82cf64313c" class="ph box"></div>
<div
id="239816e0-7572-5e4f-b628-4463677c5f85"
class="ph box"
style="grid-row: span 3"
></div>
<div
id="4ff9c957-4765-5ef3-b753-7dc3b2b3be66"
class="ph box"
style="grid-column: span 5"
></div>
<div id="defe2794-ac9d-513a-b90f-942effc7ffcb" class="ph box"></div>
<div id="c5132d1e-560f-537f-99c5-b95858d9a2b7" class="ph box"></div>
<div id="3d258657-0b40-5e08-b426-f064f4dff940" class="ph box"></div>
<div id="efe7d218-5ca1-5c5a-a935-8cd68e732daa" class="ph box"></div>
<div id="49eedd56-9a25-53b0-9f73-17f12087e03a" class="ph box"></div>
<div id="014df247-51e0-559f-8464-eecf68507004" class="ph box"></div>
<div
id="38cc034a-8b8f-56d4-8322-03e5bd509b8a"
class="ph box"
style="grid-column: span 2"
></div>
<div id="bc2c0c41-6408-5a17-ab31-b12ba2d2e821" class="ph box"></div>
<div id="cc7a8341-29b5-51ba-86be-3d8093b25e5e" class="ph box"></div>
<div id="93cd2a3c-0193-55ac-b73b-27f591499a82" class="ph box"></div>
<div id="384388e1-4475-584a-8f6c-ffcd0299eec2" class="ph box"></div>
<div
id="50ba1237-ac81-55ea-b60b-0022ef6f68fe"
class="ph box"
style="grid-column: span 4"
></div>
<div id="d8fbe4d0-b2a8-52d7-b3c5-9a6a24168101" class="ph box"></div>
<div
id="eb6f2c36-03e4-5838-bde1-2f150b053098"
class="ph box"
style="grid-row: span 2"
></div>
<div id="b737696b-f848-5fc4-b4cd-56529eedf0fd" class="ph box"></div>
<div
id="91b1cccf-23ea-5b0c-ae9a-debe25922d8e"
class="ph box"
style="grid-row: span 2"
></div>
<div id="66c2a470-8961-5c2b-bdc4-3b82ea4d13f5" class="ph box"></div>
<div id="e17df59a-9748-585e-9ee4-d8dc80d18aec" class="ph box"></div>
</div>

<link async href="/speccer.css" rel="stylesheet" type="text/css" />
<link
async
href="https://fonts.googleapis.com/css?family=Lato:300,300i,400,400i,700,700i,900,900i&amp;display=swap&amp;subset=latin-ext"
rel="stylesheet"
type="text/css"
/>
<link
async
href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i,800,800i&amp;display=swap&amp;subset=latin-ext"
rel="stylesheet"
type="text/css"
/>
<style type="text/css">
body.ph {
background-color: #f5f5f5;
}
.ph.container {
counter-reset: box;
}
.ph.box {
background-color: white;
min-height: 160px;
min-width: 160px;
margin: 0;
padding: 2rem;
border: 1pt solid rgba(51, 51, 51, 0.1);
color: #4d4d4d;
font-family: Lato, sans-serif;
font-size: 4rem;
box-sizing: border-box;
box-shadow: 0 0 10px rgba(51, 51, 51, 0.2);
display: flex;
align-items: center;
justify-content: center;
}

.ph.box:after {
counter-increment: box;
content: counter(box);
}
</style>
<script data-manual src="/speccer.js" type="text/javascript"></script>
<script>
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', window.speccer);
} else {
// `DOMContentLoaded` already fired
window.speccer();
}
const debounce = function (func, wait, immediate) {
var timeout;
return function () {
var context = this,
args = arguments;
var later = function () {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const speccerEventFunc = debounce(() => {
window.speccer();
}, 100);

window.removeEventListener('resize', speccerEventFunc);
window.addEventListener('resize', speccerEventFunc);
</script>
<svg
class="ph-speccer"
viewBox="0 0"
id="ph-speccer-svg"
xmlns="http://www.w3.org/2000/svg"
>
<path
class="ph-speccer path original"
id="ph-speccer-path"
fill="none"
stroke-width="1"
stroke="currentColor"
/>
</svg>
</body>
</html>
Binary file added public/grid.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
103 changes: 103 additions & 0 deletions src/features/grid/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/* eslint no-console:0 */
import { waitForFrame } from '../../utils/wait';

const SPECCER_DATA_ATTR = 'data-speccer-grid';
const SPECCER_FEATURE_GRID = 'grid';

/**
* Creates a visual grid overlay for a given target element.
*
* @param {HTMLElement} targetElement - The target element to create the grid overlay for.
* @param {CSSStyleDeclaration} styles - The computed styles of the target element.
* @returns {HTMLDivElement} The created grid container element.
*
* @example
* ```ts
* const targetElement = document.getElementById('target');
* if (targetElement) {
* const styles = window.getComputedStyle(targetElement);
* const gridOverlay = create(targetElement, styles);
* document.body.appendChild(gridOverlay);
* }
* ```
*/
export const create = (targetElement:HTMLElement, styles: CSSStyleDeclaration) => {
const rect = targetElement.getBoundingClientRect();
const templateColumns = styles.gridTemplateColumns;
// const templateRows = styles['gridTemplateRows'];
const columnGap = parseInt(styles.columnGap);
// const rowGap = styles.rowGap;
const padding = styles.padding;
const gridContainer = document.createElement('div');

gridContainer.style.setProperty('--ph-speccer-grid-gap-original',`${columnGap}px`);
gridContainer.style.setProperty('--ph-speccer-grid-gap',`${columnGap < 24 ? 24 : columnGap}px`);

if(columnGap < 24){
gridContainer.classList.add('speccer-small-grid');
}

gridContainer.classList.add('ph-speccer');
gridContainer.classList.add('speccer');
gridContainer.classList.add('speccer-grid-container');

gridContainer.style.height = rect.height + 64 + 'px';
gridContainer.style.width = rect.width + 'px';
gridContainer.style.position = 'absolute';
gridContainer.style.left = rect.left + 'px';
gridContainer.style.top = rect.top - 32 + 'px';
gridContainer.style.display = 'grid';
gridContainer.style.padding = padding;
gridContainer.style.columnGap = `${columnGap}px`;
gridContainer.style.gridTemplateColumns = templateColumns;

//gridContainer.style.gridTemplateRows = templateRows;
const numberOfItems = templateColumns.split(' ').length;

for(let i = 0; i < numberOfItems;i++){
const gridItem = document.createElement('div');

gridItem.classList.add('ph-speccer');
gridItem.classList.add('speccer');
gridItem.classList.add('speccer-grid-item');
gridContainer.appendChild(gridItem);
}

return gridContainer;
};

/**
* Create a visual overlay to present the column gaps for a grid container
*
* Adds a visual grid overlay to the target element if it has the appropriate data attribute and is a grid.
*
* ![grid](https://github.com/phun-ky/speccer/blob/main/public/grid.png?raw=true)
*
* @param {HTMLElement} targetElement - The target element to add the grid overlay to.
* @returns {Promise<void>} A promise that resolves once the overlay has been added.
*
* @example
* ```ts
* const targetElement = document.getElementById('target');
* if (targetElement) {
* element(targetElement).then(() => {
* console.log('Grid overlay added');
* });
* }
* ```
*/
export const element = async (targetElement: HTMLElement): Promise<void> => {
if (!targetElement) return;

const attr = targetElement.getAttribute(SPECCER_DATA_ATTR);

await waitForFrame();

const styles = window.getComputedStyle(targetElement);

if(attr === SPECCER_FEATURE_GRID && (styles.display === 'grid' || styles.display.indexOf('grid') !== -1)){
const gridContainerElement = create(targetElement, styles);

document.body.appendChild(gridContainerElement);
}
};
17 changes: 17 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import {
create as dissectCreate,
element as dissectElement
} from './features/dissect';
import {
create as gridCreate,
element as gridElement
} from './features/grid';
import { create as markCreate, element as markElement } from './features/mark';
import {
create as measureCreate,
Expand All @@ -23,6 +27,11 @@ import {
import { removeAll } from './utils/node';


export const grid = {
create: gridCreate,
element: gridElement
};

export const spacing = {
create: spacingCreate,
element: spacingElement
Expand Down Expand Up @@ -67,10 +76,18 @@ const speccer = () => {
);
const elsToBeDissected = document.querySelectorAll('[data-anatomy-section]');
const elsToBeMarked = document.querySelectorAll('[data-speccer-mark]');
const SPECCER_DATA_ATTR = 'data-speccer-grid';
const SPECCER_FEATURE_GRID = 'grid';
const SPECCER_FEATURE_GRID_SELECTOR = `[${SPECCER_DATA_ATTR}="${SPECCER_FEATURE_GRID}"]`;
const elstToBeGrid = document.querySelectorAll(SPECCER_FEATURE_GRID_SELECTOR);

for (const el of elsToBeMarked) {
markElement(el as HTMLElement);
}

for (const el of elstToBeGrid) {
gridElement(el as HTMLElement);
}
for (const el of elsToBeSpecced) {
spacingElement(el as HTMLElement);
}
Expand Down
Loading

0 comments on commit 2306cee

Please sign in to comment.