Skip to content

Commit

Permalink
♿ accessibility updates via mac screen reader (#5)
Browse files Browse the repository at this point in the history
* various accessibility fixes
* auto-copying Octicons into css variables
* move svg files from .js to css
  • Loading branch information
scottnath authored Sep 22, 2023
1 parent c438ea7 commit d836f0a
Show file tree
Hide file tree
Showing 17 changed files with 1,840 additions and 424 deletions.
10 changes: 1 addition & 9 deletions .storybook/primer-preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,7 @@ export const globalTypesPrimer = {
export const decoratorsPrimer = [
(Story, context) => {
const theme = context.globals.theme;
document.body.setAttribute('data-color-mode', !theme ? '' : theme.startsWith('light') ? 'light' : 'dark')
document.body.setAttribute(
'data-light-theme',
context.globals.theme.startsWith('light') ? theme : undefined,
)
document.body.setAttribute(
'data-dark-theme',
context.globals.theme.startsWith('dark') ? theme : undefined,
)
context.args['data-theme'] = theme;
return Story();
},
]
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ Web components which display profile information from various websites

- [ ] docs for unpkg usage
- [ ] add stackblitz demo
- [ ] typescript types output from JSDoc

## Other profile sources

* Reddit: https://www.reddit.com/user/scottnath/about/.json
1,469 changes: 1,261 additions & 208 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 10 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"repository": {
"type": "git",
"url": "git+https://github.com/scottnath/profile-components.git"
},
},
"publishConfig": {
"provenance": true
},
Expand All @@ -37,23 +37,27 @@
"./*.js": {
"import": "./dist/*.js"
},
"./utils/github/*.js" : {
"./github/*.js": {
"import": "./src/github/*.js"
},
"./github/utils/*.js": {
"import": "./src/github/utils/*.js"
}
},
"license": "MIT",
"devDependencies": {
"@custom-elements-manifest/analyzer": "^0.8.4",
"@custom-elements-manifest/to-markdown": "^0.1.0",
"@primer/css": "^21.0.9",
"@primer/octicons": "^19.7.0",
"@primer/octicons": "^19.8.0",
"@primer/primitives": "^7.13.0",
"commander": "^11.0.0",
"esbuild": "^0.19.2",
"documentation": "^14.0.2",
"esbuild": "^0.19.3",
"esbuild-plugin-inline-import": "^1.0.1",
"fs-extra": "^11.1.1",
"storydocker-storybook": "^0.0.16",
"storydocker-utilities": "^0.0.11"
"storydocker-utilities": "^0.0.11",
"yaml": "^2.3.2"
},
"customElements": "custom-elements.json"
}
69 changes: 56 additions & 13 deletions src/github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,74 @@ Includes two web components:
* `<github-repository>` - displays information about a GitHub repository
* `<github-user>` - displays information about a GitHub user, includes `<github-repository>`

## @todo

- [ ] add process.env option to include github token for local development

## User

### Demo

https://stackblitz.com/edit/profile-components

### Usage

#### import the component from unpkg
```html
<script type="module" src="https://unpkg.com/profile-components/dist/github-user.js"></script>
```

#### use the component
```html
<github-user username="scottnath" fetch="true"></github-user>
```

## Repository

### @todo
### Usage

#### import the component from unpkg
```html
<script type="module" src="https://unpkg.com/@scottnath/profile-components/dist/github-repository.js"></script>
```

#### use the component
```html
<github-repository full_name="scottnath/profile-components" fetch="true"></github-repository>
```

## Style Source

The best way to have the look n feel of an external site is to integrate their design language as much as possible.

### Primer Design System

https://primer.style/design/

"`Primer is a set of guidelines, principles, and patterns for designing and building UI at GitHub.`"

Primer is the source for all of GitHub's root UI foundations (color text, and border-styles), iconography and basic UI patterns.

### Color themes

