Skip to content

Commit

Permalink
chore: create docs, upload button, ordered first
Browse files Browse the repository at this point in the history
  • Loading branch information
jorenbroekema committed May 21, 2024
1 parent 6bd674c commit 2076bbf
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 15 deletions.
55 changes: 55 additions & 0 deletions docs/src/components/sd-dtcg-convert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { LitElement, html } from 'lit';
import { ref, createRef } from 'lit/directives/ref.js';
import '@shoelace-style/shoelace/dist/components/button/button.js';
import { convertJSONToDTCG, convertZIPToDTCG } from '../../../lib/utils/convertToDTCG.js';
import { downloadJSON, downloadZIP } from '../../../lib/utils/downloadFile.js';

class SdDtcgConvert extends LitElement {
fileInputRef = createRef();

render() {
return html`
<sl-button @click=${this.triggerUpload} variant="primary">Convert tokens to DTCG</sl-button>
<input
${ref(this.fileInputRef)}
@change=${this.upload}
id="upload-tokens-input"
type="file"
accept="application/*, text/*"
aria-hidden="true"
hidden
/>
`;
}

triggerUpload() {
const fileInput = this.fileInputRef.value;
if (fileInput) {
fileInput.dispatchEvent(new MouseEvent('click'));
}
}

async upload(ev: Event) {
if (ev.target instanceof HTMLInputElement) {
const file = ev.target.files?.[0];
if (file) {
const today = new Date(Date.now());
const filename = `dtcg-tokens_${today.getFullYear()}-${today.getMonth()}-${(
'0' + today.getDate()
).slice(-2)}`;

if (file.type.includes('zip')) {
const zipBlob = await convertZIPToDTCG(file);
await downloadZIP(zipBlob, `${filename}.zip`);
} else if (file.type.includes('json')) {
const jsonBlob = await convertJSONToDTCG(file);
await downloadJSON(jsonBlob, `${filename}.json`);
} else {
throw new Error('Only ZIP and JSON type uploads are supported.');
}
}
}
}
}

customElements.define('sd-dtcg-convert', SdDtcgConvert);
2 changes: 1 addition & 1 deletion docs/src/components/sd-playground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import '@shoelace-style/shoelace/dist/components/option/option.js';
import { bundle } from '../utils/rollup-bundle.ts';
import { changeLang, init, monaco } from '../monaco/monaco.ts';
import { analyzeDependencies } from '../utils/analyzeDependencies.ts';
import type SlRadioGroup from '@shoelace-style/shoelace/dist/components/radio-group/radio-group.js';
import { downloadZIP } from '../../../lib/utils/downloadFile.js';
import type SlRadioGroup from '@shoelace-style/shoelace/dist/components/radio-group/radio-group.js';

const { Volume } = memfs;

Expand Down
35 changes: 35 additions & 0 deletions docs/src/content/docs/info/DTCG.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
title: Design Token Community Group
sidebar:
order: 4
---

import tokens from '/public/demo-tokens.json';

There is a [W3C Design Token Community Group](https://www.w3.org/community/design-tokens/), whose goal it is to "provide standards upon which products and design tools can rely for sharing stylistic pieces of a design system at scale".

What that boils down to right now is a [draft specification for how Design Tokens ought to be formatted](https://design-tokens.github.io/community-group/format/), for cross-tool and cross-platform interoperability.
Since Style Dictionary v4, we have first-class support for this format.

## Convert your Tokens to DTCG

We also export a tool that allows you to convert your design tokens in the old format to the DTCG format:

<div spacer></div>
<sd-dtcg-convert></sd-dtcg-convert>

What it does:

- Turn `value`, `type` and `description` design token property keys into `$value`, `$type` and `$description` respectively.
- Move the `$type` properties from the design tokens onto the uppermost common ancestor token group

What it does not do (atm, feel free to raise suggestions):

- Refactor type values commonly used to the DTCG types, e.g. size -> dimension.

## Live demo

<sd-playground tokens={JSON.stringify({ value: JSON.stringify(tokens, null, 2), lang: 'json'})} default-selected="tokens" id="main-demo">

<div style="height: 100%" slot="monaco-editor"></div>
</sd-playground>
2 changes: 2 additions & 0 deletions docs/src/content/docs/info/architecture.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
title: Architecture
sidebar:
order: 2
---

This is how Style Dictionary works under the hood.
Expand Down
2 changes: 2 additions & 0 deletions docs/src/content/docs/info/package_structure.mdx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
---
title: Package Structure
sidebar:
order: 3
---

import { FileTree } from '@astrojs/starlight/components';
Expand Down
25 changes: 14 additions & 11 deletions docs/src/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,19 @@ themeObserver.observe(document.documentElement, {
attributeFilter: [themeAttr],
});

// Conditionally load the sd-playground Web Component definition if we find an instance of it.
const firstPlaygroundEl = document.querySelector('sd-playground');
const CEs = ['sd-playground', 'sd-dtcg-convert'];

if (firstPlaygroundEl) {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
import('./components/sd-playground.ts');
}
CEs.forEach((ce) => {
// Conditionally load the sd-playground Web Component definition if we find an instance of it.
const firstEl = document.querySelector(ce);
if (firstEl) {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
import(`./components/${ce}.ts`);
}
});
});
});
observer.observe(firstPlaygroundEl);
}
observer.observe(firstEl);
}
});
17 changes: 14 additions & 3 deletions lib/utils/convertToDTCG.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,20 @@ function recurse(slice, opts) {
// If it's only 1 type, we know we can apply the type on the ancestor group
// and remove it from the children
if (types.size === 1 && opts?.applyTypesToGroup !== false) {
slice.$type = [...types][0];
const entries = Object.entries(slice);

// TODO: add test that checks $type being ordered first on token groups
// delete everything in the slice without losing the reference to the slice
Object.keys(slice).forEach((key) => {
delete slice[key].$type;
delete slice[key];
});
// put the type FIRST
slice.$type = [...types][0];
// then put the rest of the key value pairs back, now we always ordered $type first on the token group
entries.forEach(([key, value]) => {
if (key !== '$type') {
slice[key] = value;
}
});
}
}
Expand Down Expand Up @@ -106,7 +117,7 @@ async function blobify(blobOrPath) {
* @param {string} [path]
*/
function validateBlobType(blob, type, path) {
if (blob.type.includes(type)) {
if (!blob.type.includes(type)) {
throw new Error(
`File ${path ?? '(Blob)'} is of type ${blob.type}, but a ${type} type blob was expected.`,
);
Expand Down

0 comments on commit 2076bbf

Please sign in to comment.