diff --git a/.changeset/chatty-shoes-taste.md b/.changeset/chatty-shoes-taste.md
new file mode 100644
index 00000000..ecda8600
--- /dev/null
+++ b/.changeset/chatty-shoes-taste.md
@@ -0,0 +1,5 @@
+---
+'@cobalt-ui/core': patch
+---
+
+Fix strokeStyle object values
diff --git a/.changeset/fresh-buses-lick.md b/.changeset/fresh-buses-lick.md
new file mode 100644
index 00000000..3d25f9fd
--- /dev/null
+++ b/.changeset/fresh-buses-lick.md
@@ -0,0 +1,5 @@
+---
+'@cobalt-ui/cli': patch
+---
+
+Call all config() callbacks before running builds
diff --git a/.changeset/grumpy-snakes-type.md b/.changeset/grumpy-snakes-type.md
new file mode 100644
index 00000000..eff236df
--- /dev/null
+++ b/.changeset/grumpy-snakes-type.md
@@ -0,0 +1,5 @@
+---
+'@cobalt-ui/plugin-css': patch
+---
+
+Allow generateName() to return `undefined` or `null` to fall back to default name generation
diff --git a/docs/.env.example b/docs/.env.example
deleted file mode 100644
index dc23c6cb..00000000
--- a/docs/.env.example
+++ /dev/null
@@ -1 +0,0 @@
-FIGMA_API_KEY=
diff --git a/docs/.gitignore b/docs/.gitignore
new file mode 100644
index 00000000..b7330346
--- /dev/null
+++ b/docs/.gitignore
@@ -0,0 +1,2 @@
+.vitepress/cache
+.vitepress/dist
diff --git a/docs/.vitepress/config.ts b/docs/.vitepress/config.ts
new file mode 100644
index 00000000..605f63cb
--- /dev/null
+++ b/docs/.vitepress/config.ts
@@ -0,0 +1,88 @@
+import {defineConfig} from 'vitepress';
+import packageJSON from '../../packages/cli/package.json';
+
+/** @see https://vitepress.dev/reference/site-config */
+export default defineConfig({
+ title: 'Cobalt',
+ description: 'Tooling to use DTFM Design Tokens anywhere',
+ cleanUrls: true,
+ /** @see https://vitepress.dev/reference/default-theme-config */
+ themeConfig: {
+ logo: '/images/cobalt-icon-solid.svg',
+ nav: [
+ {
+ text: `v${packageJSON.version}`,
+ items: [{text: 'Changelog', link: 'https://github.com/drwpow/cobalt-ui/blob/main/packages/cli/CHANGELOG.md'}],
+ },
+ ],
+ sidebar: [
+ {
+ text: 'Guides',
+ collapsed: false,
+ items: [
+ {text: 'Getting Started', link: '/guides/getting-started'},
+ {text: 'tokens.json', link: '/guides/tokens'},
+ {text: 'CLI', link: '/guides/cli'},
+ {text: 'Modes', link: '/guides/modes'},
+ ],
+ },
+ {
+ text: 'Tokens',
+ collapsed: true,
+ items: [
+ {text: 'Color', link: '/tokens/color'},
+ {text: 'Dimension', link: '/tokens/dimension'},
+ {text: 'Font Family', link: '/tokens/font-family'},
+ {text: 'Font Weight', link: '/tokens/font-weight'},
+ {text: 'Duration', link: '/tokens/duration'},
+ {text: 'Cubic Bézier', link: '/tokens/cubic-bezier'},
+ {text: 'Number', link: '/tokens/number'},
+ {text: 'Link (ext)', link: '/tokens/link'},
+ {text: 'Stroke Style', link: '/tokens/stroke-style'},
+ {text: 'Border', link: '/tokens/border'},
+ {text: 'Transition', link: '/tokens/transition'},
+ {text: 'Shadow', link: '/tokens/shadow'},
+ {text: 'Gradient', link: '/tokens/gradient'},
+ {text: 'Typography', link: '/tokens/typography'},
+ {text: 'Group', link: '/tokens/group'},
+ {text: 'Alias', link: '/tokens/alias'},
+ {text: 'Custom Tokens', link: '/tokens/custom'},
+ ],
+ },
+ {
+ text: 'Integrations',
+ collapsed: false,
+ items: [
+ {text: 'CSS', link: '/integrations/css'},
+ {text: 'Figma', link: '/integrations/figma'},
+ {text: 'JS/TS', link: '/integrations/js'},
+ {text: 'JSON/Native', link: '/integrations/json'},
+ {text: 'Sass', link: '/integrations/sass'},
+ {text: 'Style Dictionary', link: '/integrations/style-dictionary'},
+ {text: 'Tailwind', link: '/integrations/tailwind'},
+ {text: 'Other', link: '/integrations/other'},
+ ],
+ },
+ {
+ text: 'Advanced',
+ collapsed: true,
+ items: [
+ {text: 'Config', link: '/advanced/config'},
+ {text: 'Node.js API', link: '/advanced/node'},
+ {text: 'Plugin API', link: '/advanced/plugin-api'},
+ {text: 'CI', link: '/advanced/ci'},
+ {text: 'About', link: '/advanced/about'},
+ ],
+ },
+ ],
+ search: {
+ provider: 'algolia',
+ options: {
+ appId: '2U13I82HTZ',
+ apiKey: 'b67c6e8504f5721bb7c0875d044bfddb',
+ indexName: 'cobalt-ui',
+ },
+ },
+ socialLinks: [{icon: 'github', link: 'https://github.com/drwpow/cobalt-ui'}],
+ },
+});
diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts
new file mode 100644
index 00000000..fa1ef9a8
--- /dev/null
+++ b/docs/.vitepress/theme/index.ts
@@ -0,0 +1,17 @@
+// https://vitepress.dev/guide/custom-theme
+import {h} from 'vue';
+import type {Theme} from 'vitepress';
+import DefaultTheme from 'vitepress/theme';
+import './style.css';
+
+export default {
+ extends: DefaultTheme,
+ Layout: () => {
+ return h(DefaultTheme.Layout, null, {
+ // https://vitepress.dev/guide/extending-default-theme#layout-slots
+ });
+ },
+ enhanceApp({app, router, siteData}) {
+ // ...
+ },
+} satisfies Theme;
diff --git a/docs/src/styles/_fonts.scss b/docs/.vitepress/theme/style.css
similarity index 59%
rename from docs/src/styles/_fonts.scss
rename to docs/.vitepress/theme/style.css
index 2143bdda..ef409e66 100644
--- a/docs/src/styles/_fonts.scss
+++ b/docs/.vitepress/theme/style.css
@@ -1,5 +1,7 @@
-@use 'sass:map';
-@use '../../tokens/' as *;
+/**
+ * Customize default theme styling by overriding CSS variables:
+ * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
+ */
@font-face {
font-family: 'Neue Montreal';
@@ -204,3 +206,165 @@
src: url(/fonts/redhatmono-v10-300-normal-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
+
+/**
+ * Typography
+ * -------------------------------------------------------------------------- */
+
+:root {
+ --vp-font-family-base: 'Neue Montreal', -apple-system, 'system-ui', 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
+ --vp-font-family-mono: 'Red Hat Mono', ui-monospace, monospace;
+}
+
+em,
+i {
+ font-variation-settings: 'ital' 900;
+ font-style: normal;
+}
+
+/**
+ * Colors
+ *
+ * Each colors have exact same color scale system with 3 levels of solid
+ * colors with different brightness, and 1 soft color.
+ *
+ * - `XXX-1`: The most solid color used mainly for colored text. It must
+ * satisfy the contrast ratio against when used on top of `XXX-soft`.
+ *
+ * - `XXX-2`: The color used mainly for hover state of the button.
+ *
+ * - `XXX-3`: The color for solid background, such as bg color of the button.
+ * It must satisfy the contrast ratio with pure white (#ffffff) text on
+ * top of it.
+ *
+ * - `XXX-soft`: The color used for subtle background such as custom container
+ * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
+ * on top of it.
+ *
+ * The soft color must be semi transparent alpha channel. This is crucial
+ * because it allows adding multiple "soft" colors on top of each other
+ * to create a accent, such as when having inline code block inside
+ * custom containers.
+ *
+ * - `default`: The color used purely for subtle indication without any
+ * special meanings attched to it such as bg color for menu hover state.
+ *
+ * - `brand`: Used for primary brand colors, such as link text, button with
+ * brand theme, etc.
+ *
+ * - `tip`: Used to indicate useful information. The default theme uses the
+ * brand color for this by default.
+ *
+ * - `warning`: Used to indicate warning to the users. Used in custom
+ * container, badges, etc.
+ *
+ * - `danger`: Used to show error, or dangerous message to the users. Used
+ * in custom container, badges, etc.
+ * -------------------------------------------------------------------------- */
+
+:root {
+ --vp-c-default-1: var(--vp-c-gray-1);
+ --vp-c-default-2: var(--vp-c-gray-2);
+ --vp-c-default-3: var(--vp-c-gray-3);
+ --vp-c-default-soft: var(--vp-c-gray-soft);
+
+ --vp-c-brand-1: oklch(60% 0.216564 269);
+ --vp-c-brand-2: oklch(50% 0.216583 268);
+ --vp-c-brand-3: oklch(60% 0.216564 269);
+ --vp-c-brand-soft: oklch(60% 0.216564 269/0.2);
+
+ --vp-c-tip-1: var(--vp-c-brand-1);
+ --vp-c-tip-2: var(--vp-c-brand-2);
+ --vp-c-tip-3: var(--vp-c-brand-3);
+ --vp-c-tip-soft: var(--vp-c-brand-soft);
+
+ --vp-c-warning-1: var(--vp-c-yellow-1);
+ --vp-c-warning-2: var(--vp-c-yellow-2);
+ --vp-c-warning-3: var(--vp-c-yellow-3);
+ --vp-c-warning-soft: var(--vp-c-yellow-soft);
+
+ --vp-c-danger-1: var(--vp-c-red-1);
+ --vp-c-danger-2: var(--vp-c-red-2);
+ --vp-c-danger-3: var(--vp-c-red-3);
+ --vp-c-danger-soft: var(--vp-c-red-soft);
+}
+
+/**
+ * Component: Button
+ * -------------------------------------------------------------------------- */
+
+:root {
+ --vp-button-brand-border: transparent;
+ --vp-button-brand-text: var(--vp-c-white);
+ --vp-button-brand-bg: var(--vp-c-brand-3);
+ --vp-button-brand-hover-border: transparent;
+ --vp-button-brand-hover-text: var(--vp-c-white);
+ --vp-button-brand-hover-bg: var(--vp-c-brand-2);
+ --vp-button-brand-active-border: transparent;
+ --vp-button-brand-active-text: var(--vp-c-white);
+ --vp-button-brand-active-bg: var(--vp-c-brand-1);
+}
+
+/**
+ * Component: Home
+ * -------------------------------------------------------------------------- */
+
+:root {
+ --vp-home-hero-name-color: transparent;
+ --vp-home-hero-name-background: -webkit-linear-gradient(120deg, oklch(60% 0.216564 269) 30%, oklch(50% 0.216583 268));
+ --vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
+ --vp-home-hero-image-filter: blur(44px);
+}
+
+@media (min-width: 640px) {
+ :root {
+ --vp-home-hero-image-filter: blur(56px);
+ }
+}
+
+@media (min-width: 960px) {
+ :root {
+ --vp-home-hero-image-filter: blur(68px);
+ }
+}
+
+/**
+ * Component: Custom Block
+ * -------------------------------------------------------------------------- */
+
+:root {
+ --vp-custom-block-tip-border: transparent;
+ --vp-custom-block-tip-text: var(--vp-c-text-1);
+ --vp-custom-block-tip-bg: var(--vp-c-brand-soft);
+ --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
+}
+
+/**
+ * Component: Algolia
+ * -------------------------------------------------------------------------- */
+
+.DocSearch {
+ --docsearch-primary-color: var(--vp-c-brand-1) !important;
+}
+
+/**
+ * Page: Home
+ * -------------------------------------------------------------------------- */
+
+.VPHome {
+ background-image: url('/images/home-bg.png');
+ background-repeat: no-repeat;
+ background-position: center 3rem;
+ background-size: 200% auto;
+}
+
+.dark .VPHome {
+ background-image: url('/images/home-bg-dark.png');
+}
+
+@media (min-width: 800px) {
+ .VPHome {
+ background-size: 100% auto;
+ background-position: 100% 4rem;
+ }
+}
diff --git a/docs/src/pages/docs/reference/about.md b/docs/advanced/about.md
similarity index 52%
rename from docs/src/pages/docs/reference/about.md
rename to docs/advanced/about.md
index b5db13f3..a46d6a90 100644
--- a/docs/src/pages/docs/reference/about.md
+++ b/docs/advanced/about.md
@@ -1,23 +1,24 @@
---
-title: About Cobalt
-layout: ../../../layouts/docs.astro
+title: About
---
-# About Cobalt
+# About
+
+Cobalt was created to support the [Design Tokens Format Module (DTFM)](https://designtokens.org) and provide a pluggable, extensible interface for generating code for any platform.
## Project Goals
-1. Support the complete and full [Design Tokens Format Module](https://design-tokens.github.io/community-group/format) spec
-2. Support a pluggable and configurable architecture, enabling users and the community to write their own plugins to generate any format
-3. Make syncing from Figma easy and automatable ([docs](/docs/integrations/tokens-studio))
+1. Support the complete and full [Design Tokens Format Module](https://design-tokens.github.io/community-group/format) spec.
+1. Offer the widest compatiblity possible for any platform.
+1. Support a pluggable and configurable architecture, enabling users to write their own plugins to generate any format.
-## Why the name “Cobalt”?
+## Why the name “Cobalt?”
The name **Cobalt** has three meanings:
-1. Cobalt [the element](https://en.wikipedia.org/wiki/Cobalt) is a nod to design tokens being the “atoms” of your design system
+1. Cobalt [the element](https://en.wikipedia.org/wiki/Cobalt) is a nod to design tokens being the “atoms” of your design system.
_Fun fact: the animated token icons on this docs site are a nod to Cobalt’s hexagonal atomic structure_
-2. Cobalt [the pigment](https://artsartistsartwork.com/history-of-the-colour-blue-in-art/) is a nod to blue being the last missing color in art history, just as design tokens are the last missing piece of design systems
+2. Cobalt [the pigment](https://artsartistsartwork.com/history-of-the-colour-blue-in-art) is a nod to blue being the last missing color in art history, just as design tokens are the last missing piece of design systems.
_Fun fact: Van Gogh once said “Cobalt is a divine colour and there is nothing so beautiful for putting atmosphere around things”_
-3. Cobalt the color is a nod to [blueprints](https://en.wikipedia.org/wiki/Blueprint)
+3. Cobalt the color is a nod to [blueprints](https://en.wikipedia.org/wiki/Blueprint).
_Fun fact: blueprints originally were colored with Prussian Blue (ferrous ferrocyanide), not Cobalt, for cost reasons_
diff --git a/docs/advanced/ci.md b/docs/advanced/ci.md
new file mode 100644
index 00000000..06cb3390
--- /dev/null
+++ b/docs/advanced/ci.md
@@ -0,0 +1,57 @@
+---
+title: CI
+---
+
+# CI
+
+Using your preferred CI stack, here’s an example of how you could add Cobalt to your CI. First, we’ll take a `package.json` that had an existing `npm run build` command, and add `co build` script to it:
+
+::: code-group
+
+```json [package.json]
+{
+ "scripts": {
+ "build": "npm run build:app", // [!code --]
+ "build": "npm run build:tokens && npm run build:app", // [!code ++]
+ "build:app": "vite build",
+ "build:tokens": "co build" // [!code ++]
+ }
+}
+```
+
+:::
+
+This is just a generic example. The important part is that `co build` is run somehow during the build.
+
+## GitHub Actions
+
+```yaml
+name: CI
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+concurrency:
+ group: ci-\${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: actions/setup-node@v3
+ with:
+ node-version: 20
+ - run: npm i
+ - run: npm run build
+```
+
+This will run `co build` on every code change, which validates your `tokens.json` and runs all plugins to make sure they’re all working as expected.
+
+## Publishing to npm
+
+You could then take the additional step of using a package versioning tool like [Changesets](https://github.com/changesets/changesets) to release npm packages from CI ([Cobalt does this!](https://github.com/drwpow/cobalt-ui/blob/main/.github/workflows/release.yml)).
diff --git a/docs/advanced/config.md b/docs/advanced/config.md
new file mode 100644
index 00000000..0b5fc48b
--- /dev/null
+++ b/docs/advanced/config.md
@@ -0,0 +1,147 @@
+---
+title: Config
+---
+
+# Config
+
+Customizing Cobalt and managing plugins requires you to add a `tokens.config.mjs` file in the root of your project. Here’s an example configuration with all settings and defaults:
+
+::: code-group
+
+```js [tokens.config.mjs]
+import pluginJS from '@cobalt-ui/plugin-js';
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: './tokens.json',
+ outDir: './tokens/',
+ plugins: [pluginJS()],
+
+ // token type options
+};
+```
+
+:::
+
+## `tokens`
+
+The `tokens` property is where you tell Cobalt your `tokens.json` file lives ([or files](#multiple-schemas)). By default this is set to `./tokens.json`, so this option can be omitted if your tokens manifest lives there.
+
+### YAML
+
+Cobalt supports `tokens.json` as YAML as well:
+
+::: code-group
+
+```js [tokens.config.mjs]
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: './tokens.yaml',
+};
+```
+
+:::
+
+::: info
+The file extension must be `.yml` or `.yaml` to be parsed as YAML
+:::
+
+### Remote schemas
+
+Cobalt can load tokens from any **publicly-available** URL:
+
+::: code-group
+
+```js [tokens.config.mjs]
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: 'https://my-bucket.s3.amazonaws.com/tokens.json',
+};
+```
+
+:::
+
+### npm
+
+To load tokens from an npm package, update `config.tokens` to point to the **full JSON path** (not merely the root package):
+
+::: code-group
+
+```js [tokens.config.mjs]
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: '@my-scope/my-tokens', // [!code --]
+ tokens: '@my-scope/my-tokens/tokens.json', // [!code ++]
+};
+```
+
+:::
+
+### Multiple schemas
+
+Cobalt supports loading multiple tokens schemas by passing an array:
+
+::: code-group
+
+```js [tokens.config.mjs]
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: ['./base.json', './theme.json', './overrides.json'],
+};
+```
+
+:::
+
+Cobalt will flatten these schemas in order, with the latter entries overriding the former if there are any conflicts. The final result of all the combined schemas **must** result in a valid tokens.json.
+
+::: info
+All aliases must refer to the same document. For example, instead of `{./theme.json#/color.action.50}`, omit the filepath and use `{color.action.50}` as if it were in the same file.
+:::
+
+## `outdir`
+
+`outdir` is the **output directory** where all plugins will generate files to. This can only be set to a directory, not a file, since you’ll almost always use multiple plugins and generate multiple output files. By default this is `./tokens/`, but you can move this anywhere. Note that each plugin decides where to generate its file(s), but you can usually configure additional options per-plugin.
+
+## `plugins`
+
+The following official plugins are available. Refer to each’s documentation to learn all it can do as well as all the options available:
+
+- [@cobalt-ui/plugin-css](/integrations/css): Generate CSS variables, and optionally utility CSS
+- [@cobalt-ui/plugin-js](/integrations/js): Generate JavaScript + TypeScript
+- [@cobalt-ui/plugin-js](/integrations/json): Generate JSON for universal usage
+- [@cobalt-ui/plugin-sass](/integrations/sass): Generate Sass (compatible with the CSS plugin)
+- [@cobalt-ui/plugin-tailwind](/integrations/tailwind): Generate a Tailwind CSS theme (compatible with the CSS plugin)
+- @cobalt-ui/plugin-img: TODO
+- @cobalt-ui/plugin-php: TODO
+- @cobalt-ui/plugin-python: TODO
+- @cobalt-ui/plugin-ruby: TODO
+- @cobalt-ui/plugin-elixir: TODO
+
+_If you’ve created a Cobalt plugin of your own, please [suggest yours](https://github.com/drwpow/cobalt-ui)!_
+
+### Custom Plugins
+
+Creating custom plugins is designed to be easy. Please [view the plugin guide](/advanced/plugin-api) to learn how to create your own.
+
+## Token Type Options
+
+Some token types allow for extra configuration.
+
+## Color
+
+::: code-group
+
+```js [tokens.config.mjs]
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ color: {
+ convertToHex: false, // Convert all colors to sRGB hexadecimal (default: false). By default, colors are kept in their formats
+ },
+};
+```
+
+:::
+
+| Name | Type | Description |
+| :------------------- | :-------: | :--------------------------------------------------------------------------------------------------------------- |
+| `color.convertToHex` | `boolean` | Convert this color to sRGB hexadecimal. By default, colors are kept in the original formats they’re authored in. |
diff --git a/docs/advanced/node.md b/docs/advanced/node.md
new file mode 100644
index 00000000..25c398b4
--- /dev/null
+++ b/docs/advanced/node.md
@@ -0,0 +1,38 @@
+---
+title: Node.js API
+---
+
+# Node.js API
+
+Cobalt’s Node.js API is for parsing and validating the [Design Tokens Format Module](https://designtokens.org) (DTFM) standard. It can’t output code like the [CLI](/guides/cli) can, but it is a lightweight and fast parser/validator for the DTFM spec that could even be used in client code if desired.
+
+## Setup
+
+```sh
+npm install @cobalt-ui/core
+```
+
+## Usage
+
+Parse a `tokens.json` file into a JS object
+
+
+```js
+import co from '@cobalt-ui/core';
+
+const designTokens = {
+ color: {
+ red: {$type: 'color', $value: '#e34850'},
+ green: {$type: 'color', $value: '#2d9d78'},
+ blue: {$type: 'color', $value: '#2680eb'},
+ },
+};
+
+const {errors, warnings, result} = co.parse(designTokens);
+```
+
+| Name | Type | Description |
+| :--------- | :------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------ |
+| `result` | Token[] | Flattened array of all parsed tokens in the schema (this may be incomplete if `errors` present) |
+| `errors` | `string[]` \| `undefined` | If present, unrecoverable errors were encountered (you should probably `throw` with these messages). |
+| `warnings` | `string[]` \| `undefined` | If present, the parser found schema issues that are likely undesirable, but the schema is still usable (you should probably show the user). |
diff --git a/docs/advanced/plugin-api.md b/docs/advanced/plugin-api.md
new file mode 100644
index 00000000..5ed2318e
--- /dev/null
+++ b/docs/advanced/plugin-api.md
@@ -0,0 +1,208 @@
+---
+title: Plugin API
+---
+
+# Plugin API
+
+Creating your own Cobalt plugins is easy if you’re comfortable with JavaScript. This guide is for creating a custom plugin yourself; if you’re looking for instructions on how to use existing plugins, [see the Getting Started guide](/guides/getting-started#next-steps).
+
+## Plugin Format
+
+A Cobalt plugin is designed similarly to a Rollup or Vite plugin, if you’re familiar with those (no worries if you’re not). A plugin is essentially **any function that returns an object with the following keys**:
+
+| Key | Type | Description |
+| :------- | :--------: | :----------------------------------------------------------- |
+| `name` | `string` | **Required.** The name of your plugin (shown on errors) |
+| `config` | `function` | (Optional) Read the user’s config, and optionally modify it. |
+| `build` | `function` | **Required.** The build output of your plugin. |
+
+_Note: the following examples will be using TypeScript, but JavaScript will work just as well if you prefer!_
+
+```ts
+import type {Plugin} from '@cobalt-ui/core';
+
+export default function myPlugin(): Plugin {
+ return {
+ name: 'my-plugin',
+ config(config) {
+ // read final user config
+ },
+ async build({tokens, metadata, rawSchema}) {
+ // (your plugin code here)
+
+ return [
+ {
+ filename: 'my-filename.json',
+ contents: tokens,
+ },
+ ];
+ },
+ };
+}
+```
+
+### Accepting Options
+
+Your plugin can accept options as the parameters of your main function. The structure is up to you and what makes sense of your plugin. Here’s an example of letting a user configure the `filename`:
+
+```ts
+import type {Plugin} from '@cobalt-ui/core';
+
+export interface MyPluginOptions {
+ /** (Optional) Set the output filename */
+ filename?: string;
+ // add more options here!
+}
+
+export default function myPlugin(options: MyPluginOptions = {}): Plugin {
+ const filename = options.filename || 'default-filename.json'; // be sure to always set a default!
+ return {
+ name: 'my-plugin',
+ async build({tokens, rawSchema}) {
+ // (your plugin code here)
+
+ return [
+ {
+ filename,
+ contents: tokens,
+ },
+ ];
+ },
+ };
+}
+```
+
+You’d then pass any options into `tokens.config.mjs`:
+
+```js
+import myPlugin from './my-plugin.js';
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ plugins: [
+ myPlugin({
+ filename: 'custom.json',
+ }),
+ ],
+};
+```
+
+You can then expand `options` to be whatever shape you need it to be.
+
+## `name`
+
+Naming your plugin helps identify it in case something goes wrong during the build. You can name your plugin anything.
+
+## `config()`
+
+The `config()` function is an optional callback that can read the final user config or modify it. Use it if you need to read a user’s setting. Though you _can_ mutate the config, don’t do so unless absolutely necessary!
+
+```ts
+import type {Plugin} from '@cobalt-ui/core';
+
+export default function myPlugin(): Plugin {
+ let outDir: URL | undefined;
+ return {
+ name: 'my-plugin',
+ config(config) {
+ outDir = config.outDir; // read the user’s outDir from the config, and save it
+ // return nothing to leave config unaltered
+ },
+ async build({tokens, rawSchema}) {
+ console.log(outDir); // now config info is accessible within the build() function
+
+ // (your plugin code here)
+
+ return [{filename: 'my-filename.json', contents: tokens}];
+ },
+ };
+}
+```
+
+`config()` will be fired _after_ the user’s config has been fully loaded and all plugins are instantiated, and _before_ any build happens.
+
+## `build()`
+
+The `build()` function takes one parameter object with 3 keys:
+
+| Name | Type | Description |
+| :---------- | :-------------------: | :---------------------------------------------------------- |
+| `tokens` | `Token[]` | An array of tokens with metadata ([docs](#token-structure)) |
+| `rawSchema` | `DTFM JSON` | The original `tokens.json` file, unedited. |
+| `metadata` | `Record` | (currently unused) |
+
+After running, and formatting your output, the `build()` function should return an array of objects with the following properties:
+
+| Name | Type | Description |
+| :--------- | :------------------: | :------------------------------------------------------------------ |
+| `filename` | `string` | Filename (relative to user’s `outDir` setting, default `./tokens/`) |
+| `contents` | `string` \| `Buffer` | File contents to be written to disk. |
+
+```ts
+export default function myPlugin(): Plugin {
+ return {
+ name: 'my-plugin',
+ async build({tokens, rawSchema}) {
+ // (your plugin code here)
+
+ return [
+ {filename: './output-1.json', contents: jsonContents},
+ {filename: './output-2.svg', contents: svgContents},
+ ];
+ },
+ };
+}
+```
+
+### Token structure
+
+Cobalt gives you more context when dealing with tokens. Inspecting each individual token will yield the following:
+
+```js
+{
+ id: 'color.brand.green', // the full ID of the token
+ $type: 'color', // the original $type
+ $value: '#40c362', // the normalized $value
+ $extensions: {
+ mode: {…} // normalized modes
+ },
+ _group: {…} // metadata about the token’s parent group
+ _original: {…} // the original node untouched from tokens.json (including unresolved aliases, etc.)
+}
+```
+
+### Tips
+
+- For `build()`, return a **relative filename**. That way it respects the user’s `outDir` setting.
+- Returning only one file is normal! Most plugins only output one file.
+- Use JSDoc comments as much as possible! They go a long way in good DX of your plugin.
+- For the full ID of the token, a dot (`.`) always represents a group. So for `color.brand.green`, you’re looking at the `green` token, inside the `brand` group, inside the `color` group. Groups aren’t allowed to have dots in their names.
+- Cobalt will always resolve `$value` to the final value, even for aliased tokens. To see the original alias name, see `_original.$value`.
+
+## Lifecycle
+
+Cobalt executes in the following order:
+
+1. **Plugin instantiation.** All plugins are loaded, in array order, in the user’s config.
+2. **Config.** `config()` is called on every plugin (if present), also in array order. Note that if any plugin modifies the config, the changes will only be picked up by plugins that appear later in the array.
+3. **Build.** `build()` is called on every plugin, in parallel.
+4. **Write.** Cobalt writes each plugin’s file(s) to disk after it’s done. This also happens in parallel, and happens as soon as each plugin finishes.
+
+## Testing
+
+To test your plugin working on your design tokens, add it to your `tokens.config.mjs`:
+
+```js
+import myPlugin from './my-plugin.js';
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ plugins: [myPlugin()],
+};
+```
+
+Now when you run `co build`, your plugin will run and you can see its output.
+
+## Examples
+
+Examples of plugins may be found [in the original source repo](https://github.com/drwpow/cobalt-ui/tree/main/packages).
diff --git a/docs/astro.config.js b/docs/astro.config.js
deleted file mode 100644
index 9cf9332f..00000000
--- a/docs/astro.config.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import {defineConfig} from 'astro/config';
-
-export default defineConfig({
- site: `https://cobalt-ui.pages.dev`,
-});
diff --git a/docs/guides/cli.md b/docs/guides/cli.md
new file mode 100644
index 00000000..7921aa1b
--- /dev/null
+++ b/docs/guides/cli.md
@@ -0,0 +1,79 @@
+---
+title: CLI
+---
+
+# CLI
+
+The Cobalt CLI is the primary way to turn your Design Token Format Module (DTFM) design tokens into code. To install it to your project, run:
+
+```sh
+npm i -D @cobalt-ui/cli
+```
+
+## Build
+
+Most of the time you’ll be running the **build** command:
+
+```sh
+npx co build
+```
+
+This first **validates** your schema (and will error on any schema errors), then it generates code using your installed [plugins](/guides/getting-started#next-steps).
+
+::: info
+If you end up with stale assets in `outDir` from old tokens or plugins no longer used, there’s not an option to clear out this directory on build (Cobalt doesn’t assume it owns this folder). However, there are easy-to-use tools such as [del-cli](https://www.npmjs.com/package/del-cli) you can run before each build.
+:::
+
+### Watch mode
+
+To build your tokens as you work, add the `--watch` flag:
+
+```sh
+npx co build --watch
+```
+
+This watches for any changes in your `tokens.json` file, and automatically runs a build on any change. Useful for developing locally!
+
+## Validate
+
+To only validate your `tokens.json` schema without loading plugins, run the **check** command:
+
+```sh
+npx co check [path]
+```
+
+This will show any errors and warnings in your schema. `[path]` can be ommitted if you only want to validate the file(s) set to [`token`](/advanced/config#token) in your [config file](/advanced/config).
+
+## Bundle
+
+To combine multiple `tokens.json` files into one, use the `bundle` command:
+
+```sh
+npx co bundle --out [path]
+```
+
+Be sure to specify a `[path]`!
+
+## Convert
+
+The **convert** comand is useful for converting a foreign format to DTFM. Currently only converting from the [Style Dictionary token format](https://amzn.github.io/style-dictionary) format is supported.
+
+### Style Dictionary Format
+
+To convert from the [Style Dictionary token format](https://amzn.github.io/style-dictionary) to DTFM, run:
+
+```sh
+npx co convert [input] --out [output]
+```
+
+[See full guide](/integrations/style-dictionary)
+
+## Init
+
+You can initialize a placeholder `tokens.json` file with the **init** command:
+
+```sh
+npx co init
+```
+
+There’s not much here, but it can at least save a little typing.
diff --git a/docs/guides/getting-started.md b/docs/guides/getting-started.md
new file mode 100644
index 00000000..8795f713
--- /dev/null
+++ b/docs/guides/getting-started.md
@@ -0,0 +1,212 @@
+---
+title: Getting Started
+---
+
+# Getting Started
+
+Cobalt turns your [design tokens](/guides/design-tokens) into code using a CLI or Node.js. Cobalt is configurable and pluggable, and can generate [JavaScript](/integrations/js), [TypeScript](/integrations/js),
+[JSON](/integrations/json), [CSS](/integrations/css), and [Sass](/integrations/sass) via the official plugins, and even [integrate with Tailwind CSS](/integrations/tailwind).
+
+You can also create your own plugin to turn your design tokens into anything using [the plugin API](/advanced/plugin-api).
+
+## Setup
+
+With [the latest version of Node installed](https://nodejs.org), install the Cobalt CLI using npm, along with any plugins you’d like (for our example we’ll install the JS and CSS plugins, but you can install fewer or more depending on what you’d like):
+
+```sh
+npm i -D @cobalt-ui/cli @cobalt-ui/plugin-css @cobalt-ui/plugin-js
+```
+
+Next, we’ll create a `tokens.json` file in the root of our project (or `tokens.yaml`). This is where we’ll put all our [tokens](/guides/tokens):
+
+::: code-group
+
+```json [JSON]
+{
+ "color": {
+ "$type": "color",
+ "base": {
+ "gray": {
+ "0": {"$value": "#f6f8fa"},
+ "1": {"$value": "#eaeef2"},
+ "2": {"$value": "#d0d7de"},
+ "3": {"$value": "#afb8c1"},
+ "4": {"$value": "#8c959f"},
+ "5": {"$value": "#6e7781"},
+ "6": {"$value": "#57606a"},
+ "7": {"$value": "#424a53"},
+ "8": {"$value": "#32383f"},
+ "9": {"$value": "#24292f"}
+ },
+ "blue": {
+ "0": {"$value": "#ddf4ff"},
+ "1": {"$value": "#b6e3ff"},
+ "2": {"$value": "#80ccff"},
+ "3": {"$value": "#54aeff"},
+ "4": {"$value": "#218bff"},
+ "5": {"$value": "#0969da"},
+ "6": {"$value": "#0550ae"},
+ "7": {"$value": "#033d8b"},
+ "8": {"$value": "#0a3069"},
+ "9": {"$value": "#002155"}
+ }
+ },
+ "semantic": {
+ "action": "{color.base.blue.5}",
+ "textColor": "{color.base.gray.9}"
+ }
+ },
+ "fontStack": {
+ "$type": "fontFamily",
+ "sansSerif": {
+ "$value": ["-apple-system", "BlinkMacSystemFont", "Segoe UI", "Noto Sans", "Helvetica", "Arial", "sans-serif", "Apple Color Emoji", "Segoe UI Emoji"]
+ }
+ },
+ "space": {
+ "$type": "dimension",
+ "xxsmall": {"$value": "2px"},
+ "xsmall": {"$value": "4px"},
+ "small": {"$value": "6px"},
+ "medium": {"$value": "8px"},
+ "large": {"$value": "12px"},
+ "xlarge": {"$value": "16px"}
+ }
+}
+```
+
+```yaml [YAML]
+color:
+ $type: color
+ base:
+ gray:
+ '0':
+ $value: '#f6f8fa'
+ '1':
+ $value: '#eaeef2'
+ '2':
+ $value: '#d0d7de'
+ '3':
+ $value: '#afb8c1'
+ '4':
+ $value: '#8c959f'
+ '5':
+ $value: '#6e7781'
+ '6':
+ $value: '#57606a'
+ '7':
+ $value: '#424a53'
+ '8':
+ $value: '#32383f'
+ '9':
+ $value: '#24292f'
+ blue:
+ '0':
+ $value: '#ddf4ff'
+ '1':
+ $value: '#b6e3ff'
+ '2':
+ $value: '#80ccff'
+ '3':
+ $value: '#54aeff'
+ '4':
+ $value: '#218bff'
+ '5':
+ $value: '#0969da'
+ '6':
+ $value: '#0550ae'
+ '7':
+ $value: '#033d8b'
+ '8':
+ $value: '#0a3069'
+ '9':
+ $value: '#002155'
+ semantic:
+ action: '{color.base.blue.5}'
+ textColor: '{color.base.gray.9}'
+fontStack:
+ $type: fontFamily
+ sansSerif:
+ $value:
+ - -apple-system
+ - BlinkMacSystemFont
+ - Segoe UI
+ - Noto Sans
+ - Helvetica
+ - Arial
+ - sans-serif
+ - Apple Color Emoji
+ - Segoe UI Emoji
+space:
+ $type: dimension
+ xxsmall:
+ $value: 2px
+ xsmall:
+ $value: 4px
+ small:
+ $value: 6px
+ medium:
+ $value: 8px
+ large:
+ $value: 12px
+ xlarge:
+ $value: 16px
+```
+
+:::
+
+Then we’ll configure our plugins. Create a `tokens.config.mjs` file ([docs](/advanced/config)) also in the root of your project:
+
+::: code-group
+
+```js [tokens.config.mjs]
+import pluginCSS from '@cobalt-ui/plugin-css';
+import pluginJS from '@cobalt-ui/plugin-js';
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: './tokens.json',
+ outDir: './tokens/',
+ plugins: [pluginCSS(/* options */), pluginJS(/* options */)],
+};
+```
+
+:::
+
+Lastly, run the following command to generate all code from your tokens:
+
+```sh
+npx co build
+```
+
+You should see a new `/tokens/` folder with your newly-generated tokens:
+
+```
+├── package.json
+├── tokens/ <-- ✨ New ✨
+│ ├── index.css
+│ ├── index.d.ts
+│ ├── index.js
+├── tokens.config.mjs
+└── tokens.json
+```
+
+You can now use the generated CSS and/or JS in your project!
+
+You can also change any settings in `tokens.config.mjs` ([docs](/advanced/config)) such as the name of `tokens.json` and the output folder, as well as configure plugins individually (be sure to read guides on all each plugin can do—some can do quite a bit!).
+
+## Next Steps
+
+This covers the basics, but there’s a lot more you can do with your design tokens:
+
+- [Learn about the DTFM format](/guides/tokens)
+- [Learn about Modes](/guides/modes) (unique to Cobalt!)
+- See additional integrations:
+ - [CSS](/integrations/css)
+ - [JavaScript/TypeScript](/integrations/js)
+ - [JSON/Native](/integrations/json)
+ - [Sass](/integrations/sass)
+ - [Tailwind CSS](/integrations/tailwind)
+- View advanced guides
+ - [All Config Options](/advanced/config)
+ - [Plugin API](/advanced/plugin-api) for making your own plugins easily
+ - [Integrating with CI](/advanced/ci)
diff --git a/docs/guides/modes.md b/docs/guides/modes.md
new file mode 100644
index 00000000..42be14d7
--- /dev/null
+++ b/docs/guides/modes.md
@@ -0,0 +1,352 @@
+---
+title: Modes
+---
+
+# Modes
+
+Modes are **alternate forms of a token** that can be triggered to activate in different contexts. They allow your design system to account for different states or contexts that allow some values to change while others remain the same.
+
+To explain this concept, we’ll explore 2 common usages: **color** and **typography**.
+
+## Examples
+
+### Example 1: Color modes
+
+![GitHub’s theme panel](/images/mode-github.png)
+
+In this screenshot of GitHub’s dashboard you’ll find 5 color themes: _Light default_, _Light high contrast_, _Dark default_, _Dark high contrast_, and _Dark dimmed_ (shown above). How might that be
+represented in tokens?
+
+::: info
+
+This is an older screenshot that is missing some of GitHub’s newer color modes, but the core idea hasn’t changed.
+
+:::
+
+#### Without Modes
+
+Consider the `red` and `white` colors in the system. Whereas `red` has a different value for each mode, `white` is an absolute value that doesn’t change. A (wrong) first attempt may look
+something like:
+
+::: code-group
+
+```json [JSON]
+{
+ "color": {
+ "$type": "color",
+ "red": {"$value": "#fa4549"},
+ "red-light": {"$value": "#fa4549"},
+ "red-lightHighContrast": {"$value": "#d5232c"},
+ "red-dark": {"$value": "#f85149"},
+ "red-darkHighContrast": {"$value": "#ff6a69"},
+ "red-darkDimmed": {"$value": "#f47067"},
+ "white": {"$value": "#ffffff"}
+ }
+}
+```
+
+```yaml [YAML]
+color:
+ $type: color
+ red:
+ $value: '#fa4549'
+ red-light:
+ $value: '#fa4549'
+ red-lightHighContrast:
+ $value: '#d5232c'
+ red-dark:
+ $value: '#f85149'
+ red-darkHighContrast:
+ $value: '#ff6a69'
+ red-darkDimmed:
+ $value: '#f47067'
+ white:
+ $value: '#ffffff'
+```
+
+:::
+
+But off the bat we have some problems:
+
+- Color themes are scattered between our original colors
+- Token names now carry implicit context
+- There’s not a clear abstraction of color themes
+- It’s unclear when `[color]-[mode]` exists, and when it doesn’t
+- Strict naming guidelines must be enforced for this to work long-term
+- Updating/managing color modes can become a precarious game of find-and-replace
+- What if `red-darker` was added in the future—do we now have `red-darker`, `red-darker-dark`, and `red-darker-light`?
+
+#### With Modes
+
+**Modes** exist to solve these problems by decoupling token names from context and state. This is how it can be represented with modes (using the `$extensions` property from the token syntax):
+
+::: code-group
+
+```json [JSON] {7-13}
+{
+ "color": {
+ "$type": "color",
+ "red": {
+ "$value": "#fa4549",
+ "$extensions": {
+ "mode": {
+ "light": "#fa4549",
+ "lightHighContrast": "#d5232c",
+ "dark": "#f85149",
+ "darkHighContrast": "#ff6a69",
+ "darkDimmed": "#f85149"
+ }
+ }
+ }
+ }
+}
+```
+
+```yaml [YAML] {6-11}
+color:
+ $type: color
+ red:
+ $value: '#fa4549'
+ $extensions:
+ mode:
+ light: '#fa4549'
+ lightHighContrast: '#d5232c'
+ dark: '#f85149'
+ darkHighContrast: '#c38000'
+ darkDimmed: '#f85149'
+```
+
+:::
+
+Our tokens are vastly improved by having clear colors, and clear color modes. And color modes can be easily modified without affecting any names. Colors can optionally have mode variations, or not. And best of all, application-specific
+context isn’t affecting your token names.
+
+This simplifies your application code, too, as, you can simply refer to `color.red` and the mode can be inferred based on the global context.
+below to see the “how”).
+
+#### With @cobalt/plugin-css
+
+If using [@cobalt/plugin-css](/integrations/css), you could generate CSS to handle these modes. That would look something like:
+
+```js
+import pluginCSS from '@cobalt-ui/plugin-css';
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: './tokens.json',
+ outDir: './tokens/',
+ plugins: [
+ pluginCSS({
+ modeSelectors: [
+ {mode: 'light', selectors: ['@media (prefers-color-scheme: light)', 'body[data-color-mode="light"]']},
+ {mode: 'lightHighContrast', selectors: ['@media (prefers-color-scheme: light) and (prefers-contrast: more)', 'body[data-color-mode="lightHighContrast"]']},
+ {mode: 'dark', selectors: ['@media (prefers-color-scheme: dark)', 'body[data-color-mode="dark"]']},
+ {mode: 'darkHighContrast', selectors: ['@media (prefers-color-scheme: dark) and (prefers-contrast: more)', 'body[data-color-mode="darkHighContrast"]']},
+ {mode: 'darkDimmed', selectors: ['body[data-color-mode="darkDimmed"]']},
+ ],
+ }),
+ ],
+};
+```
+
+Then in your CSS, the correct color mode would apply automatically in most instances, but you could also set `` to override it. Also note there aren’t browser-global colorblind
+preferences, so if you added a colorblind color mode, it would have to be initialized manually (i.e. user preference).
+
+### Example 2: Text size modes
+
+![Apple’s Human Interface Guidelines recommended text sizes](/images/mode-apple.png)
+
+_Apple’s dynamic text sizes use modes to control multiple type scales._
+
+#### Without Modes
+
+Another common example is **text size**. If users need to make the text bigger or smaller, they can adjust to their taste. But trying to have this context exist in the token names can result in pretty long values (note this is just **ONE** text size):
+
+::: code-group
+
+```json [JSON]
+{
+ "typography": {
+ "size": {
+ "title1-xSmall": {"$value": "25px"},
+ "title1-Small": {"$value": "26px"},
+ "title1-Medium": {"$value": "27px"},
+ "title1-Large": {"$value": "28px"},
+ "title1-xLarge": {"$value": "30px"},
+ "title1-xxLarge": {"$value": "32px"},
+ "title1-xxxLarge": {"$value": "32px"}
+ }
+ }
+}
+```
+
+```yaml [YAML]
+typography:
+ size:
+ title1-xSmall:
+ $value: 25px
+ title1-Small:
+ $value: 26px
+ title1-Medium:
+ $value: 27px
+ title1-Large:
+ $value: 28px
+ title1-xLarge:
+ $value: 30px
+ title1-xxLarge:
+ $value: 32px
+ title1-xxxLarge:
+ $value: 32px
+```
+
+:::
+
+Naming a font size token as `typography.size.title1-Medium` or `typography.size.title2-Medium` is a bad idea, because then every level of your application must be aware of the user’s current preference settings.
+And if values ever change, now your entire application must be updated everywhere.
+
+### With Modes
+
+Instead, by declaring font sizes as modes, the value becomes much more portable: `typography.size.title1`.
+
+::: code-group
+
+```json [JSON] {9-17}
+{
+ "typography": {
+ "size": {
+ "title1": {
+ "$name": "Title 1",
+ "$type": "dimension",
+ "$value": "28px",
+ "$extensions": {
+ "mode": {
+ "xSmall": "25px",
+ "Small": "26px",
+ "Medium": "27px",
+ "Large": "28px",
+ "xLarge": "30px",
+ "xxLarge": "32px",
+ "xxxLarge": "32px"
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+```yaml [YAML] {8-15}
+typography:
+ size:
+ title1:
+ $name: Title 1
+ $type: dimension
+ $value: 28px
+ $extensions:
+ mode:
+ xSmall: 25px
+ Small: 26px
+ Medium: 27px
+ Large: 28px
+ xLarge: 30px
+ xxLarge: 32px
+ xxxLarge: 32px
+```
+
+:::
+
+Now the user preferences only have to be dealt with in the global context, and the rest of your code will adapt.
+
+### Additional Examples
+
+To see how to use modes in specific languages, see the following plugin docs:
+
+- [@cobalt-ui/plugin-css](/integrations/css#mode-selectors")
+- [@cobalt-ui/plugin-js](/integrations/js)
+- [@cobalt-ui/plugin-sass](/integrations/sass)
+
+## Best practices
+
+A mode is best used for **2 variations that are never used together.**
+
+Back to the color example, if a user has requested high contrast colors, we’d never want to show them the default (non-high contrast) green; we’d want to preserve their preferences.
+
+So following that, here are some common scenarios for when modes should—or shouldn’t—be used.
+
+::: tip ✅ Do
+
+Do use modes for when a user can’t be in 2 contexts on the same page:
+
+- User preferences (e.g. text size, reduced motion, colorblind mode)
+- Device (e.g. mobile or desktop)
+- Region/language
+- Product/application area (e.g. marketing site vs dashboard UI)
+
+:::
+
+::: danger ❌ Don’t
+
+Don’t use modes for things that can be used on the same page:
+
+- Semantic color (e.g _success_ or _error_)
+- Localized state (e.g. _disabled_ or _active_)
+- Color shades/hues
+- Components (e.g. _card_ or _button_)
+
+:::
+
+## Advanced
+
+### Validation
+
+To enforce all modes exist for a group. You can assert typechecking with `$extensions.requiredModes`:
+
+::: code-group
+
+```json [JSON] {3-5}
+{
+ "color": {
+ "$extensions": {
+ "requiredModes": ["light", "lightHighContrast", "dark", "darkHighContrast"]
+ },
+ "red": {
+ "4": {
+ "$type": "color",
+ "$value": "#fa4549",
+ "$extensions": {
+ "mode": {
+ "light": "#fa4549",
+ "lightHighContrast": "#d5232c",
+ "dark": "#f85149"
+ }
+ }
+ }
+ }
+ }
+}
+```
+
+```yaml [YAML] {2-9}
+color:
+ $extensions:
+ requiredModes:
+ - light
+ - lightHighContrast
+ - dark
+ - darkHighContrast
+ red:
+ '4':
+ $type: color
+ $value: '#fa4549'
+ $extensions:
+ mode:
+ light: '#fa4549'
+ lightHighContrast: '#d5232c'
+ dark: '#f85149'
+```
+
+:::
+
+In the above example, we’d have an error on `color.red.4` because the `darkHighContrast` mode is missing. This helps ensure you’re not accidentally getting fallback values you intended to set.
+
+`requiredModes` can be enforced at any level. And it will require all children to have every mode present (regardless of `$type`).
diff --git a/docs/guides/tokens.md b/docs/guides/tokens.md
new file mode 100644
index 00000000..c5f676d9
--- /dev/null
+++ b/docs/guides/tokens.md
@@ -0,0 +1,155 @@
+---
+title: tokens.json
+---
+
+# tokens.json
+
+Your `tokens.json` (or `tokens.yaml`) file is a complete manifest of all your design tokens. It follows the [Design Token Format Module (DTFM)](https://www.w3.org/community/design-tokens/), an official standard for describing design tokens.
+
+The format is currently in draft, and being developed by hundreds of design leaders that work at Figma, Adobe, Salesforce, Google, Amazon, Microsoft, Zeplin, Supernova, and more! But despite it still being a draft, it’s still a robust format and is becoming the de-facto standard for design tokens, and many popular design systems [like GitHub Primer](https://primer.style/) either have switched to DTFM or are planning to in the near future.
+
+## DTFM Format
+
+The basic design token consists of a simple JSON object with `$type` and `$value` (required), as well as an optional `$description` (highly-recommended to use to describe the token’s purpose, as well as usage instructions).
+
+::: code-group
+
+```json [JSON]
+{
+ "tokenName": {
+ "$description": "(optional) A description of this token",
+ "$type": "[token type]",
+ "$value": "[token value - different shape depending on $type]",
+ "$extensions": "(optional) Used by third-party tools"
+ }
+}
+```
+
+```yaml [YAML]
+tokenName:
+ $description: (optional) A description of this token
+ $type: '[token type]'
+ $value: '[token value - different shape depending on $type]'
+ $extensions: (optional) Used by third-party tools
+```
+
+:::
+
+Tokens can also be nested infinitely within other groups. A group counts as any arbitrary object wrapping the token (note that `$` prefixes are reserved for tokens, to prevent name conflicts):
+
+::: code-group
+
+```json [JSON]
+{
+ "groupA": {
+ "groupB": {
+ "token": {
+ "$type": "color",
+ "$value": "#000"
+ }
+ }
+ }
+}
+```
+
+```yaml [YAML]
+groupA:
+ groupB:
+ token:
+ $type: color
+ $value: '#000'
+```
+
+:::
+
+### Managing `tokens.json`
+
+Currently, the only way to manage `tokens.json` is manually. But there are tools to make editing friendlier, such as [JSON Hero](https://jsonhero.io/).
+
+::: tip
+
+The Cobalt team is working on a visual GUI for editing/managing tokens, but it’s not ready yet. We’re planning on announcing it in early 2024.
+
+:::
+
+### Token Types
+
+Within your `tokens.json`, you can use all of the following types of tokens:
+
+- [Color](/tokens/color)
+- [Dimension](/tokens/dimension) (can be used for spacing, font size, border width, etc.)
+- [Font Family](/tokens/font-family)
+- [Font Weight](/tokens/font-weight)
+- [Duration](/tokens/duration)
+- [Cubic bézier](/tokens/cubic-bezier)
+- [Number](/tokens/number)
+- [Link](/tokens/link) (for files, extension provided by Cobalt)
+- [Stroke Style](/tokens/stroke-style)
+- [Border](/tokens/border)
+- [Transition](/tokens/transition)
+- [Shadow](/tokens/shadow)
+- [Gradient](/tokens/gradient)
+- [Typography](/tokens/typography)
+
+And in addition to these, you can also [group tokens](/tokens/groups) in any hierarchy you’d like, as well as create your own [custom tokens](/tokens/custom).
+
+### Cobalt extensions
+
+Cobalt **is NOT** its own format; it is an implementation of DTFM as close to the spec as possible. However, just for quality of life, Cobalt supports a superset to DTFM, allowing:
+
+- [Addition of a Link token for assets](/tokens/link)
+- YAML is supported in addition to JSON
+- Wider support for more values are expected, such as:
+ - Color: any CSS-valid color is accepted, including [Oklab/Oklch](https://oklch.com) (the spec requires sRGB Hexadecimal)
+ - Shadow: arrays of shadows are accepted (the spec only allows one shadow)
+ - Typography: any CSS text property is accepted (the spec doesn’t allow things like `font-variant`).
+- [Modes](/guides/mode) are allowed.
+
+Any other deviations are considered unintentional. Please [file an issue](https://github.com/drwpow/cobalt-ui/issues) if you run across any!
+
+## JSON or YAML?
+
+Though the original [DTFM spec](https://design-tokens.github.io/community-group/format/) (and most examples) use JSON, Cobalt supports YAML equally well since it’s a 1:1 translation. But since YAML is an easier format to read and write, you may prefer it (the Cobalt maintainers do!). Wherever you see mention of `tokens.json`, know that Cobalt supports `tokens.yaml` equally well; the former is just used as the common term for simplicity.
+
+_Tip: [Boop](https://boop.okat.best/) is a simple, secure tool to convert JSON to YAML in a snap._
+
+## Combining multiple `tokens.json` files
+
+With Cobalt, you can organize your tokens into separate files if you’d like, and they can all be flattened together. Pass in an array to `tokens` in your config:
+
+::: code-group
+
+```js [tokens.config.mjs]
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: ['./token-src/colors.json', './token-src/typography.json', './token-src/icons.json', './token-src/spacing.json'],
+};
+```
+
+:::
+
+Note that this will flatten all tokens into one manifest, so you’ll have to handle conflicts if multiple tokens are named the same thing (including their groups).
+
+## Naming / organization
+
+Organization is completely up to you! The DTFM spec allows infinite nesting, and lets you name tokens anything, with the following exceptions:
+
+- Token names or group names can’t …
+ - … contain dots (`.`). These are reserved for shorthand IDs (e.g. `color.base.blue.500`).
+ - … contain curly braces (`{}`). These are reserved for aliases (e.g. `{color.base.blue.500}`).
+ - … start with `$`. These are reserved properties (e.g. `$type`).
+- Tokens can’t contain sub-tokens (an object is either a token or a group, but never both).
+
+### Best practices
+
+Based on looking at dozens of design systems, here are a few tips and common patterns that we’ve seen:
+
+- **Favor predictability.** For naming colors, `color.red` is better than `color.crimson`. Expand into more “creative” only after you’ve exhausted the predictable names.
+- **Use aliasing.** You can create as many aliases as you’d like. For example, you could set `color.brand.primary`, `color.semantic.action`, and `color.semantic.info` all to `{color.base.blue.500}` and only have to manage one color instead of multiple.
+- **Group tokens by type.** Most DSs contain obvious top-level groups such as `color.*`, `border.*`, `font.*`, and `space.*`. As you develop more semantic groups, you can always alias back to these tokens.
+- **Dedupe types.** Groups let you set the default `$type` that apply to all children. So set `"$type": "color"` on your `color.*` group once to save typing on all child tokens (this also encourages good organization!).
+- **Set descriptions.** Tokens and groups all support adding `$description`s. Take the time to describe how this token should (or shouldn’t) be used!
+
+## Further Reading
+
+- [The official DTFM specification](https://design-tokens.github.io/community-group/format/)
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 00000000..0390909d
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,23 @@
+---
+# https://vitepress.dev/reference/default-theme-home-page
+layout: home
+
+hero:
+ name: Cobalt
+ text: CI for Design Tokens
+ tagline: Use Design Tokens Format Module tokens to generate CSS, Sass, JS/TS, universal JSON, and more.
+ actions:
+ - theme: brand
+ text: Get Started
+ link: /guides/getting-started
+ - theme: alt
+ text: View on GitHub
+ link: https://github.com/drwpow/cobalt-ui
+features:
+ - title: Supports Design Tokens Format Module
+ details: Use the universal design token standard for the widest compatibility and no vendor lock-in
+ - title: Pluggable & customizable
+ details: Written from the ground-up to power your own custom design tooling
+ - title: Community-powered
+ details: Open source, MIT-licensed, and open to community contributions
+---
diff --git a/docs/src/pages/docs/integrations/css.md b/docs/integrations/css.md
similarity index 71%
rename from docs/src/pages/docs/integrations/css.md
rename to docs/integrations/css.md
index d8a6c00b..d50184d3 100644
--- a/docs/src/pages/docs/integrations/css.md
+++ b/docs/integrations/css.md
@@ -1,40 +1,55 @@
---
-title: CSS Plugin for Cobalt
-layout: ../../../layouts/docs.astro
+title: CSS
---
-# @cobalt-ui/plugin-css
+# CSS
-Generate CSS from your design tokens using [Cobalt](https://cobalt-ui.pages.dev).
+Generate CSS variables from your Design Tokens Format Module (DTFM) tokens.
-**Features**
-
-- ✅ 🌈 Automatic [P3 color](https://developer.mozilla.org/en-US/docs/Web/CSS/@media/color-gamut) enhancement
-- ✅ Automatic mode inheritance (e.g. light/dark mode)
+This plugin generates CSS variables for dynamic, flexible theming that supports modes and gives you the full range of what CSS can do.
## Setup
-```bash
+::: tip
+
+Make sure you have the [Cobalt CLI](/guides/cli) installed!
+
+:::
+
+Install the plugin:
+
+```sh
npm i -D @cobalt-ui/plugin-css
```
-```js
-// tokens.config.mjs
-import pluginCSS from '@cobalt-ui/plugin-css';
+Then add to your `tokens.config.mjs` file:
+
+::: code-group
+
+```js [tokens.config.mjs]
+import pluginCSS from '@cobalt-ui/plugin-css'; // [!code ++]
/** @type import('@cobalt-ui/core').Config */
export default {
tokens: './tokens.json',
outDir: './tokens/',
- plugins: [pluginCSS()],
+ plugins: [pluginCSS()], // [!code ++]
};
```
-Generates:
+:::
-```css
-/* tokens/tokens.css */
+And run:
+```sh
+npx co build
+```
+
+You’ll then get a `./tokens/tokens.css` file with [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) for you to use anywhere in your app:
+
+::: code-group
+
+```css [./tokens/tokens.css]
:root {
--color-blue: #0969da;
--color-green: #2da44e;
@@ -44,20 +59,15 @@ Generates:
}
```
-You can then use these anywhere in your app.
-
-## Usage
-
-Running `npx co build` with the plugin set up will generate a `tokens/tokens.css` file. Inspect that, and import where desired and use the [CSS Custom Properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) as desired ([docs](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties)).
+:::
-## Options
-
-### All Options
+## Config
Here are all plugin options, along with their default values
-```js
-// tokens.config.mjs
+::: code-group
+
+```js [tokens.config.mjs]
import pluginCSS from '@cobalt-ui/plugin-css';
/** @type import('@cobalt-ui/core').Config */
@@ -89,11 +99,49 @@ export default {
};
```
-### Embed Files
+:::
+
+## Color tokens
+
+::: code-group
+
+```js [tokens.config.mjs] {5}
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ plugins: [
+ pluginCSS({
+ colorFormat: 'oklch',
+ }),
+ ],
+};
+```
+
+:::
+
+By specifying a `colorFormat`, you can transform all your colors to [any browser-supported colorspace](https://www.w3.org/TR/css-color-4/). Any of the following colorspaces are accepted:
+
+- [hex](https://developer.mozilla.org/en-US/docs/Web/CSS/hex-color) (default)
+- [rgb](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb)
+- [hsl](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl)
+- [hwb](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hwb)
+- [lab](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lab)
+- [lch](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lch)
+- [oklab](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklab)
+- [oklch](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch)
+- [p3](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color)
+- [srgb-linear](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
+- [xyz-d50](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
+- [xyz-d65](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
+
+If you are unfamiliar with these colorspaces, the default `hex` value is best for most users (though [you should use OKLCH to define your colors](https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl)).
+
+## Link tokens
-Say you have `link` tokens in your `tokens.json`:
+Say you have [Link tokens](/tokens/link) in your `tokens.json`:
-```json
+::: code-group
+
+```json [JSON]
{
"icon": {
"alert": {
@@ -104,40 +152,102 @@ Say you have `link` tokens in your `tokens.json`:
}
```
+```yaml [YAML]
+icon:
+ alert:
+ $type: link
+ value: ./icon/alert.svg
+```
+
+:::
+
By default, consuming those will print values as-is:
```css
-.icon-alert {
- background-image: var(--icon-alert);
+:root {
+ --icon-alert: url('./icon/alert.svg');
}
-/* Becomes … */
.icon-alert {
- background-image: url('./icon/alert.svg');
+ background-image: var(--icon-alert);
}
```
In some scenarios this is preferable, but in others, this may result in too many requests and may result in degraded performance. You can set `embedFiles: true` to generate the following instead:
```css
-.icon-alert {
- background-image: var(--icon-alert);
+:root {
+ --icon-alert: url('image/svg+xml;utf8,');
}
-/* Becomes … */
.icon-alert {
- background-image: url('image/svg+xml;utf8,');
+ background-image: var(--icon-alert);
}
```
-[Read more](https://css-tricks.com/data-uris/)
+::: tip
+
+The CSS plugin uses [SVGO](https://github.com/svg/svgo) to optimize SVGs at lossless quality. However, raster images won’t be optimized so quality isn’t degraded.
+
+:::
+
+[Read more about the advantages to inlining files](https://css-tricks.com/data-uris/)
+
+## Generate name
+
+Use the `generateName()` option to customize the naming of CSS tokens, such as adding prefixes/suffixes, or just changing how the default variable naming works in general.
+
+### Default naming
-### Mode Selectors
+By default, Cobalt takes your dot-separated token IDs and…
+
+- Removes leading and trailing whitespace from each group or token name in an ID
+- camelCases any group or token name that has a space in the middle of it
+- Joins the normalized segments together with a single dashes
+
+### Custom naming
+
+To override specific or all CSS variable names yourself, use the `generateName()` option:
+
+::: code-group
+
+```js [tokens.config.mjs]
+import pluginCSS from '@cobalt-ui/plugin-css';
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: './tokens.json',
+ outDir: './tokens/',
+ plugins: [
+ pluginCSS({
+ generateName(variableId, token) {
+ if (variableId === 'my.special.token') {
+ return 'SUPER_IMPORTANT_VARIABLE';
+ }
+ // if nothing returned, fall back to default behavior
+ },
+ }),
+ ],
+};
+```
+
+:::
+
+A couple things to be aware of:
+
+- `token` can be `undefined` in rare cases
+ - This occurs when a token references another token that is not defined. Currently, this is not explicitly disallowed by the design tokens specification.
+- `variableId` may not be a 1:1 match with the `token.id`
+ - For example, each property in a composite token will have its own variable generated, so those `variableId`s will include the property name. In most cases you should use `variableId` rather than `token.id`.
+- The string returned does not need to be prefixed with `--`, Cobalt will take care of that for you
+
+## Modes
To generate CSS for Modes, add a `modeSelectors` array to your config that specifies the **mode** you’d like to target and which **CSS selectors** should activate those modes (can either be one or multiple). You may optionally also decide to include or exclude certain tokens (e.g. `color.*` will only target the tokens that begin with `color.`).
-```js
-// tokens.config.mjs
+::: code-group
+
+```js [tokens.config.mjs]
import css from '@cobalt-ui/plugin-css';
/** @type import('@cobalt-ui/core').Config */
@@ -167,6 +277,8 @@ export default {
};
```
+:::
+
This would generate the following CSS:
```css
@@ -206,8 +318,9 @@ In our example the `@media` selectors would automatically pick up whether a user
Further, any valid CSS selector can be used (that’s why it’s called `modeSelectors` and not `modeClasses`)! You could also generate CSS if your `typography.size` group had `desktop` and `mobile` sizes:
-```js
-// tokens.config.mjs
+::: code-group
+
+```js [tokens.config.mjs]
import css from '@cobalt-ui/plugin-css';
/** @type import('@cobalt-ui/core').Config */
@@ -225,6 +338,8 @@ export default {
};
```
+:::
+
That will generate the following:
```css
@@ -245,38 +360,15 @@ That will generate the following:
}
```
-[Learn more about modes](https://cobalt-ui.pages.dev/docs/guides/modes/)
-
-### Color Format
+[Learn more about modes](/guides/modes)
-```js
-pluginCSS({
- colorFormat: 'oklch',
-}),
-```
-
-By specifying a `colorFormat`, you can transform all your colors to [any browser-supported colorspace](https://www.w3.org/TR/css-color-4/). Any of the following colorspaces are accepted:
-
-- [hex](https://developer.mozilla.org/en-US/docs/Web/CSS/hex-color) (default)
-- [rgb](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb)
-- [hsl](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl)
-- [hwb](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hwb)
-- [lab](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lab)
-- [lch](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lch)
-- [oklab](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklab)
-- [oklch](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch)
-- [p3](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color)
-- [srgb-linear](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
-- [xyz-d50](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
-- [xyz-d65](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
-
-If you are unfamiliar with these colorspaces, the default `hex` value is best for most users (though [you should use OKLCH to define your colors](https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl)).
-
-### Transform
+## Transform
Inside plugin options, you can specify an optional `transform()` function.
-```js
+::: code-group
+
+```js [tokens.config.mjs] {7-13}
/** @type import('@cobalt-ui/core').Config */
export default {
tokens: './tokens.json',
@@ -295,13 +387,17 @@ export default {
};
```
+:::
+
Your transform will only take place if you return a truthy value, otherwise the default transformer will take place.
-#### Custom tokens
+### Custom tokens
If you have your own custom token type, e.g. `my-custom-type`, you’ll have to handle it within `transform()`:
-```js
+::: code-group
+
+```js [tokens.config.mjs] {8-13}
/** @type import('@cobalt-ui/core').Config */
export default {
tokens: './tokens.json',
@@ -321,73 +417,34 @@ export default {
};
```
-### Generate Name
-
-Because token IDs are a dot-separated series of JSON keys, they cannot be trusted to be valid CSS variable names. By default, Cobalt generates CSS variable names using the `defaultNameGenerator` function which...
-
-- Removes leading and trailing whitespace from each group or token name in an ID
-- camelCases any group or token name that has a space in the middle of it
-- Joins the normalized segments together with a single dashes
-
-If you wish to customize this behavior, you can specify your own name generator with the plugin's `generateName` option. It accepts a function with the following signature.
+:::
-```ts
-type CustomNameGenerator = (variableId: string, token?: ParsedToken) => string;
-```
+## Sass interop
-A couple things to be aware of:
+If you’re using Sass in your project, you can load this plugin through [@cobalt-ui/plugin-sass](/integrations/sass), which gives you all the benefits of this plugin plus Sass’ typechecking (the Sass plugin’s normal Sass vars will be swapped for CSS vars, but it will still error on any mistyped tokens).
-- `token` can be undefined in rare cases
- - This occurs when a token references another token that is not defined. Currently, this is not explicitly disallowed by the design tokens specification.
-- `variableId` may not be a 1:1 match with the `token.id`
- - For example, each property in a composite token will have its own variable generated, so those `variableId`s will include the property name. In most cases you should use `variableId` rather than `token.id`.
-- The string returned does not need to be prefixed with `--`, Cobalt will take care of that for you
+To use this, replace this plugin with @cobalt-ui/plugin-sass in `tokens.config.mjs` and move your options into the `pluginCSS: {}` option:
-If you wish, you can use the `defaultNameGenerator` in your custom name generator. This is handy if you only want to modify the behavior of a special case.
+::: code-group
-```js
-// tokens.config.mjs
-import pluginCSS, { defaultNameGenerator } from '@cobalt-ui/plugin-css';
+
+```js [tokens.config.mjs]
+import pluginCSS from '@cobalt-ui/plugin-css'; // [!code --]
+import pluginSass from '@cobalt-ui/plugin-sass'; // [!code ++]
/** @type import('@cobalt-ui/core').Config */
export default {
tokens: './tokens.json',
outDir: './tokens/',
plugins: [
- pluginCSS({
- generateName: (variableId, token) {
- if (variableId === 'my.special.token') {
- return "SUPER_IMPORTANT_VARIABLE";
- }
-
- return defaultNameGenerator(variableId);
- },
- }),
+ pluginCSS({filename: 'tokens.css'}), // [!code --]
+ pluginSass({ // [!code ++]
+ pluginCSS: {filename: 'tokens.css'}, // [!code ++]
+ }), // [!code ++]
],
};
```
-### Usage with @cobalt-ui/plugin-sass
-
-If you’re using Sass in your project, you can load this plugin through [@cobalt-ui/plugin-sass](https://cobalt-ui.pages.dev/docs/integrations/sass/), which lets you use CSS vars while letting Sass typecheck everything and making sure your stylesheet references everything correctly.
-
-To use this, replace this plugin with @cobalt-ui/plugin-sass in `tokens.config.mjs` and pass all options into `pluginCSS: {}`:
-
-```diff
-- import pluginCSS from '@cobalt-ui/plugin-css';
-+ import pluginSass from '@cobalt-ui/plugin-sass';
-
- /** @type import('@cobalt-ui/core').Config */
- export default {
- tokens: './tokens.json',
- outDir: './tokens/',
- plugins: [
-- pluginCSS({ filename: 'tokens.css }),
-+ pluginSass({
-+ pluginCSS: { filename: 'tokens.css' },
-+ }),
- ],
- };
-```
+:::
-This changes `token('color.blue')` to return CSS vars rather than the original values. To learn more, [read the docs](https://cobalt-ui.pages.dev/docs/integrations/sass/).
+To learn more, [read the docs](/integrations/sass).
diff --git a/docs/integrations/figma.md b/docs/integrations/figma.md
new file mode 100644
index 00000000..76e10abf
--- /dev/null
+++ b/docs/integrations/figma.md
@@ -0,0 +1,54 @@
+---
+title: Figma
+---
+
+# Figma
+
+Because Figma doesn’t have a way to export the [Design Tokens Format Module (DTFM)](https://designtokens.org) directly, you’ll need a plugin to export your styles to the DTFM format.
+
+The plugin we recommend for now is [Tokens Studio for Figma](https://tokens.studio). Though it doesn’t support DTFM directly either, it does allow you to export your design tokens in a format Cobalt can read.
+
+::: info
+
+This only allows syncing _from_ Figma. Syncing _to_ Figma isn’t possible today, but the Cobalt team is actively building something to make this possible. Stay tuned! 📺
+
+:::
+
+## Exporting from Tokens Studio
+
+Once your design tokens are in Tokens Studio ([docs](https://docs.tokens.studio/tokens/creating-tokens)), use [any of the approved sync methods](https://docs.tokens.studio/sync/sync) to export a `tokens.json` file. Then use Cobalt as you would normally:
+
+```js
+import pluginCSS from '@cobalt-ui/plugin-css';
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: './tokens.json',
+ outDir: './tokens/',
+ plugins: [pluginCSS()],
+};
+```
+
+Once your sync method is set up, it should be a snap to re-export that `tokens.json` file every time something updates.
+
+## Support
+
+| Tokens Studio Type | Supported | Notes |
+| :-------------------------------------------------------------------------------- | :-------: | :----------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [Sizing](https://docs.tokens.studio/available-tokens/sizing-tokens) | ✅ | Converted to [Dimension](/tokens/dimension). |
+| [Spacing](https://docs.tokens.studio/available-tokens/spacing-tokens) | ✅ | Converted to [Dimension](/tokens/dimension). |
+| [Color](https://docs.tokens.studio/available-tokens/color-tokens) | ✅ | Flat colors are kept as [Color](/tokens/color) while gradients are converted to [Gradient](/tokens/gradient). Modifiers aren’t supported. |
+| [Border radius](https://docs.tokens.studio/available-tokens/border-radius-tokens) | ✅ | Converted to [Dimension](/tokens/dimension). Multiple values are expanded into 4 tokens (`*TopLeft`, `*TopRight`, `*BottomLeft`, `*BottomRight`). |
+| [Border width](https://docs.tokens.studio/available-tokens/border-width-tokens) | ✅ | Converted to [Dimension](/tokens/dimension). |
+| [Shadow](https://docs.tokens.studio/available-tokens/shadow-tokens) | ✅ | Basically equivalent to [Shadow](/tokens/shadow). |
+| [Opacity](https://docs.tokens.studio/available-tokens/opacity-tokens) | ✅ | Converted to [Number](/tokens/number) |
+| [Typography](https://docs.tokens.studio/available-tokens/typography-tokens) | ✅ | Basically equivalent to [Typography](/tokens/typography). **Text decoration** and **Text Case** must be flattened as there is no DTFM spec equivalent. |
+| [Asset](https://docs.tokens.studio/available-tokens/asset-tokens) | ❌ | TODO. Cobalt supports [Link](/tokens/link), which should be an equivalent. |
+| [Composition](https://docs.tokens.studio/available-tokens/composition-tokens) | ❌ | Unsupported because this is a paid feature. |
+| [Dimension](https://docs.tokens.studio/available-tokens/dimension-tokens) | ✅ | Direct equivalent to [Dimension](/tokens/dimension). |
+| [Border](https://docs.tokens.studio/available-tokens/border-tokens) | ✅ | Direct equivalent to [Border](/tokens/border). |
+
+#### Notes
+
+- **Duration** and **Cubic Bézier** types aren’t supported by Tokens Studio (because Figma currently doesn’t support animations). So to use those types you’ll need to convert your tokens into DTFM.
+- Though Cobalt preserves your [Token Sets](https://docs.tokens.studio/themes/token-sets), which means most aliases will work, Token Studio’s [Advanced Themes](https://docs.tokens.studio/themes/themes-pro) is a paid feature and is therefore not supported. Though you could manually upconvert Token Studio themes to [modes](/tokens/modes).
diff --git a/docs/src/pages/docs/integrations/js.md b/docs/integrations/js.md
similarity index 56%
rename from docs/src/pages/docs/integrations/js.md
rename to docs/integrations/js.md
index bcedb33e..3ee14449 100644
--- a/docs/src/pages/docs/integrations/js.md
+++ b/docs/integrations/js.md
@@ -1,52 +1,57 @@
---
-title: JS/TS/JSON Plugin for Cobalt
-layout: ../../../layouts/docs.astro
+title: JS / TS
---
-# @cobalt-ui/plugin-js
+# JavaScript + TypeScript
-Generate JSON and JS (with TypeScript types) from your design tokens using [Cobalt](https://cobalt-ui.pages.dev).
+Generate JavaScript (with TypeScript declarations) from your Design Tokens Format Module (DTFM) tokens.
-**Features**
+## Setup
-- ✅ Access all your design tokens safely and programatically in any frontend or backend setup
-- ✅ Full support for token modes (e.g. light/dark mode)
-- ✅ Automatic TypeScript types for strong typechecking (never have a broken style)
+::: tip
-## Setup
+Make sure you have the [Cobalt CLI](/guides/cli) installed!
+
+:::
+
+Install the plugin from npm:
```bash
npm i -D @cobalt-ui/plugin-js
```
-```js
-// tokens.config.mjs
-import pluginJS from '@cobalt-ui/plugin-js';
+Then add to your `tokens.config.mjs` file:
+
+::: code-group
+
+
+```js [tokens.config.mjs]
+import pluginJS from '@cobalt-ui/plugin-js'; // [!code ++]
/** @type import('@cobalt-ui/core').Config */
export default {
tokens: './tokens.json',
outDir: './tokens/',
plugins: [
- pluginJS({
- /** output JS (with TS types)? boolean or filename (default: true) */
- js: true,
- /** output JSON? boolean or filename (default: false) */
- json: false,
- }),
+ pluginJS({ // [!code ++]
+ /** output JS (with TS types)? boolean or filename (default: true) */ // [!code ++]
+ js: true, // [!code ++]
+ }), // [!code ++]
],
};
```
-_Note: the default plugin exports a `.d.ts` file alongside the `.js`, which means the same file can either be used in JS or TS._
+:::
-## Usage
+And run:
-### JS
+```sh
+npx co build
+```
-To use a token, import the `token()` function and reference it by its full ID:
+You’ll then get generated JS with a `token()` function you can use to grab token values:
-```ts
+```js
import {token} from './tokens/index.js';
// get default token
@@ -60,9 +65,15 @@ import BezierEasing from 'bezier-easing';
const easing = BezierEasing(...token('ease.cubic-in-out'));
```
-You’ll also be able to see any `$description`s specified in your IDE in the form of JSDoc. If using TypeScript, `token()` is statically typed as it‘s only a thin wrapper around the `tokens` and `modes` exports.
+::: info
+
+The default plugin exports a plain `.js` with invisible `.d.ts` TypeScript declarations alongside it, which means you don’t have to configure anything whether using TypeScript or not.
+
+:::
-In addition, you’ll also find the following named exports:
+## API
+
+In addition to `token()`, you’ll also find the following named exports:
| Name | Type | Description |
| :------- | :------- | :-------------------------------------------------------------------------------------------------- |
@@ -70,24 +81,13 @@ In addition, you’ll also find the following named exports:
| `meta` | `object` | Object of token ID → metadata (`$type`, `$description`, etc.) |
| `modes` | `object` | Object of token ID → mode → values (note: tokens without any modes will be missing from the object) |
-### JSON
-
-This plugin’s JSON output has the same shape as the JS output. This format is preferable if you’re preparing tokens for an API, or for native apps (iOS or Android).
-
-Note that even if your tokens started off as a `tokens.json` file, this output JSON differs in the following ways:
-
-- It flattens deeply-nested structures into a single depth (e.g. `color.core.blue.500` becomes `tokens["color.core.blue.500"]`)
-- It resolves all aliases (so you don’t have to)
-- It normalizes token values (especially helpful when the original spec is loose in what’s accepted)
-
-## Options
-
-### All Options
+## Config
Here are all plugin options, along with their default values:
-```js
-// tokens.config.mjs
+::: code-group
+
+```js [tokens.config.mjs]
import pluginJS from '@cobalt-ui/plugin-js';
/** @type import('@cobalt-ui/core').Config */
@@ -107,7 +107,9 @@ export default {
};
```
-### Transform
+:::
+
+## Transform
Inside plugin options, you can specify an optional `transform()` function.
diff --git a/docs/integrations/json.md b/docs/integrations/json.md
new file mode 100644
index 00000000..3c3fc02b
--- /dev/null
+++ b/docs/integrations/json.md
@@ -0,0 +1,72 @@
+---
+title: JSON
+---
+
+# JSON + Native Apps
+
+Generate universal JSON from your Design Tokens Format Module (DTFM) tokens. This is usable by any platform, any language (provided you do a small amount of JSON parsing).
+
+## Setup
+
+::: tip
+
+Make sure you have the [Cobalt CLI](/guides/cli) installed!
+
+:::
+
+This uses the [JS plugin](/integrations/js), which we’ll install from npm:
+
+```bash
+npm i -D @cobalt-ui/plugin-js
+```
+
+Then add to your `tokens.config.mjs` file:
+
+::: code-group
+
+
+```js [tokens.config.mjs]
+import pluginJS from '@cobalt-ui/plugin-js'; // [!code ++]
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: './tokens.json',
+ outDir: './tokens/',
+ plugins: [
+ pluginJS({ // [!code ++]
+ /** output JSON? boolean or filename (default: false) */ // [!code ++]
+ json: true, // [!code ++]
+ }), // [!code ++]
+ ],
+};
+```
+
+:::
+
+And run:
+
+```sh
+npx co build
+```
+
+You’ll get a generated `./tokens/tokens.json` file with the following structure:
+
+| Name | Type | Description |
+| :------- | :------- | :-------------------------------------------------------------------------------------------------- |
+| `tokens` | `object` | Object of token ID → value (all aliases resolved & all transformations applied) |
+| `meta` | `object` | Object of token ID → metadata (`$type`, `$description`, etc.) |
+| `modes` | `object` | Object of token ID → mode → values (note: tokens without any modes will be missing from the object) |
+
+## Usage
+
+Usage will vary depending on the platform and language, but here are a few examples:
+
+- [Simplifying iOS Apps Design with Design Tokens](https://blogs.halodoc.io/simplifying-ios-app-design-with-design-tokens/) (this blog post uses Style Dictonary JSON, but the same ideas apply to DTFM JSON)
+
+## Config
+
+The config options [are the same as the JS plugin](/integrations/js#config).
+
+## Transform
+
+Likewise, the transform API is [also the same as the JS plugin](/integrations/js#transform).
diff --git a/docs/integrations/other.md b/docs/integrations/other.md
new file mode 100644
index 00000000..b90c5ca5
--- /dev/null
+++ b/docs/integrations/other.md
@@ -0,0 +1,24 @@
+---
+title: Other
+---
+
+# Other Integrations
+
+The following integrations are planned, but aren’t ready yet:
+
+- Elixir
+- PHP
+- Python
+- Ruby
+
+## Consuming JSON
+
+If your integration isn’t supported (or isn’t planned), you can use the [JSON plugin](/integrations/json) to pull the tokens into your project. JSON is a universal language, and can be easily parsed in just about every language.
+
+Even though [`tokens.json` manifests](/guides/tokens) are written in JSON, Cobalt’s JSON plugin performs extra layers of work to make tokens even easier to consume:
+
+- Syntax errors are caught
+- All aliases are resolved
+- Token values are normalized wherever possible (e.g. colors converted to hex)
+
+[Read JSON plugin docs](/integrations/json)
diff --git a/docs/src/pages/docs/integrations/sass.md b/docs/integrations/sass.md
similarity index 58%
rename from docs/src/pages/docs/integrations/sass.md
rename to docs/integrations/sass.md
index 1fad8be5..2cffdda9 100644
--- a/docs/src/pages/docs/integrations/sass.md
+++ b/docs/integrations/sass.md
@@ -1,56 +1,70 @@
---
-title: Sass Plugin for Cobalt
-layout: ../../../layouts/docs.astro
+title: Sass
---
-# @cobalt-ui/plugin-sass
+# Sass
-Generate `.scss` and `.sass` output from your design tokens using [Cobalt](https://cobalt-ui.pages.dev).
+Generate `.scss` and `.sass` from your Design Tokens Format Module (DTFM) tokens.
-**Features**
+## Setup
-- ✅ Supports all features of the [CSS plugin](https://cobalt-ui.pages.dev/integrations/css)
-- ✅ Strong typechecking with Sass to never have broken styles
+::: tip
-## Setup
+Make sure you have the [Cobalt CLI](/guides/cli) installed!
+
+:::
+
+Install the plugin (and its dependency) from npm:
-```bash
+```sh
npm i -D @cobalt-ui/plugin-sass @cobalt-ui/plugin-css
```
-```js
-// tokens.config.mjs
-import pluginSass from '@cobalt-ui/plugin-sass';
+Then add to your `tokens.config.mjs` file:
+
+::: code-group
+
+```js [tokens.config.mjs]
+import pluginSass from '@cobalt-ui/plugin-sass'; // [!code ++]
/** @type import('@cobalt-ui/core').Config */
export default {
tokens: './tokens.json',
outDir: './tokens/',
- plugins: [
- pluginSass({
- /** set the filename inside outDir */
- filename: './index.scss',
- /** output CSS vars generated by @cobalt-ui/plugin-css? */
- pluginCSS: undefined,
- /** use indented syntax? (.sass format) */
- indentedSyntax: false,
- /** embed file tokens? */
- embedFiles: false,
- /** handle specific token types */
- transform(token, mode) {
- // Replace "sans-serif" with "Brand Sans" for font tokens
- if (token.$type === 'fontFamily') {
- return token.$value.replace('sans-serif', 'Brand Sans');
- }
- },
- }),
- ],
+ plugins: [pluginSass()], // [!code ++]
};
```
+:::
+
+And run:
+
+```sh
+npx co build
+```
+
+You’ll then generate a `./tokens/index.scss` file that exports a `token()` function you can use to grab tokens:
+
+```scss
+@use '../tokens' as *; // update '../tokens' to match your location of tokens/index.scss
+
+.heading {
+ color: token('color.blue');
+ font-size: token('typography.size.xxl');
+}
+```
+
## Usage
-Use the provided `token()` function to get a token by its ID (separated by dots):
+The generated Sass outputs the following helpers:
+
+- [`token()`](#token)
+- [`typography()`](#typography)
+- [`listModes()`](#list-modes)
+
+### `token()`
+
+The main way you’ll use the token is by importing the `token()` function to grab a token by its ID (separated by dots):
```scss
@use '../tokens' as *; // update '../tokens' to match your location of tokens/index.scss
@@ -71,47 +85,53 @@ Note that a function has a few advantages over plain Sass variables:
- ✅ You can programmatically pull values (which is more difficult to do with Sass vars)
- ✅ Use the same function to access [modes](#modes)
-### CSS Variable Mode (recommended)
+### typography()
-By default, the Sass plugin only loads your raw token values to Sass. This is a good basic usage, but leaves all the automatic mode inheritance and advanced features of the CSS plugin on the table. To get all the features of the CSS plugin, you can load it through the Sass plugin. In other words:
+[Sass mixin](https://sass-lang.com/documentation/at-rules/mixin/) to inject all styles from a [typography](https://cobalt-ui.pages.dev/docs/tokens/#typography) token. Optionally provide the **mode** as the 2nd param.
-```sass
-color: token('color.blue');
+```scss
+@include typography($tokenID, [$mode]);
```
-Becomes:
+```scss
+@use '../tokens' as *;
+
+h2 {
+ @include typography('typography.heading-2');
-```diff
-- color: #506fff;
-+ color: var(--color-blue);
+ font-size: token('typography.size.xxl'); // overrides can still be applied after the mixin!
+}
```
-_“Why would I want to do this?”_ you may ask. _“Why not just type CSS variables directly?”_
+Note that you can override any individual property so long as it comes _after_ the mixin.
-The answer is that **CSS variables have no typechecking.** If, say, your tokens were renamed, or you made a typo, you would never know! You would just have broken styles. However, **using the Sass plugin in CSS variable mode** gives you all the advantages of CSS variables but with the typechecking of Sass so that you’ll never have a single broken style.
+### listModes()
-**Pros**
+The `listModes()` function lists all modes a token has defined. This returns a [Sass list](https://sass-lang.com/documentation/values/lists/). This can be used to generate styles for specific modes:
+
+```scss
+@use '../tokens' as *;
-- Get automatic mode inheritance from CSS variables (such as light/dark mode)
-- Get dynamic style inheritance from your app
-- Get P3 Color enhancement (provided by `@cobalt-ui/plugin-css`)
+@for $mode in listModes('color.blue') {
+ [data-color-mode='#{$mode}'] {
+ color: token('color.blue', $mode);
+ }
+}
+```
-**Cons**
+## CSS Variable Mode
-- None, really! You may have to just change how you write CSS.
+By default, this plugin converts tokens to pure Sass variables. But if you’d like to take advantage of dynamic CSS variables (which support dynamic [modes](/integrations/css#modes)), you can use in conjunction with the [CSS plugin](/integrations/css). This gives you all the flexibility and benefits of modern CSS while still keeping the typechecking properties of Sass.
-#### Setup
+To use CSS variables instead of Sass variables, set `cssVars: true` and set the `pluginCSS` option:
-In your `tokens.config.mjs` file, opt in by adding a `pluginCSS` option. That will automatically load @cobalt-ui/plugin-css and will pass all options to it (all options are supported):
+::: code-group
-```js
-// tokens.config.mjs
+```js [tokens.config.mjs] {7-14}
import pluginSass from '@cobalt-ui/plugin-sass';
/** @type import('@cobalt-ui/core').Config */
export default {
- tokens: './tokens.json',
- outDir: './tokens/',
plugins: [
pluginSass({
cssVars: true,
@@ -123,54 +143,130 @@ export default {
],
},
}),
- ],
-};
```
-
+:::
-⚠️ Don’t load another instance of @cobalt-ui/plugin-css, otherwise they may conflict!
+From here you can set [any option the CSS plugin allows](/integrations/css).
-
+::: tip
-Lastly, you’ll need to make sure the new `tokens.css` file is loaded in your app somehow (otherwise the variables won’t be defined):
+Don’t forget to import the `./tokens/tokens.css` file into your app as well so those variables are defined!
-```diff
- // src/app.ts
-+ import '../tokens/tokens.css';
-```
+:::
+
+::: warning
+
+Don’t load another instance of @cobalt-ui/plugin-css, otherwise they may conflict!
-#### Usage
+:::
-Here’s one example of how you may need to adjust your code with CSS vars. For example, **opacity** can be achieved with the [color-mix()](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix) function:
+### Tips
-```diff
-- color: rgba(token('color.ui.foreground'), 0.75); // ❌ rgba(var(--color-ui-foreground), 0.75)
-+ color: color-mix(in oklab, #{token('color.ui.foreground')}, 25% transparent); // ✅ var(--color-ui-foreground) at 75% opacity
+Though CSS variable mode is recommended, there may be some caveats to be aware of. One example is that you’ll lose the ability for Sass to change opacity, however, you can achieve the same results with the [color-mix()](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix) function:
+
+```scss
+.text {
+ color: rgba(token('color.ui.foreground'), 0.75); // [!code --]
+ color: color-mix(in oklab, #{token('color.ui.foreground')}, 25% transparent); // [!code ++]
+}
```
-Or perhaps you want to do some calculations off your tokens. CSS’ `calc()` can do that the same:
+You’ll also lose Sass’ ability to perform math on the values, however, CSS’ built-in `calc()` can do the same:
-```diff
-- margin-left: -0.5 * token('space.sm'); // ❌ Error: Undefined operation "-0.5 * var(--space-sm)"
-+ margin-left: calc(-0.5 * #{token('space.ms')}); // ✅ calc(-0.5 * var(--color-ui-foreground));
+```scss
+.nav {
+ margin-left: -0.5 * token('space.sm'); // [!code --]
+ margin-left: calc(-0.5 * #{token('space.ms')}); // [!code ++]
+}
```
In either case, letting the browser do the work is better, especially considering CSS variables are dynamic and can be modified on-the-fly.
-
+::: tip
-✨ **Tip**: Always use `in oklab` as the default colorspace for `color-mix()`. It usually outperforms other blending methods ([comparison](https://better-color-tools.pages.dev/mix)).
+Always use `in oklab` as the default colorspace for `color-mix()`. It usually outperforms other blending methods ([comparison](https://better-color-tools.pages.dev/mix)).
-
+:::
## Config
-### Embed Files
+Here are all plugin options, along with their default values:
+
+:::code-group
-Say you have `link` tokens in your `tokens.json`:
+```js [tokens.config.mjs]
+import pluginSass from '@cobalt-ui/plugin-sass';
-```json
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: './tokens.json',
+ outDir: './tokens/',
+ plugins: [
+ pluginSass({
+ /** set the filename inside outDir */
+ filename: './index.scss',
+ /** output CSS vars generated by @cobalt-ui/plugin-css? */
+ pluginCSS: undefined,
+ /** use indented syntax? (.sass format) */
+ indentedSyntax: false,
+ /** embed file tokens? */
+ embedFiles: false,
+ /** handle specific token types */
+ transform(token, mode) {
+ // Replace "sans-serif" with "Brand Sans" for font tokens
+ if (token.$type === 'fontFamily') {
+ return token.$value.replace('sans-serif', 'Brand Sans');
+ }
+ },
+ }),
+ ],
+};
+```
+
+:::
+
+## Color tokens
+
+::: code-group
+
+```js [tokens.config.mjs] {5}
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ plugins: [
+ pluginSass({
+ colorFormat: 'oklch',
+ }),
+ ],
+};
+```
+
+:::
+
+By specifying a `colorFormat`, you can transform all your colors to [any browser-supported colorspace](https://www.w3.org/TR/css-color-4/). Any of the following colorspaces are accepted:
+
+- [hex](https://developer.mozilla.org/en-US/docs/Web/CSS/hex-color) (default)
+- [rgb](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb)
+- [hsl](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl)
+- [hwb](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hwb)
+- [lab](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lab)
+- [lch](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lch)
+- [oklab](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklab)
+- [oklch](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch)
+- [p3](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color)
+- [srgb-linear](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
+- [xyz-d50](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
+- [xyz-d65](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
+
+If you are unfamiliar with these colorspaces, the default `hex` value is best for most users (though [you should use OKLCH to define your colors](https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl)).
+
+## Link tokens
+
+Say you have [link tokens](/tokens/link) in your `tokens.json`:
+
+::: code-group
+
+```json [JSON]
{
"icon": {
"alert": {
@@ -181,16 +277,20 @@ Say you have `link` tokens in your `tokens.json`:
}
```
+```yaml [YAML]
+icon:
+ alert:
+ $type: link
+ value: ./icon/alert.svg
+```
+
+:::
+
By default, consuming those will print values as-is:
```scss
.icon-alert {
- background-image: token('icon.alert');
-}
-
-// Becomes …
-.icon-alert {
- background-image: url('./icon/alert.svg');
+ background-image: token('icon.alert'); // url('./icon/alert.svg')
}
```
@@ -198,47 +298,25 @@ In some scenarios this is preferable, but in others, this may result in too many
```scss
.icon-alert {
- background-image: token('icon.alert');
-}
-
-// Becomes …
-.icon-alert {
- background-image: url('image/svg+xml;utf8,');
+ background-image: token('icon.alert'); // url('image/svg+xml;utf8,');
}
```
-[Read more](https://css-tricks.com/data-uris/)
+::: tip
-### Color Format
+The Sass plugin uses [SVGO](https://github.com/svg/svgo) to optimize SVGs at lossless quality. However, raster images won’t be optimized so quality isn’t degraded.
-```js
-pluginSass({
- colorFormat: 'oklch',
-}),
-```
+:::
-By specifying a `colorFormat`, you can transform all your colors to [any browser-supported colorspace](https://www.w3.org/TR/css-color-4/). Any of the following colorspaces are accepted:
+[Read more about the advantages to inlining files](https://css-tricks.com/data-uris/)
-- [hex](https://developer.mozilla.org/en-US/docs/Web/CSS/hex-color) (default)
-- [rgb](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/rgb)
-- [hsl](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl)
-- [hwb](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hwb)
-- [lab](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lab)
-- [lch](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/lch)
-- [oklab](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklab)
-- [oklch](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/oklch)
-- [p3](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color)
-- [srgb-linear](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
-- [xyz-d50](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
-- [xyz-d65](https://developer.mozilla.org/en-US/docs/Web/CSS/color-interpolation-method)
-
-If you are unfamiliar with these colorspaces, the default `hex` value is best for most users (though [you should use OKLCH to define your colors](https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl)).
-
-### Transform
+## Transform
Inside plugin options, you can specify an optional `transform()` function:
-```js
+::: code-group
+
+```js [tokens.config.mjs] {7-13}
/** @type import('@cobalt-ui/core').Config */
export default {
tokens: './tokens.json',
@@ -257,13 +335,17 @@ export default {
};
```
+:::
+
Your transform will only take place if you return a truthy value, otherwise the default transformer will take place.
-#### Custom tokens
+### Custom tokens
If you have your own custom token type, e.g. `my-custom-type`, you’ll have to handle it within `transform()`:
-```js
+::: code-group
+
+```js [tokens.config.mjs] {8-13}
/** @type import('@cobalt-ui/core').Config */
export default {
tokens: './tokens.json',
@@ -282,49 +364,3 @@ export default {
],
};
```
-
-## API
-
-All available methods in the Sass plugin.
-
-### listModes()
-
-List all modes a token has defined. This returns a [Sass list](https://sass-lang.com/documentation/values/lists/). This can be used to generate styles for specific modes:
-
-```scss
-@use '../tokens' as *;
-
-@for $mode in listModes('color.blue') {
- [data-color-mode='#{$mode}'] {
- color: token('color.blue', $mode);
- }
-}
-```
-
-### token()
-
-Retrieve a token by its ID. Optionally provide the **mode** as the 2nd param.
-
-```scss
-token($tokenID, [$mode]);
-```
-
-### typography()
-
-[Sass mixin](https://sass-lang.com/documentation/at-rules/mixin/) to inject all styles from a [typography](https://cobalt-ui.pages.dev/docs/tokens/#typography) token. Optionally provide the **mode** as the 2nd param.
-
-```scss
-@include typography($tokenID, [$mode]);
-```
-
-```scss
-@use '../tokens' as *;
-
-h2 {
- @include typography('typography.heading-2');
-
- font-size: token('typography.size.xxl'); // overrides can still be applied after the mixin!
-}
-```
-
-Note that you can override any individual property so long as it comes _after_ the mixin.
diff --git a/docs/integrations/style-dictionary.md b/docs/integrations/style-dictionary.md
new file mode 100644
index 00000000..7e8c83de
--- /dev/null
+++ b/docs/integrations/style-dictionary.md
@@ -0,0 +1,31 @@
+---
+title: Style Dictionary
+---
+
+# Style Dictionary
+
+You can migrate your [Style Dictionary](https://amzn.github.io/style-dictionary) tokens to the Design Tokens Format Module (DTFM) standard by running the following command (granted you have [the CLI installed](/docs/reference/cli)):
+
+```bash
+npx co convert style-dictionary-tokens.json --out tokens.json
+```
+
+After running `npx co convert` it’s not recommended to keep using the Style Dictionary format.
+
+::: warning
+This is **NOT** a perfect conversion. This is only meant to do most of the work of migrating to DTFM, but you’ll still have to do some clean up and migrate the parts that weren’t able to be converted.
+:::
+
+## Why convert to DTFM?
+
+::: tip
+
+Only you can decide what’s best, and don’t fix your design tooling if it isn’t broken! Only switch to DTFM if it makes sense for your project.
+
+:::
+
+There are reasons to switch from Style Dictionary to DTFM. While Style Dictionary is a powerful and flexible tool, it also requires more configuration and maintenance than DTFM does. For example, Style Dictionary requires you place all your colors underneath a top-level `color` group. If you want to reference colors elsewhere, you’ll have to configure all your transformers to look for them. The same applies for `size` and `time` tokens.
+
+Further, Style Dictionary is missing more advanced features like `gradient`, `typography`, and `shadow` tokens from the DTFM spec, to name a few (and adding them results in nonstandard usage that would be improved by opting for a standard that supports them out-of-the-box).
+
+While Style Dictionary was a significant trailblazer in managing design tokens and was the first mature library to accomplish this elegantly, the new DTFM spec is being designed to replace the Style Dictionary format by improving on its flaws. In fact, DTFM is more influenced by Style Dictionary than any other format, so rest assured that while migrating can be hard work, the goal of DTFM is to support all of Style Dictionary’s functionality and then some.
diff --git a/docs/integrations/tailwind.md b/docs/integrations/tailwind.md
new file mode 100644
index 00000000..8f989d67
--- /dev/null
+++ b/docs/integrations/tailwind.md
@@ -0,0 +1,159 @@
+---
+title: Tailwind CSS
+---
+
+# Tailwind CSS
+
+Generate a [Tailwind CSS](https://tailwindcss.com/) preset from your design tokens.
+
+## Setup
+
+::: tip
+Make sure you have the [Cobalt CLI](/guides/cli) installed!
+:::
+
+Install the plugin from npm
+
+```sh
+npm i -D @cobalt-ui/plugin-tailwind
+```
+
+Then add to your `tokens.config.mjs` file, configuring [theme](https://tailwindcss.com/docs/configuration#theme) as you would normally, except replacing the values with token IDs:
+
+::: code-group
+
+```js [tokens.config.mjs]
+import pluginTailwind from '@cobalt-ui/plugin-tailwind';
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ plugins: [
+ pluginTailwind({
+ /** (optional) the path to the Tailwind preset */
+ output?: './tailwind-tokens.js',
+ /** (optional) module format to use (to match your Tailwind config) */
+ outputFormat?: 'esm' | 'cjs',
+ tailwind: {
+ theme: {
+ /** @see https://tailwindcss.com/docs/configuration#theme */
+ colors: {
+ blue: {
+ 100: 'color.blue.100',
+ 200: 'color.blue.200',
+ // …
+ },
+ },
+ fontFamily: {
+ sans: 'typography.family.base',
+ // …
+ },
+ extend: {
+ spacing: {
+ 1: 'token.size.s.space',
+ 2: 'token.size.m.space',
+ // …
+ },
+ borderRadius: {
+ m: 'token.size.m.borderRadius',
+ // …
+ },
+ },
+ },
+ },
+ }),
+ ],
+};
+```
+
+:::
+
+Then run:
+
+```sh
+npx co build
+```
+
+And you’ll generate a `./tokens/tailwind-tokens.js` file. Add it to your Tailwind config [`presets`](https://tailwindcss.com/docs/configuration#presets) and your Tailwind theme now pulls directly from your design tokens:
+
+::: code-group
+
+
+```js [tailwind.config.js]
+import tailwindTokens from './tokens/tailwind-tokens.js'; // [!code ++]
+
+/** @type {import('tailwindcss').Config} */
+export default {
+ presets: [ // [!code ++]
+ tailwindTokens, // [!code ++]
+ ], // [!code ++]
+};
+```
+
+:::
+
+::: tip
+Be sure to rerun `co build` to rebuild your Tailwind preset, or run `co build --watch` to rebuild your tokens every time they change!
+
+:::
+
+## Automated mapping
+
+Because the Tailwind config is “just JS,” you can automate the mapping by using JS:
+
+::: code-group
+
+```js [tokens.config.mjs]
+import pluginTailwind from '@cobalt-ui/plugin-tailwind';
+
+function makeColor(colorName) {
+ const output = {};
+ for (const step of [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950]) {
+ output[step] = [colorName, step].join('.'); // e.g. `color.blue.50`
+ }
+ return output;
+}
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ tokens: './tokens.json',
+ outDir: './tokens/',
+ plugins: [
+ pluginTailwind({
+ tailwind: {
+ theme: {
+ colors: {
+ blue: makeColor('color.blue'), // { 50: 'color.blue.50', 100: 'color.blue.100', … }
+ green: makeColor('color.green'), // { 50: 'color.green.50', 100: 'color.green.100', … }
+ // …
+ },
+ },
+ },
+ }),
+ ],
+};
+```
+
+:::
+
+Use this to avoid having to repeat yourself when mapping between dozens (if not hundreds) of your tokens.
+
+## CommonJS
+
+If you’re still using CommonJS (using `require("…")` rather than `import "…"`), make sure to change the `outputFormat` setting to `cjs`:
+
+::: code-group
+
+```js [tokens.config.mjs] {7}
+import pluginTailwind from '@cobalt-ui/plugin-tailwind';
+
+/** @type import('@cobalt-ui/core').Config */
+export default {
+ plugins: [
+ pluginTailwind({
+ outputFormat: 'cjs',
+ }),
+ ],
+};
+```
+
+:::
diff --git a/docs/package.json b/docs/package.json
index 150bd240..290765cd 100644
--- a/docs/package.json
+++ b/docs/package.json
@@ -1,31 +1,18 @@
{
- "name": "cobalt-docs",
- "version": "0.0.0",
+ "name": "@cobalt-ui/docs",
"private": true,
+ "version": "0.0.0",
"type": "module",
"scripts": {
- "build": "npm run build:tokens && npm run build:readme && npm run build:static",
- "build:tokens": "co build",
- "build:readme": "node ./scripts/update-readmes.js",
- "build:static": "astro build",
- "sync": "co sync",
- "dev": "run-p dev:*",
- "dev:tokens": "co build -w",
- "dev:serve": "astro dev"
+ "dev": "vitepress dev",
+ "build": "vitepress build",
+ "preview": "vitepress preview"
},
"dependencies": {
- "js-yaml": "^4.1.0",
- "nanoid": "^4.0.2"
+ "vue": "^3.3.7"
},
"devDependencies": {
- "@cobalt-ui/cli": "workspace:*",
- "@cobalt-ui/core": "workspace:*",
- "@cobalt-ui/plugin-css": "workspace:*",
- "@cobalt-ui/plugin-sass": "workspace:*",
- "astro": "^3.3.2",
- "npm-run-all": "^4.1.5",
- "sass": "^1.69.4",
- "shiki": "^0.14.5",
- "vite": "^4.5.0"
+ "vite": "^4.5.0",
+ "vitepress": "1.0.0-rc.24"
}
}
diff --git a/docs/public/arrow-r.svg b/docs/public/arrow-r.svg
deleted file mode 100644
index 7b8a0971..00000000
--- a/docs/public/arrow-r.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/docs/public/github.svg b/docs/public/github.svg
deleted file mode 100644
index 52c363b1..00000000
--- a/docs/public/github.svg
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/docs/public/icons/cloud--download.svg b/docs/public/icons/cloud--download.svg
deleted file mode 100644
index f7700926..00000000
--- a/docs/public/icons/cloud--download.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/docs/public/icons/cloud--upload.svg b/docs/public/icons/cloud--upload.svg
deleted file mode 100644
index 5b08fbe2..00000000
--- a/docs/public/icons/cloud--upload.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/docs/public/icons/crop.svg b/docs/public/icons/crop.svg
deleted file mode 100644
index 12dab3fd..00000000
--- a/docs/public/icons/crop.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/delete.svg b/docs/public/icons/delete.svg
deleted file mode 100644
index a8d1441d..00000000
--- a/docs/public/icons/delete.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/do-not--02.svg b/docs/public/icons/do-not--02.svg
deleted file mode 100644
index 7439dc00..00000000
--- a/docs/public/icons/do-not--02.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/do-not.svg b/docs/public/icons/do-not.svg
deleted file mode 100644
index a60a39ba..00000000
--- a/docs/public/icons/do-not.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/download--01.svg b/docs/public/icons/download--01.svg
deleted file mode 100644
index 727798df..00000000
--- a/docs/public/icons/download--01.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/docs/public/icons/download--02.svg b/docs/public/icons/download--02.svg
deleted file mode 100644
index c09632d9..00000000
--- a/docs/public/icons/download--02.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/docs/public/icons/embed.svg b/docs/public/icons/embed.svg
deleted file mode 100644
index b3688515..00000000
--- a/docs/public/icons/embed.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/export--01.svg b/docs/public/icons/export--01.svg
deleted file mode 100644
index 77b72944..00000000
--- a/docs/public/icons/export--01.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/export--02.svg b/docs/public/icons/export--02.svg
deleted file mode 100644
index 6e94f768..00000000
--- a/docs/public/icons/export--02.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/docs/public/icons/launch.svg b/docs/public/icons/launch.svg
deleted file mode 100644
index eb3490c3..00000000
--- a/docs/public/icons/launch.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/love.svg b/docs/public/icons/love.svg
deleted file mode 100644
index 956a5196..00000000
--- a/docs/public/icons/love.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/minimize.svg b/docs/public/icons/minimize.svg
deleted file mode 100644
index 7b30ba26..00000000
--- a/docs/public/icons/minimize.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/paperclip.svg b/docs/public/icons/paperclip.svg
deleted file mode 100644
index 80e7456d..00000000
--- a/docs/public/icons/paperclip.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/player--flow.svg b/docs/public/icons/player--flow.svg
deleted file mode 100644
index 6f6ec5d8..00000000
--- a/docs/public/icons/player--flow.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/renew.svg b/docs/public/icons/renew.svg
deleted file mode 100644
index 267a8c4a..00000000
--- a/docs/public/icons/renew.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/repeat.svg b/docs/public/icons/repeat.svg
deleted file mode 100644
index 6b0514d8..00000000
--- a/docs/public/icons/repeat.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/reset.svg b/docs/public/icons/reset.svg
deleted file mode 100644
index e824d6f9..00000000
--- a/docs/public/icons/reset.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
diff --git a/docs/public/icons/trash.svg b/docs/public/icons/trash.svg
deleted file mode 100644
index 758aa56e..00000000
--- a/docs/public/icons/trash.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/docs/public/icons/upload--01.svg b/docs/public/icons/upload--01.svg
deleted file mode 100644
index c9a11c36..00000000
--- a/docs/public/icons/upload--01.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/docs/public/icons/upload--02.svg b/docs/public/icons/upload--02.svg
deleted file mode 100644
index 5faa79d7..00000000
--- a/docs/public/icons/upload--02.svg
+++ /dev/null
@@ -1,4 +0,0 @@
-
diff --git a/docs/public/images/.DS_Store b/docs/public/images/.DS_Store
new file mode 100644
index 00000000..5008ddfc
Binary files /dev/null and b/docs/public/images/.DS_Store differ
diff --git a/docs/public/images/cobalt-icon-solid.svg b/docs/public/images/cobalt-icon-solid.svg
new file mode 100644
index 00000000..3d840d3d
--- /dev/null
+++ b/docs/public/images/cobalt-icon-solid.svg
@@ -0,0 +1,5 @@
+
diff --git a/docs/public/images/cobalt-icon.svg b/docs/public/images/cobalt-icon.svg
new file mode 100644
index 00000000..751f719f
--- /dev/null
+++ b/docs/public/images/cobalt-icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/public/images/figma-colors.png b/docs/public/images/figma-colors.png
deleted file mode 100644
index efbf0e3c..00000000
Binary files a/docs/public/images/figma-colors.png and /dev/null differ
diff --git a/docs/public/images/figma-icons.png b/docs/public/images/figma-icons.png
deleted file mode 100644
index c61875f7..00000000
Binary files a/docs/public/images/figma-icons.png and /dev/null differ
diff --git a/docs/public/images/figma-typography.png b/docs/public/images/figma-typography.png
deleted file mode 100644
index 010fc955..00000000
Binary files a/docs/public/images/figma-typography.png and /dev/null differ
diff --git a/docs/public/images/home-bg-dark.png b/docs/public/images/home-bg-dark.png
new file mode 100644
index 00000000..caf6ab19
Binary files /dev/null and b/docs/public/images/home-bg-dark.png differ
diff --git a/docs/public/images/home-bg.png b/docs/public/images/home-bg.png
new file mode 100644
index 00000000..a3045bc8
Binary files /dev/null and b/docs/public/images/home-bg.png differ
diff --git a/docs/public/images/tokens-studio-for-figma.png b/docs/public/images/tokens-studio-for-figma.png
deleted file mode 100644
index 8d16e8b5..00000000
Binary files a/docs/public/images/tokens-studio-for-figma.png and /dev/null differ
diff --git a/docs/public/token-hex.svg b/docs/public/token-hex.svg
deleted file mode 100644
index 2b09fca5..00000000
--- a/docs/public/token-hex.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/docs/scripts/update-readmes.js b/docs/scripts/update-readmes.js
deleted file mode 100644
index 0e9659b4..00000000
--- a/docs/scripts/update-readmes.js
+++ /dev/null
@@ -1,33 +0,0 @@
-/**
- * Update READMEs
- *
- * For the docs pages that are just duplicates of other markdown files, automate them
- */
-
-import fs from 'node:fs';
-import {URL} from 'node:url';
-const FRONTMATTER_RE = /^---/gm;
-
-const updates = {
- '../../packages/plugin-css/README.md': '../src/pages/docs/integrations/css.md',
- '../../packages/plugin-sass/README.md': '../src/pages/docs/integrations/sass.md',
- '../../packages/plugin-js/README.md': '../src/pages/docs/integrations/js.md',
-};
-
-const urlRewrites = {
- '../plugin-css/': './css',
- '../plugin-js/': './js',
- '../plugin-sass/': './sass',
-};
-
-for (const [input, output] of Object.entries(updates)) {
- let src = fs.readFileSync(new URL(input, import.meta.url), 'utf8');
- for (const [find, replace] of Object.entries(urlRewrites)) {
- src = src.replace(new RegExp(`\\(${find}\\)`, 'g'), `(${replace})`);
- }
-
- const dest = fs.readFileSync(new URL(output, import.meta.url), 'utf8');
- const parts = dest.split(FRONTMATTER_RE);
- parts[parts.length - 1] = `\n\n${src}`;
- fs.writeFileSync(new URL(output, import.meta.url), parts.join('---'));
-}
diff --git a/docs/src/components/CobaltSm.astro b/docs/src/components/CobaltSm.astro
deleted file mode 100644
index ddaa34c9..00000000
--- a/docs/src/components/CobaltSm.astro
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
- Converting your tokens to JSON is a manual process of grabbing values from your design files and formatting the JSON yourself. There’s not a great UI for this yet, but the Cobalt team is developing one currently.
-
-
-
-
-
Save these all to a tokens.json file (or tokens.yaml, if you prefer YAML) like so:
-
-
-
-
You can use the following token types (organizing them into any Groups you’d like) (docs):
ℹ️ For this step, you’ll need Node.js installed (v20 is recommended).
-
-
- For this example, we’ll install the JS, Sass, and CSS plugins, but skip any you don’t need (you can always install them
- later).
-
-
-
Run the following in a terminal, in the code project folder you’d like to generate code to:
-
-
-
-
3. Running the CLI
-
-
First install the CLI:
-
-
-
-
Next, in the root of your code project, create a tokens.config.mjs file, importing the plugins you installed in the previous step:
-
-
-
-
To learn more about the config file, see config options. To learn about plugins and integrations, see Integrations.
-
-
Lastly, run the following command to generate all code from your tokens:
-
-
-
-
This will output JS, CSS, and Sass in the ./tokens/ folder (which you can change in your config). It will also alert you of any errors in your schema.
-
-
4. (optional) Adding Cobalt to CI
-
-
Using your preferred CI stack, here’s an example of how you could add Cobalt to your CI. First, we’ll take a package.json that had an existing npm run build command, and add co build to it:
-
-
-
-
Note: this is just a generic example. The important part is that co build is run somehow during the build.
-
-
Then add the npm run build command to your preferred CI tool. Here’s an example in GitHub Actions:
-
-
-
-
- This will then run co build on every code change. This not only validates your tokens to make sure they’re 100% valid; it also runs all the code plugins so you know if there was an error generating tokens to CSS, etc.
-
-
-
- You could then take the additional step of using a package versioning tool like Changesets to release npm packages from CI (the the Cobalt GitHub repo uses this to release new package versions automatically).
-
-
-
-
diff --git a/docs/src/pages/docs/guides/best-practices.md b/docs/src/pages/docs/guides/best-practices.md
deleted file mode 100644
index 955967c3..00000000
--- a/docs/src/pages/docs/guides/best-practices.md
+++ /dev/null
@@ -1,67 +0,0 @@
----
-title: Best Practices
-layout: ../../../layouts/docs.astro
----
-
-# Best practices
-
-Best practices are only community conventions meant to fill in opinions when you have none. Disregard any information in here if it doesn’t work with your organization, or if there is a conflict between this information and your configuration.
-
-## Aliasing
-
-Use [aliases](/docs/tokens#aliasing)! They’re free and can help make your design system easier-to-use. Here are just a few ways you can use aliases:
-
-- Common spelling differences, e.g. `color.gray` → `color.grey` (fun fact: CSS supports both spellings!)
-- Useful shortcuts, e.g. `color.white` → `color.gray.100`
-- Semantic colors e.g. `color.ui.action` → `color.blue`, `color.ui.error` → `color.red`, etc.
-
-## Casing
-
-Prefer **camelCased** properties when possible:
-
-```diff
- {
- "typography": {
-- "base-heading": {
-+ "baseHeading": {
- "$type": "fontFamily",
- "$value": "sans-serif"
- }
- }
- }
-```
-
-This will result in more predictable naming, and in many languages is simpler to reference (for example, in JavaScript):
-
-```diff
-- tokens.typography['base-heading'].$value;
-+ tokens.typography.baseHeading.$value;
-```
-
-## Logical color numbering
-
-Many design systems use [color ramps](https://ferdychristant.com/color-for-the-color-challenged-884c7aa04a56) which typically use numbers for greater flexiblity than relative terms like _dark_, _darker_, etc. But if possible, make your numbering follow some **logical** reasoning.
-
-For example, since Cobalt supports [OKLCH](https://evilmartians.com/chronicles/oklch-in-css-why-quit-rgb-hsl), you could use **perceived lightness** as the number where `color.blue.60` is 60% light, `color.blue.70` is 70% light, and so on:
-
-```json
-{
- "color": {
- "blue": {
- "10": {"$value": "oklch(10% 0.069574 264)"},
- "15": {"$value": "oklch(15% 0.102086 265)"},
- "20": {"$value": "oklch(20% 0.000304 265)"},
- "25": {"$value": "oklch(25% 0.172216 265)"},
- "30": {"$value": "oklch(30% 0.203543 266)"},
- "40": {"$value": "oklch(40% 0.216254 267)"},
- "50": {"$value": "oklch(50% 0.216583 268)"},
- "60": {"$value": "oklch(60% 0.216564 269)"},
- "70": {"$value": "oklch(70% 0.156718 268)"},
- "80": {"$value": "oklch(80% 0.100540 267)"},
- "85": {"$value": "oklch(85% 0.073053 266)"},
- "90": {"$value": "oklch(90% 0.048514 265)"},
- "95": {"$value": "oklch(95% 0.023788 264)"}
- }
- }
-}
-```
diff --git a/docs/src/pages/docs/guides/color.md b/docs/src/pages/docs/guides/color.md
deleted file mode 100644
index c94ebcd8..00000000
--- a/docs/src/pages/docs/guides/color.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Color
-layout: ../../../layouts/docs.astro
----
-
-# Color
-
-TODO
diff --git a/docs/src/pages/docs/guides/design-tokens.md b/docs/src/pages/docs/guides/design-tokens.md
deleted file mode 100644
index d19e1ac5..00000000
--- a/docs/src/pages/docs/guides/design-tokens.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: What are Design Tokens?
-layout: ../../../layouts/docs.astro
----
-
-# What are Design Tokens?
-
-Tokens are the fundamental building blocks of design. They typically refer to things like colors, typography, and icons, but have no formal definition or restriction on what they can be. Tokens aren’t user interface (UI); they’re the lower-level **common building blocks** that make up a UI design system.
-
-## History
-
-The coinage of the phrase “design tokens” dates back to a 2016 talk with Jina Bolton and Jon Levine talking about Salesforce’s _Lightning Design System_. In it they define their tokens as “basic sub-atoms of their design system.”
-
-
-
-
-
-## Why use Tokens?
-
-It‘s easy to fall into the trap of thinking that a design system is truly complete, and finished, and will never change. The reality is that just like products, design systems go through micro-iterations as well. Colors and typography get tweaked as you go through accessibility audits. Values get improved. It’s more realistic to look at your design system as a living, breathing, evolving creature that changes with time.
-
-Of course, keeping all code across all your products and platforms up-to-date with this changing, evolving, iterative brand is hard. Things have to be embedded into code at some level. So the thinking around design tokens is to find the elements of design that are so small and reusable that they can be managed in one central place and be reused across different programming languages and in different contexts.
-
-## Design Token Formats
-
-Though there is “one standard to rule them all” being actively worked on by the W3C that hopes to improve upon all previous formats, it’s still **under development** and subject to change.
-
-
-
-
-
-Cobalt uses the Design Tokens Format Module standard in the hopes that it will become a common/universal way of expressing design tokens. To get started, you can view either:
-
-- [Cobalt’s guide to writing tokens](/docs/tokens), or
-- [Design Token Format Module spec](https://design-tokens.github.io/community-group/format/)
-
-Other competing formats include, but aren’t limited to:
-
-- Style Dictionary
-- Tokens Studio for Figma plugin
-- Diez
diff --git a/docs/src/pages/docs/guides/figma.md b/docs/src/pages/docs/guides/figma.md
deleted file mode 100644
index 8b0a2ea5..00000000
--- a/docs/src/pages/docs/guides/figma.md
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Syncing with Figma
-layout: ../../../layouts/docs.astro
----
-
-# Figma
-
-Syncing with Figma since `1.1.0` is now done via the [Tokens Studio plugin for Figma](/docs/integrations/tokens-studio). The previous version of Figma syncing was buggy and incomplete.
diff --git a/docs/src/pages/docs/guides/index.md b/docs/src/pages/docs/guides/index.md
deleted file mode 100644
index 7189abcd..00000000
--- a/docs/src/pages/docs/guides/index.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-title: Guides
-layout: ../../../layouts/docs.astro
----
-
-# Guides
-
-- [What are Design Tokens?](/docs/guides/design-tokens/)
-- [Best Practices](/docs/guides/best-practices/)
-- [Thinking in Modes](/docs/guides/modes)
diff --git a/docs/src/pages/docs/guides/modes.astro b/docs/src/pages/docs/guides/modes.astro
deleted file mode 100644
index e3aecd94..00000000
--- a/docs/src/pages/docs/guides/modes.astro
+++ /dev/null
@@ -1,270 +0,0 @@
----
-import {Code} from 'astro/components';
-import Layout from '../../../layouts/docs.astro';
-import JSONYaml from '../../../components/JSONYaml.astro';
-
-const title = 'Modes';
----
-
-
-
{title}
-
-
Modes are alternate forms of a token. They allow your design system to account for different states or contexts that allow some values to change while others remain the same.
-
-
To explain this concept, we’ll explore 2 common usages: color and typography.
-
-
Example: color modes
-
-
-
-
- In this screenshot of GitHub’s dashboard you’ll find 5 color themes: Light default, Light high contrast, Dark default, Dark high contrast, and Dark dimmed (shown above). How might that be
- represented in tokens?
-
-
-
Note: since this guide was written, GitHub has since added additional color modes. But since that doesn’t change the concept, we’ll stick with the older (simpler) example for the purposes of illustration.
-
-
Without Modes
-
-
- Consider the red and white colors in the system. Whereas red has a different value for each mode, white is an absolute value that doesn’t change. A (wrong) first attempt may look
- something like:
-
-
-
-
-
But off the bat we have some problems:
-
-
-
Color themes are scattered between our original colors
-
Token names now carry implicit context
-
There’s not a clear abstraction of color themes
-
It’s unclear when [color]-[mode] exists, and when it doesn’t
-
Strict naming guidelines must be enforced for this to work long-term
-
Updating/managing color modes can become a precarious game of find-and-replace
-
What if red-darker was added in the future—do we now have red-darker, red-darker-dark, and red-darker-light?
-
-
-
With Modes
-
-
Modes exist to solve these problems by decoupling token names from context and state. This is how it can be represented with modes (using the “$extensions” property from the token syntax):
-
-
-
-
- Our tokens are vastly improved by having clear colors, and clear color modes. And color modes can be easily modified without affecting any names. Colors can optionally have mode variations, or not. And best of all, application-specific
- context isn’t affecting your token names.
-
-
-
- This simplifies your application code, too, as, you can simply refer to red or white and the mode can be inferred based on the global context (see the Examples in code section
- below to see the “how”).
-
-
-
With @cobalt/plugin-css
-
-
If using @cobalt/plugin-css, you could generate CSS to handle these modes. That would look something like:
-
-
-
-
- Then in your CSS, the correct color mode would apply automatically in most instances, but you could also set <body data-color-mode="[mode]"> to override it. Also note there aren’t browser-global colorblind
- preferences, so for the colorblind color schemes, they’d have to be set manually.
-
-
-
Example: typographic modes
-
-
-
-
Without Modes
-
-
Another common example is text size. If users need to make the text bigger or smaller, they can adjust to their taste. But trying to have this context exist in the token names can result in pretty long values:
-
-
-
-
- Referring to a font size as typography.size.title1-Medium or typography.size.title2-Medium is a bad idea, because then every level of your application must be aware of the user’s current preference settings.
- And if values ever change, now your entire application must be updated everywhere.
-
-
-
With Modes
-
-
Instead, by declaring font sizes as modes, the value becomes much more portable: typography.size.title1.
-
-
-
-
Now the user preferences only have to be dealt with in the global context, and the rest of your code will adapt.
-
-
Best practices
-
-
A mode is best used for 2 variations that are never used together.
-
-
- Back to the color example, if a user has requested colorblind-friendly colors, we’d never want to show them the colorblind-friendly green in some areas, and the colorblind-unfriendly green in the same view. We’d always want to respect
- their preferences. And thus, color modes are a great use of this.
-
-
-
So following that, here are some common scenarios for when modes should—or shouldn’t—be used.
-
-
✅ Good usecases for modes
-
-
Modes work best when a user can’t be in 2 contexts at once:
-
-
-
User preferences (e.g. text size, reduced motion, colorblind mode)
-
Device (e.g. mobile or desktop)
-
Region/language
-
Product/application area (e.g. different typographic settings in a dashboard UI vs longform content in marketing pages and documentation)
-
-
-
❌ Bad usecases for modes
-
-
However, when 2 or more things are frequently used side-by-side, modes should be avoided:
-
-
-
Semantic color (e.g success or error)
-
Localized state (e.g. disabled or active)
-
Color shades/hues
-
Components (e.g. card or button)
-
-
-
Examples in code
-
-
The examples above were generic concepts that applied to all languages. To see how to use modes in specific languages, see the following plugin docs:
To enforce all modes exist for a group. You can assert type checking with $extensions.requiredModes:
-
-
-
-
In the above example, we’d have an error on our red-4 color because the dark-high-contrast mode is missing.
-
-
requiredModes can be enforced at any level. And it will require any and all siblings and children to have every mode present.
-
diff --git a/docs/src/pages/docs/index.md b/docs/src/pages/docs/index.md
deleted file mode 100644
index e76adecf..00000000
--- a/docs/src/pages/docs/index.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: Getting Started
-layout: ../../layouts/docs.astro
----
-
-# Getting Started
-
-Cobalt exists to let you ship your `tokens.json` to any digital platform without having to build custom tooling. It includes adaptors for:
-
-- [CSS][plugins]
-- [Sass][plugins]
-- [JS/JSON/TS][plugins]
-
-[plugins]: ./plugins
diff --git a/docs/src/pages/docs/integrations/custom-plugins.md b/docs/src/pages/docs/integrations/custom-plugins.md
deleted file mode 100644
index 515b36dd..00000000
--- a/docs/src/pages/docs/integrations/custom-plugins.md
+++ /dev/null
@@ -1,165 +0,0 @@
----
-title: Plugins
-layout: ../../../layouts/docs.astro
----
-
-# Create your own plugins
-
-Creating your own Cobalt plugins is easy if you’re comfortable with JavaScript. This guide is for creating a custom plugin yourself; if you’re looking for instructions on how to use existing plugins, [see the plugins directory](/docs/integrations).
-
-## Why use Cobalt?
-
-Cobalt was created to deal with the following difficulties of the Design Tokens Format Module (DTFM) spec:
-
-1. **Validation**: Cobalt errs on schema violations
-2. **Normalization**: The DTFM spec allows for much flexibility, which means many unexpected values
-3. **Aliasing**: Cobalt resolves aliases (including _aliases of aliases of aliases!_) for you
-4. **Traversal**: A deeply-nested object is converted into a flat array for easy iteration
-5. **Modes** Cobalt extends the DTFM with powerful [modes](/docs/tokens#modes)
-6. **Figma syncing** Update your DTFM tokens with Figma easily
-
-## Basic structure
-
-A Cobalt plugin is a function that returns an object. That object requires only 2 things:
-
-1. **name**: a string that provides the name of your plugin (this will be shown if there are any errors)
-2. **build**: an asynchronous function that returns an array of files to be built.
-
-_Note: the following examples will be using TypeScript, but JavaScript will work just as well if you prefer!_
-
-```ts
-import type {Plugin} from '@cobalt-ui/core';
-
-export default function myPlugin(): Plugin {
- return {
- name: 'my-plugin',
- async build({tokens}) {
- return [
- {
- filename: 'my-filename.json',
- contents: tokens,
- },
- ];
- },
- };
-}
-```
-
-`tokens` is that array of tokens that have been validated, normalized, aliased, and all the other actions outlined above.
-
-The return signature of `build` is an array. This means you can output one, or multiple files with your plugin. Since `tokens/` is the default folder where everything gets generated ([configurable](/docs/reference/config/)), in our example we’d be generating a `tokens/my-filename.json` file when our plugin is done. `filename` is how we set the filename (and it accepts subfolders); `contents` is a string of code that will be written to disk (it can also accept a `Buffer` if needed).
-
-For many plugins, an output of one file will suffice (i.e. an array of one). But say you were generating multiple icons from tokens. You’d need to populate the array with one filename & content entry per icon. The array is meant to handle this case, rather than requiring a plugin that generates multiple files to deal with the file system directly and make sure all the user settings were respected.
-
-## Testing
-
-To test your plugin working on your design tokens, add it to your `tokens.config.mjs`:
-
-```js
-import myPlugin from './my-plugin.js';
-
-/** @type import('@cobalt-ui/core').Config */
-export default {
- plugins: [myPlugin()],
-};
-```
-
-Now when you run `co build`, your plugin will run and you can see its output.
-
-## Options
-
-Your plugin can accept any options desired as parameters to your main function. What your options are is entirely up to you and what makes sense of your plugin. Here’s an example of letting a user configure the `filename`:
-
-```ts
-import type {Plugin} from '@cobalt-ui/core';
-
-export interface MyPluginOptions {
- /** set the output filename */
- filename?: string;
- // add more options here!
-}
-
-export default function myPlugin(options: MyPluginOptions = {}): Plugin {
- const filename = options.filename || 'default-filename.json'; // be sure to always set a default!
- return {
- name: 'my-plugin',
- async build({tokens}) {
- return [
- {
- filename,
- contents: tokens,
- },
- ];
- },
- };
-}
-```
-
-You’d then pass any options into `tokens.config.mjs`:
-
-```js
-import myPlugin from './my-plugin.js';
-
-/** @type import('@cobalt-ui/core').Config */
-export default {
- plugins: [
- myPlugin({
- filename: 'custom.json',
- }),
- ],
-};
-```
-
-You can then expand `options` to be whatever shape you need it to be.
-
-## User Config
-
-Plugins may also provide an optional `config()` function to either read the user config, or modify it:
-
-```ts
-import type {Plugin} from '@cobalt-ui/core';
-
-export default function myPlugin(): Plugin {
- let outDir: URL | undefined;
- return {
- name: 'my-plugin',
- config(config) {
- outDir = config.outDir; // read the user’s outDir from the config, and save it
- // return nothing to leave config unaltered
- },
- async build({tokens}) {
- console.log(outDir); // now config info is accessible within the build() function
-
- return [
- {
- filename: 'my-filename.json',
- contents: tokens,
- },
- ];
- },
- };
-}
-```
-
-`config()` will be fired after the user’s config has been fully loaded and all plugins are instantiated, but before any build happens.
-
-## Cobalt token structure
-
-Cobalt gives you more context when dealing with tokens. Inspecting each individual token will yield the following:
-
-```js
-{
- id: 'color.brand.green', // the full ID of the token
- $type: 'color', // the original $type
- $value: '#40c362', // the normalized $value
- $extensions: {
- mode: {…} // normalized modes
- },
- _group: {…} // metadata about the token’s parent group
- _original: {…} // the original node untouched from tokens.json (including unresolved aliases, etc.)
-}
-```
-
-## Examples
-
-Examples of plugins may be found [in the original source repo](https://github.com/drwpow/cobalt-ui/tree/main/packages).
diff --git a/docs/src/pages/docs/integrations/index.md b/docs/src/pages/docs/integrations/index.md
deleted file mode 100644
index 7f9e974c..00000000
--- a/docs/src/pages/docs/integrations/index.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Integrations
-layout: ../../../layouts/docs.astro
----
-
-# Integrations
-
-Plugins let you **generate code** from your `tokens.json` / `tokens.yaml` manifest in your projects.
-
-## Plugins
-
-Each Cobalt plugin lets you generate code for your desired platform. You can use one plugin, or all of them!
-
-| Plugin | Generates | Platform |
-| :------------------------------------------------ | :--------------- | :----------------------------- |
-| [@cobalt-ui/plugin-css](/docs/integrations/css) | CSS | Web |
-| [@cobalt-ui/plugin-js](/docs/integrations/js) | JS, TS, and JSON | Web and Native Apps (via JSON) |
-| [@cobalt-ui/plugin-sass](/docs/integrations/sass) | Sass (and CSS) | Web |
-
-## External Tools
-
-Cobalt also supports the following external formats/tools, which can also be used in conjunction with any/all plugins.
-
-- [Style Dictionary](/docs/integrations/style-dictionary)
-- [Tokens Studio for Figma](/docs/integrations/tokens-studio)
-
-## Custom Plugins
-
-Cobalt was designed to be easy to create plugins within minutes. View the [developer guide to creating plugins](/docs/integrations/custom-plugins) to learn more.
diff --git a/docs/src/pages/docs/integrations/style-dictionary.md b/docs/src/pages/docs/integrations/style-dictionary.md
deleted file mode 100644
index 29f3eac8..00000000
--- a/docs/src/pages/docs/integrations/style-dictionary.md
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: Style Dictionary
-layout: ../../../layouts/docs.astro
----
-
-# Style Dictionary
-
-You can migrate your Style Dictionary tokens to the Design Tokens Format Module (DTFM) standard by running the following command (granted you have [the CLI installed](/docs/reference/cli)):
-
-```bash
-npx co convert style-dictionary-tokens.json --out tokens.json
-```
-
-
-
-⚠️ **Warning**
-This is **NOT** meant to be a comprehensive conversion. The DTFM standard is not 1:1 compatible with Style Dictionary. This will not import your transformations, and it will probably make mistakes, and miss tokens. This is only meant for **migrating** to the DTFM standard permanently, and is meant to save you some work by giving you a starting point you’ll have to clean up afterward.
-
-After running `npx co convert` it’s not recommended to keep using the Style Dictionary format.
-
-
-
-## Why convert to DTFM?
-
-While Style Dictionary is a powerful and flexible tool, it also requires more configuration and maintenance than the Design Tokens Format Module does. For example, Style Dictionary requires you place all your colors underneath a top-level `color` group. If you want to reference colors elsewhere, you’ll have to configure all your transformers to look for them. The same applies for `size` and `time` tokens.
-
-Further, Style Dictionary is missing more advanced features like `gradient`, `typography`, and `shadow` tokens from the DTFM spec, to name a few.
-
-While Style Dictionary was a significant trailblazer in managing design tokens and was the first mature library to accomplish this elegantly, the DTFM spec is being actively designed to make up for Style Dictionary’s shortcomings. The new DTFM spec is arguably more influenced by Style Dictionary than any other tool, and takes into account Style Dictionary’s way of doing things. DTFM is meant to replace the Style Dictionary format eventually.
diff --git a/docs/src/pages/docs/integrations/tailwind.md b/docs/src/pages/docs/integrations/tailwind.md
deleted file mode 100644
index a81110c3..00000000
--- a/docs/src/pages/docs/integrations/tailwind.md
+++ /dev/null
@@ -1,90 +0,0 @@
----
-title: Tailwind
-layout: ../../../layouts/docs.astro
----
-
-# Tailwind
-
-Cobalt’s Tailwind plugin lets you use your [Design Tokens Format Module](https://designtokens.org) tokens seamlessly in any Tailwind project by building your own custom [preset](https://tailwindcss.com/docs/presets). To start, install the Tailwind plugin and CLI:
-
-```bash
-npm install -D @cobalut-ui/plugin-tailwind @cobalt-ui/cli
-```
-
-_Note: this assumes you already have Tailwind [installed and configured](https://tailwindcss.com/docs/installation) in your project_
-
-Then set up your `tokens.config.mjs` file, adding the Tailwind plugin, and mapping token IDs to the Tailwind [theme config](https://tailwindcss.com/docs/configuration#theme) inside the `tailwind` option:
-
-```js
-// tokens.config.mjs
-import pluginTailwind from '@cobalt-ui/plugin-tailwind';
-
-/** @type import('@cobalt-ui/core').Config */
-export default {
- plugins: [
- pluginTailwind({
- /** (optional) the path to the Tailwind preset */
- output?: './tailwind-tokens.js',
- /** (optional) module format to use (to match your Tailwind config) */
- outputFormat?: 'esm' | 'cjs',
- /** @see https://tailwindcss.com/docs/configuration#theme */
- tailwind: {
- theme: {
- colors: {
- blue: {
- 100: 'color.blue.100', // map token IDs to Tailwind values
- 200: 'color.blue.200',
- // …
- },
- },
- fontFamily: {
- sans: 'typography.family.base',
- // …
- },
- spacing: {
- 1: 'token.size.s.space',
- 2: 'token.size.m.space',
- // …
- },
- borderRadius: {
- m: 'token.size.m.borderRadius',
- // …
- },
- },
- },
- }),
- ],
-};
-```
-
-Then, when you run `co build` in your project, it will generate a `./tokens/tailwind-tokens.js` file. Now add it to your Tailwind config under `presets` ([docs](https://tailwindcss.com/docs/configuration#presets)):
-
-```diff
- // tailwind.config.js
-
- /** @type {import('tailwindcss').Config} */
- export default {
-+ presets: ['./tokens/tailwind-tokens.js'],
- };
-```
-
-_Note: if using CommonJS, use the `format: 'cjs'` plugin option._
-
-And you’re up and running! You’ll now have all your design tokens available in Tailwind.
-
-_✨ **Tip**: be sure to rerun `co build` to rebuild your Tailwind preset, or run `co build --watch` to rebuild your tokens every time they change!_
-
-## Publishing to npm
-
-You can publish your preset to npm, and keep it versioned like any of your other dependencies. You can then just consume the preset by passing the npm package name to Tailwind’s `presets` option:
-
-```js
-// tailwind.config.js
-
-/** @type {import('tailwindcss').Config} */
-export default {
- presets: ['@my-scope/my-tokens-package'],
-};
-```
-
-_✨ **Tip**: if publishing to npm, either name your Tailwind preset `./index.js`, or set the `package.json` [main field](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#main) to point directly to `./tailwind-tokens.js`._
diff --git a/docs/src/pages/docs/integrations/tokens-studio.md b/docs/src/pages/docs/integrations/tokens-studio.md
deleted file mode 100644
index 50625fee..00000000
--- a/docs/src/pages/docs/integrations/tokens-studio.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: Tokens Studio for Figma
-layout: ../../../layouts/docs.astro
----
-
-# Tokens Studio for Figma
-
-![Tokens Studio for Figma](/images/tokens-studio-for-figma.png)
-
-[Tokens Studio for Figma](https://tokens.studio/) is a free plugin that makes managing design tokens in Figma easy ([docs](https://docs.tokens.studio/)). While it doesn’t use the [Design Tokens Format Module](https://designtokens.org) (DTFM) like Cobalt does, Cobalt supports most of Tokens Studio’s format.
-
-To use Tokens Studio, first export a `tokens.json` file using [any of the approved sync methods](https://docs.tokens.studio/sync/sync). Then use Cobalt as you would normally:
-
-```js
-import pluginCSS from '@cobalt-ui/plugin-css';
-
-/** @type import('@cobalt-ui/core').Config */
-export default {
- tokens: './tokens.json',
- outDir: './tokens/',
- plugins: [pluginCSS()],
-};
-```
-
-## Compatibility
-
-| Token Studio Token | Supported | Notes |
-| :-------------------------------------------------------------------------------- | :-------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| [Sizing](https://docs.tokens.studio/available-tokens/sizing-tokens) | ✅ | Converted to [Dimension](/docs/tokens/#dimension). |
-| [Spacing](https://docs.tokens.studio/available-tokens/spacing-tokens) | ✅ | Converted to [Dimension](/docs/tokens/#dimension). |
-| [Color](https://docs.tokens.studio/available-tokens/color-tokens) | ✅ | Flat colors are kept as [Color](/docs/tokens/#color) while gradients are converted to [Gradient](/docs/tokens/#gradient). Modifiers aren’t supported. |
-| [Border radius](https://docs.tokens.studio/available-tokens/border-radius-tokens) | ✅ | Converted to [Dimension](/docs/tokens/#dimension). Multiple values are expanded into 4 tokens (`*TopLeft`, `*TopRight`, `*BottomLeft`, `*BottomRight`). |
-| [Border width](https://docs.tokens.studio/available-tokens/border-width-tokens) | ✅ | Converted to [Dimension](/docs/tokens/#dimension). |
-| [Shadow](https://docs.tokens.studio/available-tokens/shadow-tokens) | ✅ | Basically equivalent to [Shadow](/docs/tokens/#shadow). |
-| [Opacity](https://docs.tokens.studio/available-tokens/opacity-tokens) | ✅ | Converted to [Number](/docs/tokens/#number) |
-| [Typography](https://docs.tokens.studio/available-tokens/typography-tokens) | ✅ | Basically equivalent to [Typography](/docs/tokens/#typography). **Text decoration** and **Text Case** must be flattened as there is no DTFM spec equivalent. |
-| [Asset](https://docs.tokens.studio/available-tokens/asset-tokens) | ❌ | TODO. Cobalt supports [Link](/docs/tokens/#link), which should be an equivalent. |
-| [Composition](https://docs.tokens.studio/available-tokens/composition-tokens) | ❌ | Unsupported because this is a paid feature. |
-| [Dimension](https://docs.tokens.studio/available-tokens/dimension-tokens) | ✅ | Direct equivalent to [Dimension](/docs/tokens/#dimension). |
-| [Border](https://docs.tokens.studio/available-tokens/border-tokens) | ✅ | Direct equivalent to [Border](/docs/tokens/#border). |
-
-Note that **Duration** and **Cubic Bezier** aren’t supported by Tokens Studio (because Figma currently doesn’t support animations). So to use those types you’ll need to convert your tokens into DTFM.
-
-Though Cobalt preserves your [Token Sets](https://docs.tokens.studio/themes/token-sets), which means most aliases will work, Token Studio’s [Advanced Themes](https://docs.tokens.studio/themes/themes-pro) is a paid feature and is therefore not supported. Though you could manually upconvert Token Studio themes to [modes](http://localhost:3000/docs/tokens/#modes).
diff --git a/docs/src/pages/docs/reference/cli.md b/docs/src/pages/docs/reference/cli.md
deleted file mode 100644
index 6da058cd..00000000
--- a/docs/src/pages/docs/reference/cli.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: About Cobalt
-layout: ../../../layouts/docs.astro
----
-
-# CLI
-
-The Cobalt CLI is available for installing via npm:
-
-```bash
-npm i -D @cobalt-ui/cli
-```
-
-## API
-
-All CLI commands require a [config](/docs/reference/config/) to work properly, with the exception of `co check` and `co convert`.
-
-`npx co [command]`
-
-| Command | Notes |
-| :---------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `build` | Turn design tokens into output files using [plugins](/docs/integrations). You can watch for changes in dev mode with `build --watch`. |
-| `bundle --out [path]` | Bundle multiple `tokens.json` files into one, e.g. `co bundle --out path/to/output.json`. Can output `.json` or `.yaml`. Requires [multiple schemas set in config](https://cobalt-ui.pages.dev/docs/reference/config/#loading-multiple-schemas) |
-| `check [path]` | Validate a `tokens.json` file and check for errors. This won’t output any files. |
-| `init` | Create a starter `tokens.json` file. |
-| `convert [path] --out [path]` | Convert a [Style Dictionary](https://amzn.github.io/style-dictionary) JSON file to Design Tokens Format Module ([docs](/docs/guides/style-dictionary)) |
diff --git a/docs/src/pages/docs/reference/config.md b/docs/src/pages/docs/reference/config.md
deleted file mode 100644
index c993748e..00000000
--- a/docs/src/pages/docs/reference/config.md
+++ /dev/null
@@ -1,106 +0,0 @@
----
-title: Config
-layout: ../../../layouts/docs.astro
----
-
-# Config
-
-Customizing Cobalt and managing plugins requires you to add a `tokens.config.mjs` file in the root of your project. Here’s an example configuration with all settings and defaults:
-
-```js
-// tokens.config.mjs
-import pluginJS from '@cobalt-ui/plugin-js';
-
-/** @type import('@cobalt-ui/core').Config */
-export default {
- tokens: './tokens.json',
- outDir: './tokens/',
- plugins: [pluginJS()],
-
- /** token type options */
-};
-```
-
-### Loading from YAML
-
-Cobalt supports `tokens.json` as YAML as well:
-
-```js
-export default {
- tokens: './tokens.yaml',
-};
-```
-
-
-
-⚠️ Note the file must end in `.yml` or `.yaml` to take effect
-
-
-
-### Loading from URL
-
-Cobalt can load tokens from any **publicly-available** URL:
-
-```js
-// tokens.config.mjs
-export default {
- tokens: 'https://my-bucket.s3.amazonaws.com/tokens.json',
-};
-```
-
-### Loading from npm
-
-To load tokens from an npm package, update `config.tokens` to point to the **full JSON path** (not merely the root package):
-
-```diff
- /** @type import('@cobalt-ui/core').Config */
- export default {
-- tokens: "@my-scope/my-tokens", // ❌ Cobalt won’t be able to find the tokens
-+ tokens: "@my-scope/my-tokens/tokens.json", // ✅ Cobalt can locate this just fine
-```
-
-### Loading multiple schemas
-
-Cobalt supports loading multiple tokens schemas by passing an array:
-
-```js
-// tokens.config.mjs
-export default {
- tokens: ['./base.json', './theme.json', './overrides.json'],
-};
-```
-
-Cobalt will flatten these schemas in order, with the latter entries overriding the former if there are any conflicts. The final result of all the combined schemas **must** result in a valid tokens.json.
-
-
-
-⚠️ **Warning** All aliases must refer to the same document, e.g. don’t try to include filenames such as `{./theme.json#/color.action.50}`. Reference it as if it were in the same file.
-
-
-
-## Token Type Options
-
-Some token types allow for extra configuration.
-
-```ts
-// tokens.config.mjs
-export default {
- color: {
- convertToHex: false, // Convert all colors to sRGB hexadecimal (default: false). By default, colors are kept in their formats
- },
-};
-```
-
-| Name | Type | Description |
-| :------------------- | :-------: | :--------------------------------------------------------------------------------------------------------------- |
-| `color.convertToHex` | `boolean` | Convert this color to sRGB hexadecimal. By default, colors are kept in the original formats they’re authored in. |
-
-## Syncing with Figma
-
-You can sync tokens with Figma by using the [Tokens Studio for Figma](/docs/integrations/tokens-studio) plugin.
-
-## Integrations
-
-Each integration comes with its own rules and setup. Follow the corresponding guide to enable code generation:
-
-👉 **[View Integrations](/docs/integrations)**
diff --git a/docs/src/pages/docs/reference/index.md b/docs/src/pages/docs/reference/index.md
deleted file mode 100644
index 12a82de2..00000000
--- a/docs/src/pages/docs/reference/index.md
+++ /dev/null
@@ -1,10 +0,0 @@
----
-title: Reference
-layout: ../../../layouts/docs.astro
----
-
-# Reference
-
-- [CLI API](/docs/reference/cli)
-- [Config API](/docs/reference/config)
-- [About](/docs/reference/about)
diff --git a/docs/src/pages/docs/tips.md b/docs/src/pages/docs/tips.md
deleted file mode 100644
index 55feae4e..00000000
--- a/docs/src/pages/docs/tips.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: tokens.json
-layout: ../../layouts/docs.astro
----
-
-# Cobalt Schema v0
-
-### Tips
-
-- Good IDs should be in their shortest form, while being recognizable. For example, consider “Typography”:
- - ❌ `typography` too long
- - ✅ `type` a common shorthand for “typography”
- - ✅ `font` also good; may also be preferred over “type” which out-of-context has other meanings
- - ❌ `t` too short—what does this even mean?
-- IDs can be capitalized. But try to be consistent with capitalization:
- - ❌ `Type.Family.FoundersGrotesk` and `color.tiffany_blue` are both individually fine, but together they disagree. Prefer one or the other.
-- If IDs use underscores (`_`), they will work easily in any language
- - ✅ `dark_blue` works in CSS, JavaScript, and many other programming languages
- - ❌ `dark-blue` works in CSS but not JavaScript nor other programming languages (without being escaped)
- - ✅ `darkBlue` or `DarkBlue` also works without underscores; up to you on which is more readable
diff --git a/docs/src/pages/docs/tokens/index.astro b/docs/src/pages/docs/tokens/index.astro
deleted file mode 100644
index dcb88f3f..00000000
--- a/docs/src/pages/docs/tokens/index.astro
+++ /dev/null
@@ -1,811 +0,0 @@
----
-import JSONYaml from '../../../components/JSONYaml.astro';
-import Token from '../../../components/Token.astro';
-import Layout from '../../../layouts/docs.astro';
-
-const title = 'Tokens';
-
-const tokenDef = {
- border: 'https://design-tokens.github.io/community-group/format/#border',
- color: 'https://design-tokens.github.io/community-group/format/#color',
- cubicBezier: 'https://design-tokens.github.io/community-group/format/#cubic-bezier',
- dimension: 'https://design-tokens.github.io/community-group/format/#dimension',
- duration: 'https://design-tokens.github.io/community-group/format/#duration',
- fontFamily: 'https://design-tokens.github.io/community-group/format/#font-family',
- fontWeight: 'https://design-tokens.github.io/community-group/format/#font-weight',
- number: 'https://design-tokens.github.io/community-group/format/#number',
- gradient: 'https://design-tokens.github.io/community-group/format/#gradient',
- shadow: 'https://design-tokens.github.io/community-group/format/#shadow',
- strokeStyle: 'https://design-tokens.github.io/community-group/format/#stroke-style',
- transition: 'https://design-tokens.github.io/community-group/format/#transition',
- typography: 'https://design-tokens.github.io/community-group/format/#typography',
-};
----
-
-
-
Tokens
-
-
- Tokens are defined via the Design Tokens Format Module schema (Apr 2023). You’ll save your tokens in a tokens.yaml or tokens.json file in the root of your
- project. Cobalt supports 100% of the spec, but with the following changes:
-
A composite type combining color and percentages (normalized to 1) to form the stops of a CSS gradient, as defined in 9.6.
-
-
- Note: you’ll notice that there’s information missing on whether this is a linear, radial, or conic gradient
-
-
-
-
-
Property
-
Type
-
Description
-
-
-
-
$type
-
string
-
gradient
-
-
-
$value
-
{'{'}color: string, position: number{'}'}[]
-
Array of stops that provide both a color and position, from 0 (0%) to 1 (100%).
-
-
-
-
-
-
-
-
- Typography
-
-
-
A composite type combining font and dimension to form a complete typographic style, as defined in 9.7.
-
-
-
-
Property
-
Type
-
Description
-
-
-
-
$type
-
string
-
typography
-
-
-
$value
-
object
-
Specify any typographic CSS properties in camelCase format. Although the spec limits the properties to only a few, Cobalt allows any valid attributes including letterSpacing, fontVariant, etc.
-
-
-
-
-
-
-
Groups
-
-
- A group is a way to collect similar tokens. A group is made by omitting $value (and it is impossible for a group to have a $value). In the schema, all reserved names start with a $. All other
- properties will be treated either as tokens or other sub-groups.
-
-
-
-
-
Property
-
Type
-
Description
-
-
-
-
$description
-
string
-
(optional) Set a human-readable description for this group
-
-
-
$type
-
string
-
(optional) Lets child tokens omit $type and will use this instead (can be overridden per-token)
-
-
-
$extensions
-
object
-
(optional) Any arbitrary data is allowed within `$extensions` object.
-
-
-
$extensions.requiredModes
-
string[]
-
(optional) Cobalt: Enforce mode IDs that must be present on all child tokens
-
-
-
-
-
Example
-
-
- In this example, both color and typography are groups, as neither have a $value. But typography also has a subgroup: family. Groups can be nested infinitely, as long as
- they’re not inside tokens.
-
-
-
-
-
Custom types
-
-
- Any other $type will be treated as a custom type. $value may have any shape desired. But note that custom types will likely break existing plugins unless you configure them (the CSS and Sass plugins have a transformer option), or unless you write your own plugin for Cobalt (which is easier than some may think!).
-
- Types can be aliased as defined in the Design Tokens spec by using dot-delimited path syntax, wrapped in curly braces (e.g., {'{'}groupA.groupB.token{'}'}):
-
-
-
-
-
Modes
-
-
- Modes are alternate versions of your tokens. For example, say your design system has a standard palette and an alternate version optimized for colorblind users. Here’s one way you could
- declare that:
-
-
-
-
-
This works but has several problems:
-
-
-
❌ multiple palettes are mixed into one
-
❌ this suggests red and redColorblind should be used alongside one another (defeating the whole purpose!)
-
❌ it’s unclear what the purpose of redColorblind is, and will likely be avoided by engineers
-
-
-
To address all these, let’s use modes instead by adding an $extensions.mode property:
-
-
-
-
This is much better:
-
-
-
✅ palettes are kept separate
-
✅ when colorblind mode is enabled, it prevents standard red from being used
-
✅ in code, switching from standard to colorblind mode automatically creates the palette
Note: all examples are unofficial and for demonstration purposes only; all companies referenced retain full ownership over their respective systems, and are unaffiliated with this project: