-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9 from penpot/contrast-plugin
feat: contrast plugin
- Loading branch information
Showing
28 changed files
with
552 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"presets": ["@nx/js/babel"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"extends": ["../../.eslintrc.json"], | ||
"ignorePatterns": ["!**/*"], | ||
"overrides": [ | ||
{ | ||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.ts", "*.tsx"], | ||
"rules": {} | ||
}, | ||
{ | ||
"files": ["*.js", "*.jsx"], | ||
"rules": {} | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"jsc": { | ||
"parser": { | ||
"syntax": "typescript" | ||
}, | ||
"target": "es2016" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<title>ContrastPlugin</title> | ||
<base href="/" /> | ||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> | ||
<link rel="stylesheet" href="/src/styles.css" /> | ||
</head> | ||
<body> | ||
<app-root></app-root> | ||
<script type="module" src="/src/main.ts"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"name": "contrast-plugin", | ||
"$schema": "../../node_modules/nx/schemas/project-schema.json", | ||
"projectType": "application", | ||
"sourceRoot": "apps/contrast-plugin/src", | ||
"tags": ["type:plugin"], | ||
"targets": {} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"name": "Contrast plugin", | ||
"code": "http://localhost:4201/plugin.js", | ||
"permissions": [ | ||
"page:read", | ||
"file:read", | ||
"selection:read" | ||
] | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
.wrapper { | ||
color: var(--app-white); | ||
} | ||
|
||
.color { | ||
align-items: center; | ||
display: flex; | ||
margin-inline-end: var(--spacing-16); | ||
} | ||
|
||
.color-preview { | ||
block-size: var(--spacing-36); | ||
border: 1px solid var(--df-secondary); | ||
border-radius: var(--spacing-4); | ||
display: block; | ||
inline-size: var(--spacing-36); | ||
margin-inline-end: var(--spacing-16); | ||
} | ||
|
||
.fail { | ||
background-color: var(--error-500); | ||
} | ||
|
||
.good { | ||
background-color: var(--success-500); | ||
} | ||
|
||
.title { | ||
margin-block-end: var(--spacing-8); | ||
} | ||
|
||
.list { | ||
display: flex; | ||
margin-block-end: var(--spacing-16); | ||
} | ||
|
||
.tag { | ||
border-radius: var(--spacing-4); | ||
color: var(--db-primary); | ||
margin-inline-end: var(--spacing-16); | ||
padding: var(--spacing-4) var(--spacing-8); | ||
text-transform: uppercase; | ||
} | ||
|
||
.contrast-preview { | ||
align-items: center; | ||
border: 1px solid var(--df-secondary); | ||
border-radius: var(--spacing-4); | ||
box-sizing: content-box; | ||
block-size: calc(2 * var(--spacing-40)); | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
inline-size: calc(100% - var(--spacing-16)); | ||
margin-block-end: var(--spacing-16); | ||
padding-block: var(--spacing-24); | ||
} | ||
|
||
.empty-preview { | ||
position: absolute; | ||
} | ||
|
||
.text { | ||
color: transparent; | ||
margin-block-end: var(--spacing-8); | ||
|
||
&.small { | ||
font-size: 18px; | ||
} | ||
|
||
&.large { | ||
font-size: 24px; | ||
} | ||
} | ||
|
||
.icons-list { | ||
display: flex; | ||
gap: var(--spacing-8); | ||
margin-block-start: var(--spacing-8); | ||
} | ||
|
||
.shape { | ||
block-size: var(--spacing-24); | ||
inline-size: var(--spacing-24); | ||
} | ||
|
||
.circle { | ||
border-radius: 50%; | ||
} | ||
|
||
.triangle { | ||
border-left: var(--spacing-12) solid transparent; | ||
border-right: var(--spacing-12) solid transparent; | ||
border-bottom: var(--spacing-24) solid transparent; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { AppElement } from './app.element'; | ||
|
||
describe('AppElement', () => { | ||
let app: AppElement; | ||
|
||
beforeEach(() => { | ||
app = new AppElement(); | ||
}); | ||
|
||
it('should create successfully', () => { | ||
expect(app).toBeTruthy(); | ||
}); | ||
|
||
it('should have a greeting', () => { | ||
app.connectedCallback(); | ||
|
||
expect(app.querySelector('h1').innerHTML).toContain( | ||
'Welcome contrast-plugin' | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import 'plugins-styles/lib/styles.css'; | ||
import './app.element.css'; | ||
|
||
export class AppElement extends HTMLElement { | ||
public static observedAttributes = []; | ||
|
||
calculateContrast(firstColor: string, secondColor: string) { | ||
const luminosityFirstColor = this.getLuminosity(firstColor); | ||
const luminositySecondColor = this.getLuminosity(secondColor); | ||
|
||
const result = (luminosityFirstColor + 0.05) / (luminositySecondColor + 0.05); | ||
this.setColors(firstColor, secondColor); | ||
this.setResult(result.toFixed(2).toString()); | ||
this.setA11yTags(result); | ||
} | ||
|
||
getLuminosity(color: string) { | ||
const rgb = this.hexToRgb(color); | ||
return 0.2126 * (rgb[0]/255) + 0.7152 * (rgb[1]/255) + 0.0722 * (rgb[2]/255); | ||
} | ||
|
||
hexToRgb(hex: string) { | ||
const r = parseInt(hex.slice(1, 3), 16) | ||
const g = parseInt(hex.slice(3, 5), 16) | ||
const b = parseInt(hex.slice(5, 7), 16) | ||
return [ r, g, b ]; | ||
} | ||
|
||
setResult(text: string) { | ||
const selector = document.getElementById('result'); | ||
|
||
if (selector) { | ||
selector.innerText = `${text} : 1`; | ||
} | ||
} | ||
|
||
setColors(firstColor: string | null, secondColor: string | null) { | ||
const color1 = document.getElementById('first-color'); | ||
const color2 = document.getElementById('second-color'); | ||
const code1 = document.getElementById('first-color-code'); | ||
const code2 = document.getElementById('second-color-code'); | ||
const contrastPreview = document.getElementById('contrast-preview'); | ||
const smallText = document.getElementById('small-text'); | ||
const largeText = document.getElementById('large-text'); | ||
const circle = document.getElementById('circle'); | ||
const square = document.getElementById('square'); | ||
const triangle = document.getElementById('triangle'); | ||
|
||
if (color1 && code1) { | ||
color1.style.background = firstColor ? firstColor : 'transparent'; | ||
code1.innerText = firstColor ? firstColor : ''; | ||
} | ||
|
||
if (color2 && code2) { | ||
color2.style.background = secondColor ? secondColor : 'transparent'; | ||
code2.innerText = secondColor ? secondColor : ''; | ||
} | ||
|
||
if (contrastPreview && smallText && largeText && circle && square && triangle) { | ||
contrastPreview.style.background = secondColor ? secondColor : 'transparent'; | ||
smallText.style.color = firstColor ? firstColor : 'transparent'; | ||
largeText.style.color = firstColor ? firstColor : 'transparent'; | ||
circle.style.background = firstColor ? firstColor : 'transparent'; | ||
square.style.background = firstColor ? firstColor : 'transparent'; | ||
triangle.style.borderBottom = firstColor ? `var(--spacing-24) solid ${firstColor}` : 'var(--spacing-24) solid transparent'; | ||
} | ||
|
||
const emptyPreview = document.getElementById('empty-preview'); | ||
if (!firstColor && !secondColor && emptyPreview) { | ||
emptyPreview.style.display = 'block'; | ||
} else if (emptyPreview) { | ||
emptyPreview.style.display = 'none'; | ||
} | ||
} | ||
|
||
setA11yTags(result: number) { | ||
const selectors = { | ||
aa: document.getElementById('aa'), | ||
aaa: document.getElementById('aaa'), | ||
aaLg: document.getElementById('aa-lg'), | ||
aaaLg: document.getElementById('aaa-lg'), | ||
graphics: document.getElementById('graphics') | ||
}; | ||
const fail = 'tag fail'; | ||
const good = 'tag good'; | ||
|
||
function setClass(selector: HTMLElement | null, className: string) { | ||
if (selector) { | ||
selector.className = className; | ||
} | ||
} | ||
|
||
if (result > 7) { | ||
setClass(selectors.aa, good); | ||
setClass(selectors.aaa, good); | ||
setClass(selectors.aaLg, good); | ||
setClass(selectors.aaaLg, good); | ||
setClass(selectors.graphics, good); | ||
} else if (result > 4.5) { | ||
setClass(selectors.aa, good); | ||
setClass(selectors.aaa, fail); | ||
setClass(selectors.aaLg, good); | ||
setClass(selectors.aaaLg, good); | ||
setClass(selectors.graphics, good); | ||
} else if (result > 3) { | ||
setClass(selectors.aa, fail); | ||
setClass(selectors.aaa, fail); | ||
setClass(selectors.aaLg, good); | ||
setClass(selectors.aaaLg, fail); | ||
setClass(selectors.graphics, good); | ||
} else { | ||
setClass(selectors.aa, fail); | ||
setClass(selectors.aaa, fail); | ||
setClass(selectors.aaLg, fail); | ||
setClass(selectors.aaaLg, fail); | ||
setClass(selectors.graphics, fail); | ||
} | ||
} | ||
|
||
connectedCallback() { | ||
window.addEventListener('message', (event) => { | ||
if (event.data.type === 'selection') { | ||
if (event.data.content.length === 2) { | ||
this.calculateContrast('#d5d1d1', '#000410'); | ||
} else { | ||
this.setColors(null, null); | ||
this.setResult('0'); | ||
this.setA11yTags(0); | ||
} | ||
} else if (event.data.type === 'page') { | ||
console.log('refrespage', event.data); | ||
} else if (event.data.type === 'init') { | ||
if (event.data.content.selection.length === 2) { | ||
//TODO get real colors from selection | ||
this.calculateContrast('#d5d1d1', '#000410'); | ||
} | ||
} | ||
}); | ||
|
||
this.innerHTML = ` | ||
<div class="wrapper"> | ||
<div id="contrast-preview" class="contrast-preview"> | ||
<p id="empty-preview" class="empty-preview">Select two colors to calculate contrast</p> | ||
<p id="small-text" data-color="text" data-second class="text small">SMALL sample text</p> | ||
<p id="large-text" data-color="text" data-second class="text large">LARGE sample text</p> | ||
<ul class="icons-list"> | ||
<span id="circle" class="shape circle"></span> | ||
<span id="square" class="shape square"></span> | ||
<span id="triangle" class="triangle"></span> | ||
</ul> | ||
</div> | ||
<p class="title body-l">Selected colors:</p> | ||
<ul class="list"> | ||
<li class="color"> | ||
<span id="first-color" data-first class="color-preview"></span> | ||
<code id="first-color-code"></code> | ||
</li> | ||
<li class="color"> | ||
<span id="second-color" data-second class="color-preview"></span> | ||
<code id="second-color-code"></code> | ||
</li> | ||
</ul> | ||
<p class="title body-l">Contrast ratio: <span id="result">0 : 1</span></p> | ||
<p class="title body-l">Normal text:</p> | ||
<ul class="list"> | ||
<li id="aa" class="tag fail">AA</li> | ||
<li id="aaa" class="tag fail">AAA</li> | ||
</ul> | ||
<p class="title body-l">Large text (24px or 19px + bold):</p> | ||
<ul class="list"> | ||
<li id="aa-lg" class="tag fail">AA</li> | ||
<li id="aaa-lg" class="tag fail">AAA</li> | ||
</ul> | ||
<p class="title body-l">Graphics (such as form input borders):</p> | ||
<ul class="list"> | ||
<li id="graphics" class="tag fail">AA</li> | ||
</ul> | ||
</div> | ||
`; | ||
|
||
parent.postMessage({ content: 'ready' }, '*'); | ||
} | ||
} | ||
customElements.define('app-root', AppElement); |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
import './app/app.element'; |
Oops, something went wrong.