GitHub (from Primer) has two sets of light themes and two sets of dark themes. Check out [Primer's Storybook docs for colors](https://primer.style/design/foundations/css-utilities/colors) to play around with the colors and see the different themes.

- [ ] repo language colors
- need to expand on the `getCircle` function to include the top X languages on GH
- need a way to expand the available colors
- @see https://github.com/github/personal-website/blob/ec99147d789ea3332274857d38aba8c3b5063ae5/_data/colors.json#L1199
- octicons
- create script to generate local svgs with aria-label
- should be added into .js by esbuild
- @see https://github.com/primer/octicons/blob/main/package.json
* light: 'Light'
* light_colorblind: 'Light Protanopia & Deuteranopia'
* light_tritanopia: 'Light Tritanopia'
* light_high_contrast: 'Light High Contrast'
* dark: 'Dark'
* dark_dimmed: 'Dark Dimmed'
* dark_colorblind: 'Dark Protanopia & Deuteranopia'
* dark_tritanopia: 'Dark Tritanopia'
* dark_high_contrast: 'Dark High Contrast'

## @futureFeatures
#### Primatives and iconography
These components are styled with variables generated from Primer's npm packages.

### GitHub contribution graph
* [primer/primatives](https://github.com/primer/primitives) for colors, borders, and typography
* [primer/octicons](https://github.com/primer/octicons) is the source for all icons used on GitHub. [storybook docs for Octicons](https://primer.style/design/foundations/icons)

Might could incorporate into `<github-user>` component
#### Auto-generated styles

- [ ] graph contrib: https://github.com/enpitsuLin/wc-github-graph/blob/master/src/github-graph.ts
CSS variables and svg icons are pulled from Primer's npm packages. The generated variables are used to style the components.
75 changes: 12 additions & 63 deletions src/github/repository.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,47 +12,6 @@ ${stylesGlobal}
${styles}
`;

/**
* Primer Octicons used by this component
* @see https://primer.style/octicons/
*/
const repoIcon = `<svg viewBox="0 0 16 16" width="16" height="16" fill="currentColor"><path d="M2 2.5A2.5 2.5 0 0 1 4.5 0h8.75a.75.75 0 0 1 .75.75v12.5a.75.75 0 0 1-.75.75h-2.5a.75.75 0 0 1 0-1.5h1.75v-2h-8a1 1 0 0 0-.714 1.7.75.75 0 1 1-1.072 1.05A2.495 2.495 0 0 1 2 11.5Zm10.5-1h-8a1 1 0 0 0-1 1v6.708A2.486 2.486 0 0 1 4.5 9h8ZM5 12.25a.25.25 0 0 1 .25-.25h3.5a.25.25 0 0 1 .25.25v3.25a.25.25 0 0 1-.4.2l-1.45-1.087a.249.249 0 0 0-.3 0L5.4 15.7a.25.25 0 0 1-.4-.2Z"></path></svg>`;
const forksIcon = `<svg aria-label="forks" height="16" viewBox="0 0 16 16" version="1.1" width="16" fill="currentColor">
<path d="M5 5.372v.878c0 .414.336.75.75.75h4.5a.75.75 0 0 0 .75-.75v-.878a2.25 2.25 0 1 1 1.5 0v.878a2.25 2.25 0 0 1-2.25 2.25h-1.5v2.128a2.251 2.251 0 1 1-1.5 0V8.5h-1.5A2.25 2.25 0 0 1 3.5 6.25v-.878a2.25 2.25 0 1 1 1.5 0ZM5 3.25a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Zm6.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5Zm-3 8.75a.75.75 0 1 0-1.5 0 .75.75 0 0 0 1.5 0Z"></path>
</svg>`;
const starIcon = `<svg aria-label="stars" height="16" viewBox="0 0 16 16" version="1.1" width="16" fill="currentColor">
<path d="M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.751.751 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25Zm0 2.445L6.615 5.5a.75.75 0 0 1-.564.41l-3.097.45 2.24 2.184a.75.75 0 0 1 .216.664l-.528 3.084 2.769-1.456a.75.75 0 0 1 .698 0l2.77 1.456-.53-3.084a.75.75 0 0 1 .216-.664l2.24-2.183-3.096-.45a.75.75 0 0 1-.564-.41L8 2.694Z"></path>
</svg>`;
const watchIcon = `<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M8 2c1.981 0 3.671.992 4.933 2.078 1.27 1.091 2.187 2.345 2.637 3.023a1.62 1.62 0 0 1 0 1.798c-.45.678-1.367 1.932-2.637 3.023C11.67 13.008 9.981 14 8 14c-1.981 0-3.671-.992-4.933-2.078C1.797 10.83.88 9.576.43 8.898a1.62 1.62 0 0 1 0-1.798c.45-.677 1.367-1.931 2.637-3.022C4.33 2.992 6.019 2 8 2ZM1.679 7.932a.12.12 0 0 0 0 .136c.411.622 1.241 1.75 2.366 2.717C5.176 11.758 6.527 12.5 8 12.5c1.473 0 2.825-.742 3.955-1.715 1.124-.967 1.954-2.096 2.366-2.717a.12.12 0 0 0 0-.136c-.412-.621-1.242-1.75-2.366-2.717C10.824 4.242 9.473 3.5 8 3.5c-1.473 0-2.825.742-3.955 1.715-1.124.967-1.954 2.096-2.366 2.717ZM8 10a2 2 0 1 1-.001-3.999A2 2 0 0 1 8 10Z"></path></svg>`;

/**
* Generates a circle svg with a fill color based on the repository language
* @param {string} language
* @returns hex code color from colors.json
* @todo parse actual colors.json
*/
const getCircle = (language) => {
let fill = '#f1e05a';
switch (language) {
case "TypeScript":
fill = '#3178c6'
case "Shell":
fill = '#89e051'
case "JavaScript":
fill = '#f1e05a'
case "HTML":
fill = '#e34c26'
case "CSS":
fill = '#563d7c'
case "Java":
fill = '#b07219'
default:
fill = '#f1e05a'
}

return `<svg width="16" height="16" viewBox="0 0 16 16"><circle cx="8" cy="8" r="8" fill="${fill}" /></svg>`
}

/**
* GitHub repository UI component
* When `fetch` is true, fetches repo from GitHub api, but content from the
Expand Down Expand Up @@ -111,15 +70,6 @@ export class GitHubRepository extends HTMLElement {
if (this.org && this.user_login) {
delete this.org;
}
if (this.stargazers_count) {
this.stargazers_count = intToString(this.stargazers_count);
}
if (this.forks_count) {
this.forks_count = intToString(this.forks_count);
}
if (this.subscribers_count) {
this.subscribers_count = intToString(this.subscribers_count);
}
}

/**
Expand Down Expand Up @@ -152,16 +102,15 @@ export class GitHubRepository extends HTMLElement {
_render() {
if (this.error) {
return `
<section role="complementary" itemscope itemtype="http://schema.org/Action">
<div aria-label="GitHub repository" itemscope itemtype="http://schema.org/Action">
<p itemprop="error">${this.error}</p>
</section>
</div>
`
}

return `
<section role="complementary" itemscope itemtype="http://schema.org/SoftwareSourceCode" ${this.itemprop ? `itemprop=${this.itemprop}` : ''}>
<div aria-label="GitHub repository" itemscope itemtype="http://schema.org/SoftwareSourceCode" ${this.itemprop ? `itemprop=${this.itemprop}` : ''}>
<a href="https://github.com/${this.full_name}" itemprop="codeRepository">
${repoIcon}
${this.org ? `
<span itemprop="maintainer">${this.org} /</span>
` : ''}
Expand All @@ -170,25 +119,25 @@ export class GitHubRepository extends HTMLElement {
${this.description ? `
<p itemprop="about">${this.description}</p>
` : ''}
<dl>
<dl aria-label="Repository details">
${this.language ? `
<dt>${getCircle(this.language)} <span>Language</span></dt>
<dt data-detail="language" data-language="${this.language}"><span class="sr-only">Language</span></dt>
<dd itemprop="programmingLanguage">${this.language}</dd>
` : ''}
${this.stargazers_count ? `
<dt>${starIcon} <span>Stars</span></dt>
<dd>${this.stargazers_count}</dd>
<dt data-detail="stars"><span class="sr-only">Stars</span></dt>
<dd><span aria-hidden="true">${intToString(this.stargazers_count)}</span><span class="sr-only">${this.stargazers_count}</span></dd>
` : ''}
${this.subscribers_count ? `
<dt>${watchIcon} <span>Watchers</span></dt>
<dd>${this.subscribers_count}</dd>
<dt data-detail="watchers"><span class="sr-only">Watchers</span></dt>
<dd><span aria-hidden="true">${intToString(this.subscribers_count)}</span><span class="sr-only">${this.subscribers_count}</span></dd>
` : ''}
${this.forks_count ? `
<dt>${forksIcon} <span>Forks</span></dt>
<dd>${this.forks_count}</dd>
<dt data-detail="forks"><span class="sr-only">Forks</span></dt>
<dd><span aria-hidden="true">${intToString(this.forks_count)}</span><span class="sr-only">${this.forks_count}</span></dd>
` : ''}
</dl>
</section>
</div>
`;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/github/repository.shared-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { within as shadowWithin } from 'shadow-dom-testing-library';
*/
export const getElements = async (canvasElement) => {
const screen = shadowWithin(canvasElement);
const container = await screen.findByShadowRole('complementary');
const container = await screen.queryByShadowLabelText(/GitHub repository/i);
const link = await screen.queryByShadowRole('link');
const langDetails = await container?.querySelector('[itemprop="programmingLanguage"]');
const langTerm = await langDetails?.previousElementSibling;
Expand Down
13 changes: 12 additions & 1 deletion src/github/repository.stories.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { repoProfileComponents, repoFreeCodeCamp } from './fixtures';
import './repository';

export default {
title: 'GitHub Repository',
title: 'GitHub/github-repository',
component: 'github-repository',
tags: ['autodocs'],
render: (args) => {
Expand Down Expand Up @@ -47,6 +47,13 @@ export const WithOrgName = {
},
play: FullNameOnly.play,
}
export const LanguageCircle = {
args: {
full_name: 'just-another/c-plus-plus-repo',
language: 'C++',
},
play: FullNameOnly.play,
}

export const AllRepoContent = {
args: {
Expand All @@ -66,6 +73,8 @@ export const Fetch = {
]
},
play: async ({ args, canvasElement, step }) => {
/** wait for fetch to complete */
await new Promise(resolve => setTimeout(resolve, 0));
const elements = await getElements(canvasElement);
const argsAfterFetch = {
...parseFetchedRepo(repoProfileComponents),
Expand Down Expand Up @@ -95,6 +104,8 @@ export const FetchError = {
]
},
play: async ({ args, canvasElement, step }) => {
/** wait for fetch to complete */
await new Promise(resolve => setTimeout(resolve, 0));
const elements = await getElements(canvasElement);
const argsAfterFetch = {
...args,
Expand Down
45 changes: 39 additions & 6 deletions src/github/styles/repository.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,33 @@
container-name: repository;
}

section[itemscope] {
div[itemscope] {
padding: var(--row-spacing);
}

@container repository (min-width: 300px) {
section[itemscope] {
div[itemscope] {
padding: calc(var(--row-spacing) * 2);
}
}

[itemprop="codeRepository"] {
display: block;

&::before {
content: " ";
display: inline-block;
vertical-align: text-bottom;
height: var(--svg-size);
width: var(--svg-size);
background-color: var(--color-light);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;
-webkit-mask-image: var(--svg-repo);
mask-image: var(--svg-repo);
}
> svg {
fill: var(--color-light);
vertical-align: text-bottom;
Expand All @@ -42,11 +56,30 @@ dl {

> dt {
flex: 0 0 var(--svg-size);
> span {
display: none;
background-color: var(--color-light);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-position: center;
mask-position: center;

&[data-detail="language"] {
-webkit-mask-image: var(--svg-circle);
mask-image: var(--svg-circle);
}

&[data-detail="stars"] {
-webkit-mask-image: var(--svg-star);
mask-image: var(--svg-star);
}

&[data-detail="watchers"] {
-webkit-mask-image: var(--svg-eye);
mask-image: var(--svg-eye);
}
> svg {
vertical-align: text-bottom;

&[data-detail="forks"] {
-webkit-mask-image: var(--svg-repo-forked);
mask-image: var(--svg-repo-forked);
}
}
> dd {
Expand Down
Loading

0 comments on commit d836f0a

Please sign in to comment.