From 510315ef315c8e7881f59b385af5f577773ac05e Mon Sep 17 00:00:00 2001
From: cassie spain <58054751+dreamwasp@users.noreply.github.com>
Date: Mon, 25 Nov 2024 16:45:23 -0500
Subject: [PATCH] typography + meta (#2975)
* create foundations + layout stories
* start foundations
* start retooling componentheader
* component header tweak
* start restructure of header components
* TOC + Theme working, need DataTable + code background color
* working on color mode - need to fix text color
* revert test
* Theme page sorted, need to fix ColorMode
* colormode sorted
* colormode sorted
* start type fix + what to do about blocks
* LayoutGrid + content Container
* LayoutGrid done
* start flexbox, need to look into sandbox stuff
* gridbox + flexbox are good, just need to tweak
* tweaks to headers
* lots of style tweaks + deduplications
* fix typograpth, need to fix color mode switches
* start on system stories
* unify shared elements
* add variance + fix tables
* more tweaks to status
* design tweaks
* add hub
* more tweaks
* rename DataTable
* clean up of default
* typography + meta stories
* add anchor story
* start text + hiddentext
* text done
* started snippet changes
* fixed code snippets
* meta and sorted done?"
* renamed + sorting
* more kenny edits
* more kenny edits + other new tab for links
* the last of it
---
.vscode/stories.code-snippets | 171 +++++++-----
.../components/Elements/Callout.tsx | 9 +
.../components/Elements/Markdown.tsx | 4 +-
.../components/Headers/ComponentHeader.tsx | 1 -
.../.storybook/components/index.tsx | 1 +
packages/styleguide/.storybook/preview.ts | 19 +-
packages/styleguide/src/lib/Layouts/About.mdx | 6 +-
packages/styleguide/src/lib/Meta/About.mdx | 40 +++
.../src/lib/Meta/Best Practices.mdx | 247 ++++++++++++++++++
packages/styleguide/src/lib/Meta/Brand.mdx | 16 ++
.../styleguide/src/lib/Meta/Contributing.mdx | 92 +++++++
packages/styleguide/src/lib/Meta/FAQs.mdx | 58 ++++
packages/styleguide/src/lib/Meta/Stories.mdx | 169 ++++++++++++
.../styleguide/src/lib/Typography/About.mdx | 44 ++++
.../lib/Typography/Anchor/Anchor.examples.tsx | 116 ++++++++
.../src/lib/Typography/Anchor/Anchor.mdx | 110 ++++++++
.../lib/Typography/Anchor/Anchor.stories.tsx | 87 ++++++
.../lib/Typography/HiddenText/HiddenText.mdx | 36 +++
.../HiddenText/HiddenText.stories.tsx | 14 +
.../src/lib/Typography/Text/Text.mdx | 111 ++++++++
.../src/lib/Typography/Text/Text.stories.tsx | 160 ++++++++++++
.../src/lib/Typography/Text/tables.tsx | 21 ++
.../src/static/typography/anchor.png | Bin 0 -> 8360 bytes
23 files changed, 1466 insertions(+), 66 deletions(-)
create mode 100644 packages/styleguide/.storybook/components/Elements/Callout.tsx
create mode 100644 packages/styleguide/src/lib/Meta/About.mdx
create mode 100644 packages/styleguide/src/lib/Meta/Best Practices.mdx
create mode 100644 packages/styleguide/src/lib/Meta/Brand.mdx
create mode 100644 packages/styleguide/src/lib/Meta/Contributing.mdx
create mode 100644 packages/styleguide/src/lib/Meta/FAQs.mdx
create mode 100644 packages/styleguide/src/lib/Meta/Stories.mdx
create mode 100644 packages/styleguide/src/lib/Typography/About.mdx
create mode 100644 packages/styleguide/src/lib/Typography/Anchor/Anchor.examples.tsx
create mode 100644 packages/styleguide/src/lib/Typography/Anchor/Anchor.mdx
create mode 100644 packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx
create mode 100644 packages/styleguide/src/lib/Typography/HiddenText/HiddenText.mdx
create mode 100644 packages/styleguide/src/lib/Typography/HiddenText/HiddenText.stories.tsx
create mode 100644 packages/styleguide/src/lib/Typography/Text/Text.mdx
create mode 100644 packages/styleguide/src/lib/Typography/Text/Text.stories.tsx
create mode 100644 packages/styleguide/src/lib/Typography/Text/tables.tsx
create mode 100644 packages/styleguide/src/static/typography/anchor.png
diff --git a/.vscode/stories.code-snippets b/.vscode/stories.code-snippets
index be682ee3d1..da25ae07cd 100644
--- a/.vscode/stories.code-snippets
+++ b/.vscode/stories.code-snippets
@@ -1,86 +1,137 @@
{
- "Component Story": {
- "prefix": "component-story",
+ "Component Doc": {
+ "prefix": "component-doc",
"body": [
- "import { $1 } from '@codecademy/$2';",
- "import title from '@codecademy/macros/lib/title.macro';",
- "import { Canvas, Meta, Story } from '@storybook/addon-docs/blocks';",
- "import { PropsTable } from '@codecademy/storybook-addon-variance';",
+ "import { Canvas, Controls, Meta } from '@storybook/blocks';",
+ "",
+ "import { ComponentHeader } from '~styleguide/blocks';",
+ "",
+ "import * as $1Stories from './$1.stories';",
+ "",
+ "export const parameters = {",
+ "subtitle: `Template component`,",
+ "design: {",
+ "type: 'figma',",
+ "url: 'https: //www.figma.com/file/XXX',",
+ " },",
+ "status: 'current',",
+ "source: {",
+ "repo: '$2',",
+ "// this is easy to find by right clicking on the file in VSCode and clicking 'Copy Remote File Url From...' and the selecting 'main' or amending the url path below like so: https://github.com/Codecademy/gamut/blob/main/packages/${2}/src/file/location",
+ "githubLink:",
+ "'https: //github.com/Codecademy/gamut/blob/main/packages/gamut/src/Logo',",
+ " },",
+ "};",
+ "",
+ "",
+ "",
+ "",
+ "## Usage",
+ "",
+ "Use $1 to [what it should be used for]",
+ "",
+ "### Best practices:",
+ "",
+ "- [recommendation / best practice for implementation]",
+ "- [recommendation / best practice for implementation]",
+ "",
+ "When NOT to use",
+ "",
+ "- [use case]- for [describe the use case], use the [similar component] component.",
+ "- [use case]- for [describe the use case], use the [similar component] component",
+ "",
+ "## Anatomy",
+ "",
+ "[Insert image exported from Figma]",
+ "",
+ "1. [Element name]",
+ "- [description including available options and ux writing if relevant]",
"",
- "",
+ "## Variants",
"",
- "`$1` component summary goes here",
+ "### [Variant 1 name]",
"",
- "## Design Principles",
+ "Use the [variant 1 name] to [what it should be used for]",
"",
- "Design Principles summary",
+ "",
"",
- "## Usage Guidelines",
+ "## Playground",
"",
- "Usage summary",
+ "If you are using a story named 'Default', you can forgo the `of` prop.",
"",
- "## Code Playground",
+ "",
"",
- "",
+ "",
"",
- ""
+ "## Accessibility considerations",
+ "",
+ "- [Accessibility guidance]",
+ "",
+ "## UX writing",
+ "",
+ "- [content]",
+ " - [guidance]",
+ " - [guidance]"
],
- "description": "Default Component Story Structure."
+ "description": "Default Component Doc Structure."
},
"Table of Contents Story": {
"prefix": "toc-story",
"body": [
- "import title from '@codecademy/macros/lib/title.macro';",
- "import { Meta } from '@storybook/addon-docs/blocks';",
+ "import { Meta } from '@storybook/blocks';",
+ "import { AboutHeader, TableOfContents } from '~styleguide/blocks';",
+ "",
+ "export const parameters = {",
+ " id: '$1',",
+ " title: '$1/About',",
+ " subtitle: '$2',",
+ " }",
"",
- "import { TableOfContents } from '~styleguide/blocks';",
+ "",
"",
- "",
+ "",
"",
- ""
+ "Foundations make up the smallest scale design values that comprise a design system. Sometimes referred to elsewhere as "tokens", they are the abstract units that comprise and stitch together our atoms, molecules, and organisms.",
+ "",
+ ""
],
"description": "TOC Story Structure."
},
- "Canvas Block": {
- "prefix": "canvas-block",
- "body": [
- ""
- ],
- "description": "A single story block wrapped in a canvas"
- },
- "Story Block": {
- "prefix": "story-block",
+ "Component Story": {
+ "prefix": "component-story",
"body": [
- " ",
- " {(args) => <$2 {...args} />}",
- " "
+ "import { $1 } from '@codecademy/gamut';",
+ "import type { Meta, StoryObj } from '@storybook/react';",
+ "",
+ "const meta: Meta = {",
+ " component: $1,",
+ " args: {},",
+ "};",
+ "",
+ "export default meta;",
+ "type Story = StoryObj;",
+ "",
+ "export const Default: Story = {",
+ " args: {",
+ " children: 'Test'",
+ " },",
+ "};",
+ "",
+ "export const Secondary: Story = {",
+ " args: {",
+ " children: 'Test again',",
+ " variant: 'secondary'",
+ " }",
+ "};"
],
- "description": "A single story block without a canvas"
+ "description": "Default TSX story structure."
}
}
diff --git a/packages/styleguide/.storybook/components/Elements/Callout.tsx b/packages/styleguide/.storybook/components/Elements/Callout.tsx
new file mode 100644
index 0000000000..f33b94df76
--- /dev/null
+++ b/packages/styleguide/.storybook/components/Elements/Callout.tsx
@@ -0,0 +1,9 @@
+import { Alert } from '@codecademy/gamut';
+
+export const Callout: React.FC<{ text: string }> = ({ text }) => {
+ return (
+
+ {text}
+
+ );
+};
diff --git a/packages/styleguide/.storybook/components/Elements/Markdown.tsx b/packages/styleguide/.storybook/components/Elements/Markdown.tsx
index 0a5de3cc23..3ecf29348e 100644
--- a/packages/styleguide/.storybook/components/Elements/Markdown.tsx
+++ b/packages/styleguide/.storybook/components/Elements/Markdown.tsx
@@ -24,7 +24,9 @@ export const Link: React.FC = ({ ref, id, variant, ...props }) => {
if (variant === 'area') {
return ;
}
- return ;
+ return (
+
+ );
};
export const LinkTo = Link;
diff --git a/packages/styleguide/.storybook/components/Headers/ComponentHeader.tsx b/packages/styleguide/.storybook/components/Headers/ComponentHeader.tsx
index 6dccb7a0d3..9f080192b6 100644
--- a/packages/styleguide/.storybook/components/Headers/ComponentHeader.tsx
+++ b/packages/styleguide/.storybook/components/Headers/ComponentHeader.tsx
@@ -5,7 +5,6 @@ import {
InfoTip,
Text,
} from '@codecademy/gamut';
-import { Background } from '@codecademy/gamut-styles';
import { Figma } from '@storybook/addon-designs/blocks';
import { Title } from '@storybook/blocks';
import * as React from 'react';
diff --git a/packages/styleguide/.storybook/components/index.tsx b/packages/styleguide/.storybook/components/index.tsx
index 008fae063a..a5c61b29fb 100644
--- a/packages/styleguide/.storybook/components/index.tsx
+++ b/packages/styleguide/.storybook/components/index.tsx
@@ -1,6 +1,7 @@
export * from './ImageWrapper';
export * from './TokenTable';
export * from './Headers';
+export * from './Elements/Callout';
export * from './Elements/Markdown';
export * from './Scales/ColorScale';
export * from './Navigation/TableOfContents';
diff --git a/packages/styleguide/.storybook/preview.ts b/packages/styleguide/.storybook/preview.ts
index b4556eab63..31d80937ff 100644
--- a/packages/styleguide/.storybook/preview.ts
+++ b/packages/styleguide/.storybook/preview.ts
@@ -7,13 +7,28 @@ import { DocsContainer } from './components/Elements/DocsContainer';
const preview: Preview = {
parameters: {
+ backgrounds: {
+ disable: true,
+ },
docs: {
container: DocsContainer,
theme: theme,
toc: { headingSelector: 'h1, h2, h3' },
},
- backgrounds: {
- disable: true,
+ options: {
+ storySort: {
+ method: 'configure',
+ includeNames: true,
+ order: [
+ 'Meta',
+ ['About', 'Best Practices', 'Contributing', 'FAQs', 'Stories'],
+ 'Foundations',
+ 'Layouts',
+ 'Typography',
+ 'Atoms',
+ '*',
+ ],
+ },
},
viewport: {
defaultViewport: 'responsive',
diff --git a/packages/styleguide/src/lib/Layouts/About.mdx b/packages/styleguide/src/lib/Layouts/About.mdx
index 5313fa35ed..4fc6ed7bf3 100644
--- a/packages/styleguide/src/lib/Layouts/About.mdx
+++ b/packages/styleguide/src/lib/Layouts/About.mdx
@@ -9,7 +9,7 @@ export const parameters = {
'Layouts are basic building blocks to help you construct layouts on the page via configuration',
};
-
+
@@ -21,6 +21,7 @@ Pure sizing and padding containers. These position our elements on pages in stan
id: 'Layouts/Boxes/About',
subtitle: 'Flexible container component with all system props available.',
title: 'Boxes',
+ status: 'current',
},
{
id: 'Layouts/ContentContainer',
@@ -35,5 +36,6 @@ Pure sizing and padding containers. These position our elements on pages in stan
status: 'current',
title: 'LayoutGrid',
},
- ]}
+
+]}
/>
diff --git a/packages/styleguide/src/lib/Meta/About.mdx b/packages/styleguide/src/lib/Meta/About.mdx
new file mode 100644
index 0000000000..67054a34f6
--- /dev/null
+++ b/packages/styleguide/src/lib/Meta/About.mdx
@@ -0,0 +1,40 @@
+import { Meta } from '@storybook/blocks';
+
+import { AboutHeader, TableOfContents } from '~styleguide/blocks';
+
+export const parameters = {
+ id: 'Meta',
+ title: 'Meta',
+ subtitle:
+ 'Documentation and associated links explaining our in-progress approach to a design system.',
+};
+
+
+
+
+
+
diff --git a/packages/styleguide/src/lib/Meta/Best Practices.mdx b/packages/styleguide/src/lib/Meta/Best Practices.mdx
new file mode 100644
index 0000000000..f02e19a473
--- /dev/null
+++ b/packages/styleguide/src/lib/Meta/Best Practices.mdx
@@ -0,0 +1,247 @@
+import { Meta } from '@storybook/blocks';
+
+import { AboutHeader, Callout } from '~styleguide/blocks';
+
+export const parameters = {
+ id: 'Best Practices',
+ title: 'Best Practices',
+ subtitle: 'Current best practices for using the Gamut Design System',
+ status: 'current',
+};
+
+
+
+
+
+For best practices for writing for specific components, like alerts, errors, or confirmation dialogs, check out the individual component pages.
+
+# Variants + ColorMode
+
+The way we access design tokens is becoming increasingly important as we move away from a single theme and towards a system of themes. The best way to access design tokens is through our semantic colors, which are are tied intrinsically to ColorModes. This means that when you use a semantic color, you are guaranteed to get the right color for the right theme. Using variants and and its related utilities will also guarantee you have access to the right tokens, typings, and _state_ going forward. It is also [safer](https://gamut.codecademy.com/?path=/docs/foundations-system-compose--page)!
+
+Think of our semantic color names as a variable referencing _what the primary use of the color is within each color mode_. For example - an icon set to the `text` color will match _the primary color of text within that color mode._
+
+For specific semantic name to color, please see the [ColorMode](https://gamut.codecademy.com/?path=/docs/foundations-colormode--page) documentation.
+
+### Use the utility functions from `gamut-styles` with ColorMode semantic color names + shorthands
+
+```tsx
+import { css, states, variant } from '@codecademy/gamut-styles';
+import styled from '@emotion/styled';
+
+// Single value
+const Box = styled.div(css({ p: 4 }));
+
+// Mutiple values
+const OtherCoolThing = styled.div(css({ color: 'primary', p: 4 }));
+
+// Need some variants?
+const Anchor = styled.a(
+ variant({
+ base: { p: 4 },
+ defaultVariant: 'interface',
+ variants: {
+ interface: {
+ color: 'text',
+ '&:hover': {
+ color: 'text-accent',
+ },
+ },
+ inline: {
+ color: 'primary',
+ '&:hover': {
+ color: 'secondary',
+ },
+ },
+ },
+ })
+);
+
+// Need some boolean states?
+const UtilityBox = styled.div(
+ states({
+ base: { mx: 4, my: 8, p: 16 },
+ disabled: {
+ bg: 'background-disabled',
+ color: 'text-disabled',
+ },
+ center: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ })
+);
+
+;
+```
+
+
+
+```tsx
+import { states } from '@codecademy/gamut-styles';
+import { StyleProps } from '@codecademy/variance';
+import styled from '@emotion/styled';
+import React from 'react';
+
+const someWrapperStates = states({
+ absolute: { position: 'absolute', left: 'calc(50% - 85px)' },
+ danger: { color: 'text', bg: 'danger' },
+});
+
+const SomeWrapper = styled.div(someWrapperStates);
+
+export interface CoolNumberComponentProps
+ extends StyleProps {
+ coolNumber: number;
+ anotherCoolNumber: number;
+}
+
+export const CoolNumberComponent: React.FC = ({
+ coolNumber,
+ anotherCoolNumber,
+ ...rest //where your state props are!
+}) => ;
+```
+
+# System props
+
+System props are a core part of our new approach to dynamic and customized styling. Where writing custom styles is painful, system props are here to make it painless.
+
+```tsx
+import { Box } from '@codecademy/gamut';
+
+const MyContainer = ({ children }) => (
+ {children}
+);
+
+const MyOtherContainer = ({ children }) => (
+
+ {children}
+
+);
+```
+
+**Intellisense + Typesafety** - Many system props are tied to specific design token scales. You can be sure that you are using the correct tokens between contexts. All props will autosuggest possible values for the scale that you are in.
+
+**Responsive Syntax** - [**Docs**](https://gamut.codecademy.com/storybook/?path=/docs/foundations-system-responsive-properties--page) All system props accept 2 responsive syntaxes for easily creating responsive layouts. System prop media queries are mobile first (Greater Than or Equal To).
+
+**The typings behind the scenes:**
+
+```tsx
+type MediaQueryMap = {
+ _?: T;
+ xs?: T;
+ sm?: T;
+ md?: T;
+ lg?: T;
+ xl?: T;
+};
+
+type MediaQueryArray = [
+ T?, // base
+ T?, // xs
+ T?, // sm
+ T?, // md
+ T?, // lg
+ T? // xl
+];
+
+type SystemProp = T | MediaQueryMap | MediaQueryArray;
+```
+
+**Usage:**
+
+```tsx
+import { Box } from '@codecademy/gamut';
+
+// Object Syntax
+
+
+// Array Syntax
+
+```
+
+
+
+## Real-world use cases
+
+**Mobile / Desktop specific content**
+
+```tsx
+import { Box } from '@codecademy/gamut';
+
+const App = () => (
+
+ Title
+ Desktop Only Content
+ Mobile Only Content
+
+);
+```
+
+**Adaptive Layouts** - 3 columns ⇒ 2 columns
+
+```tsx
+import { GridBox } from '@codecademy/gamut';
+
+const SomeCoolLayout = ({ children }) => (
+
+ {children}
+
+);
+```
+
+**Design Token Access** - Responsively accessing tokens by key.
+
+```tsx
+const CardLikeThing = ({ children }) => (
+
+ {children}
+
+);
+
+const Content = ({ children }) => (
+ {children}
+);
+```
+
+# ❌ Nested selectors
+
+Nested selectors can cause a huge amount of side effects unwittingly and make it very hard to maintain consistent behavior while making updates. We politely ask (and will shortly lint) that you refrain from using:
+
+- **Tag Selectors** - `*` `div` `p` `span`
+- **Component Selectors (From Gamut)** - EG: `Box`
+
+```tsx
+//❌ Don't do this❌
+const App = styled.main`
+ * {
+ box-sizing: content-box;
+ }
+`;
+
+//❌ Don't do this❌
+const App = styled.main`
+ display: flex;
+ ${Box} {
+ align-self: start;
+ }
+`;
+
+// ✅ Do this ✅
+const App = ({ children }) => (
+
+ {children}
+
+```
diff --git a/packages/styleguide/src/lib/Meta/Brand.mdx b/packages/styleguide/src/lib/Meta/Brand.mdx
new file mode 100644
index 0000000000..eb97255c77
--- /dev/null
+++ b/packages/styleguide/src/lib/Meta/Brand.mdx
@@ -0,0 +1,16 @@
+import { Meta } from '@storybook/blocks';
+
+import { AboutHeader } from '~styleguide/blocks';
+
+export const parameters = {
+ id: 'Brand',
+ title: 'Brand',
+ subtitle: `Codecademy internal and branded components`,
+ status: 'static',
+};
+
+
+
+
+
+The [Brand Library](https://brand-storybook.codecademy.com/) is a subset of assets, components, and themes intended for branded experiences and internal use. If you have any questions about Brand, feel free to reach out at #gamut-team on Slack.
diff --git a/packages/styleguide/src/lib/Meta/Contributing.mdx b/packages/styleguide/src/lib/Meta/Contributing.mdx
new file mode 100644
index 0000000000..6099e63ad0
--- /dev/null
+++ b/packages/styleguide/src/lib/Meta/Contributing.mdx
@@ -0,0 +1,92 @@
+import { Meta } from '@storybook/blocks';
+
+import { AboutHeader, Callout, LinkTo } from '~styleguide/blocks';
+
+export const parameters = {
+ id: 'Contributing',
+ title: 'Contributing',
+ subtitle: `Thanks so much for being interested in contributing to Gamut!
+We love working with Codecademy employees across all our teams.`,
+ status: 'static',
+};
+
+
+
+
+
+## Prework
+
+We track planned work for Gamut components in the [Gamut Board](https://skillsoftdev.atlassian.net/jira/software/projects/GM/boards/784) on JIRA.
+
+- If there's a ticket there you want to take on, send a Slack to #gamut-team or come to Gamut Office hours and lets talk about it!
+- If the work you'd like to do isn't captured in a JIRA ticket, talk to us and we can work with you to create that ticket.
+- If you would like to make a request for work to be done, please discuss with us on Slack or during Gamut Office Hours.
+- If you'd like to pitch a change to the design system, please attend Gamut Crit, come to Gamut Office Hours, or send a Slack message to #gamut-team.
+
+## Writing components
+
+### Component structure
+
+Create your component as an `index.tsx` file in a PascalCase-named folder within its package directory, such as `packages/gamut/src/ProgressBar/index.tsx`.
+Consider saving this recommended format as an editor snippet:
+
+```tsx
+import React from 'react';
+
+export type MyComponentProps = {
+ /* ... */
+};
+
+export const MyComponent: React.FC = (
+ {
+ /* ... */
+ }
+) => {
+ // ...
+};
+```
+
+#### Props documentation
+
+With the exception of widespread, self-documenting props such as `onClick`, please include a sentence cased description of the prop's intent.
+React props on the component will be picked up by Storybook and added to the component's documentation story.
+We prefer these be full sentences.
+
+```ts
+/**
+ * Number of lines to limit the message to.
+ */
+limit: number;
+```
+
+- If your comment purely restartes the name and type of variable, please either elaborate on it or remove the comment altogether.
+- Consider starting comments for booleans with _"Whether "_.
+
+### Unit tests
+
+Your component should have unit tests in a `__tests__/MyComponent-test.tsx` file within its directory.
+Use Enzyme's `mount` to test it.
+
+We generally try to unit test all component logic, with the exception of class names in components that contain other logic.
+
+### Stories
+
+All components must have Storybook stories showing their use. See Stories for documentation.
+
+## Pull requests
+
+Please fill out the pull request template, including links to the corresponding Abstract design and JIRA ticket.
+
+
+
+### Publishing updates
+
+If you know your PR has breaking changes in at least one downstream repository, such as the [codecademy-engineering/mono](https://github.com/codecademy-engineering/mono):
+
+1. Before merging it, create PRs in those downstream repositories using your PR's published alpha package versions
+2. Verify those PRs work as expected and get them signed off normally
+3. Merge your Gamut PR
+4. Wait until the new Gamut package is published, then update the downstream repository PRs to use it
+5. Merge and deploy those PRs as soon as possible
+
+If your PR contains breaking changes that might affect other users, please mention them in the `#frontend` Slack channel.
diff --git a/packages/styleguide/src/lib/Meta/FAQs.mdx b/packages/styleguide/src/lib/Meta/FAQs.mdx
new file mode 100644
index 0000000000..641e3c8f45
--- /dev/null
+++ b/packages/styleguide/src/lib/Meta/FAQs.mdx
@@ -0,0 +1,58 @@
+import { Meta } from '@storybook/blocks';
+
+import { AboutHeader } from '~styleguide/blocks';
+
+export const parameters = {
+ id: 'FAQs',
+ title: 'FAQs',
+ subtitle:
+ "Please let us know if there are questions you'd like answered here!",
+ status: 'static',
+};
+
+
+
+
+
+## How can I contribute?
+
+Thanks for your interest! 🙌
+
+We are prepared to accept contributions from Codecademy employees only at this time, but we are working on a process to accept contributions from the wider community. Watch this space!
+
+## To Gamut or not to Gamut?
+
+> When should we create a general component in Gamut instead of a specific one in another application?
+
+In general, we prefer Gamut components to be those that are commonly shared across multiple experiences in the monolith.
+If something can be easily built from the existing primitives _without_ adding logic, we generally wouldn't make a special component for it.
+
+Some examples of things we'd generally include in Gamut are:
+
+- Common visually identifiable atoms, such as buttons or form inputs
+- Atoms linked together with client logic, such as an Alert bar
+
+Some examples of things we generally wouldn't include are:
+
+- Customized atoms specially designed for a particular use case, such as promotional "cards"
+- Groups of components that could be recreated easily, such as a particular button and grid combination
+
+Consider referencing other design systems such as [Fluent](https://www.microsoft.com/design/fluent) and [Material Design](https://material.io/design) to see what they choose to turn into generic components.
+
+### Implementation strategy?
+
+> Should we implement components in separate repositories or in Gamut?
+
+As general rules of thumb:
+
+1. If a component is being written for the first time or used for a second time:
+
+ - If the designer thinks it might belong in Gamut, feel free to implement it in the separate repository
+ - Consider making its API simple and flexible _(e.g. passing props to it instead of hooking it up to Redux)_
+ - If the designer doesn't intend for it to be in the design system, never mind Gamut
+
+2. If a component is being used for a third time or more, please discuss moving it to Gamut
+
+## What's going on with accessibility?
+
+Codecademy is committed to becoming [WCAG 2.1 accessible](https://www.w3.org/WAI/standards-guidelines/wcag), and technical accessibility is a must-have in our design system.Components added here are expected to be fully AA compliant.
diff --git a/packages/styleguide/src/lib/Meta/Stories.mdx b/packages/styleguide/src/lib/Meta/Stories.mdx
new file mode 100644
index 0000000000..ac1afa5d82
--- /dev/null
+++ b/packages/styleguide/src/lib/Meta/Stories.mdx
@@ -0,0 +1,169 @@
+import { Meta } from '@storybook/blocks';
+
+import { AboutHeader } from '~styleguide/blocks';
+
+export const parameters = {
+ id: 'Stories',
+ title: 'Meta/Stories',
+ subtitle: 'Guidelines and tooling for writing Storybook stories and docs.',
+ status: 'static',
+};
+
+
+
+
+
+## Quick start
+
+We've provided a few helpful vscode snippets to help you get through boilerplate. To use these start to type these strings in your editor and pick the template and fill out the tab targets.
+
+- `component-story`: The default TSX story template.
+- `component-doc`: The default component documentation template - each component should have a `.tsx` and `.mdx` file.
+- `toc-story`: A simple template for a Table of Contents category page.
+
+## File structure and naming
+
+When you make a new story theres a few things to keep in mind:
+
+- The folder structure is indicative of our flavor of atomic design.
+- The folder struture is identical to the storybook hierarchy generated.
+
+First find the right folder for your story in `packages/styleguide/stories` (e.g. `Atoms` | `Molecules` | `Organisms`).
+Once you've found it create a new folder with two new files `#{COMPONENT_NAME}.stories.tsx` and `#{COMPONENT_NAME}.mdx`. You can also store examples or other associated utility files in this folder.
+
+In your new files you can use the above snippets to set up your component add:
+
+```tsx
+// For ComponentName.stories.tsx
+
+import { ComponentName } from '@codecademy/gamut';
+import type { Meta, StoryObj } from '@storybook/react';
+
+const meta: Meta = {
+ component: ComponentName,
+ args: {
+ variant: 'default',
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ children:
,
+ },
+};
+
+export const Secondary: Story = {
+ args: {
+ children: 'Pro Content',
+ variant: 'secondary',
+ },
+};
+```
+
+```tsx
+// For ComponentName.mdx, more details in the component-doc code snippet
+
+import { Canvas, Controls, Meta } from '@storybook/blocks';
+
+import { ComponentHeader } from '~styleguide/blocks';
+
+import * as ComponentStories from './ComponentName.stories';
+
+export const parameters = {
+ subtitle: `Template component`,
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/file/XXX',
+ },
+ status: 'current',
+ source: {
+ repo: 'gamut',
+ // this is easy to find by right clicking on the file in VSCode and clicking "Copy Remote File Url From..." and the selecting 'main' or amending the url path below like so: https://github.com/Codecademy/gamut/blob/main/packages/${package}/src/file/location
+ githubLink:
+ 'https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/ComponentName',
+ },
+};
+
+
+
+
+
+## Usage
+
+Etc...
+```
+
+## Story structure
+
+In our opinion, a good component story page consists of:
+
+1. **General Information:** Each component should define some key information on the `` component
+2. **Flagship Story + Props:** A single default story showing the default state of the component with a connected props table right below it.
+3. **Variation Stories:** Granular subsections that show the discrete varaitions of the component and describe their use cases
+4. **Usage instructions and Guidelines:** A section that describes how to use the component should and shouldn't be used, and any guidelines that should be followed.
+
+### General information
+
+1. `subtitle`: What the component does, and what the component would typically be used for.
+2. `source`: The source package of the component (e.g. `gamut` | `gamut-styles`) and a link to the corresponding code.
+3. `status`: The health of the components API (e.g. `current` | `updating` | `deprecated` | `static`)
+4. `design`: A link to the Figma file that is associated with the component.
+
+```tsx
+import { Meta } from '@storybook/blocks';
+
+import { ComponentHeader } from '~styleguide/blocks';
+
+import * as AnchorStories from './Anchor.stories';
+
+export const parameters = {
+ subtitle: `A clickable text element that navigates to another page, resource, or location on the same page.`,
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/file/ReGfRNillGABAj5SlITalN/%F0%9F%93%90-Gamut?node-id=993-0',
+ },
+ status: 'current',
+ source: {
+ repo: 'gamut',
+ githubLink:
+ 'https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/Anchor',
+ },
+};
+
+
+
+
+
+```
+
+### Flagship story
+
+The Flagship story for a component should be intended to give the reader a broad overview of its high-level functionality. Its `Canvas` should automatically display the story's code by setting the prop sourceState="shown".
+
+Try to include the major behaviors for the component that most readers would need to understand its uses.
+
+```tsx
+## Playground
+
+//If your flagship story is named Default, you don't need to specify it for the Playground
+
+
+
+```
+
+### Granular stories
+
+Each subsequent story should elaborate on an important behavioral feature of the component.
+Try to show a single use of the behavior configurable with args.
+
+```tsx
+## Variant Anchors
+
+A short description should go here, as well as any variant specific usage guidelines.
+
+
+
+```
diff --git a/packages/styleguide/src/lib/Typography/About.mdx b/packages/styleguide/src/lib/Typography/About.mdx
new file mode 100644
index 0000000000..a098bc0d1b
--- /dev/null
+++ b/packages/styleguide/src/lib/Typography/About.mdx
@@ -0,0 +1,44 @@
+import { Meta } from '@storybook/blocks';
+
+import { AboutHeader, TableOfContents } from '~styleguide/blocks';
+
+export const parameters = {
+ id: 'Typography/About',
+ title: 'Typography',
+ subtitle:
+ 'These are basic primitives for displaying text components in configurable ways.',
+};
+
+
+
+
+
+Foundations make up the smallest scale design values that comprise a design system.
+Sometimes referred to elsewhere as "tokens", they are the abstract units that comprise and stitch together our atoms, molecules, and organisms.
+
+
diff --git a/packages/styleguide/src/lib/Typography/Anchor/Anchor.examples.tsx b/packages/styleguide/src/lib/Typography/Anchor/Anchor.examples.tsx
new file mode 100644
index 0000000000..154cae723d
--- /dev/null
+++ b/packages/styleguide/src/lib/Typography/Anchor/Anchor.examples.tsx
@@ -0,0 +1,116 @@
+import {
+ Anchor,
+ AnchorProps,
+ Box,
+ Column,
+ FlexBox,
+ LayoutGrid,
+ Text,
+} from '@codecademy/gamut';
+import {
+ MiniArrowRightIcon,
+ MiniInfoOutlineIcon,
+ MiniStarIcon,
+} from '@codecademy/gamut-icons';
+import { Background } from '@codecademy/gamut-styles';
+import startCase from 'lodash/startCase';
+
+const variants = ['inline', 'interface', 'standard'] as const;
+
+export const VariantsExample = ({ useIcon }: { useIcon: boolean }) => {
+ return (
+
+
+
+ {variants.map((variant) => (
+
+
+ {startCase(variant)}
+
+
+ Click Me
+
+
+ ))}
+
+
+
+
+ {variants.map((variant) => (
+
+
+ {startCase(variant)}
+ {' '}
+
+ Click Me
+
+
+ ))}
+
+
+
+ );
+};
+
+export const InlineAnchorWithIconAndText: React.FC = (args) => {
+ return (
+
+ I started painting as a hobby when I was little. I didn't know I had
+ any talent. I believe talent is just a pursued interest.e{' '}
+
+ Anybody can do what I do.
+ {' '}
+ Just go back and put one little more happy tree in there. Everybody's
+ different.{' '}
+
+ Learn more
+
+
+ );
+};
+
+export const PolymorphicAnchors: React.FC = (args) => {
+ return (
+
+ null}>
+ I look like an Anchor, but I am a button.
+
+
+
+ I look like a link, and I am one!
+
+
+ );
+};
diff --git a/packages/styleguide/src/lib/Typography/Anchor/Anchor.mdx b/packages/styleguide/src/lib/Typography/Anchor/Anchor.mdx
new file mode 100644
index 0000000000..1a809a2330
--- /dev/null
+++ b/packages/styleguide/src/lib/Typography/Anchor/Anchor.mdx
@@ -0,0 +1,110 @@
+import { Canvas, Controls, Meta } from '@storybook/blocks';
+
+import {
+ Callout,
+ ComponentHeader,
+ ImageWrapper,
+ LinkTo,
+} from '~styleguide/blocks';
+
+import * as AnchorStories from './Anchor.stories';
+
+export const parameters = {
+ subtitle: `A clickable text element that navigates to another page, resource, or location on the same page.`,
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/file/ReGfRNillGABAj5SlITalN/%F0%9F%93%90-Gamut?node-id=993-0',
+ },
+ status: 'current',
+ source: {
+ repo: 'gamut',
+ githubLink:
+ 'https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/Anchor',
+ },
+};
+
+
+
+
+
+## Usage
+
+Use an anchor to navigate to another page, resource, or location on the same page.
+
+### Best practices:
+
+- Include a leading or trailing icon to clarify the link’s destination or to further distinguish from surrounding text.
+- Consider opening in a new tab when navigating away would interrupt a task or workflow the user is currently engaged in.
+
+### When NOT to use:
+
+- **Actions** - when performing an actions, use a Button component instead.
+
+## Anatomy
+
+
+
+**1. Leading Icon** _(optional)_
+
+- Use to clarify or reinforce the link’s destination
+
+**2. Anchor link label**
+
+- Specify where the link goes
+- Use casing from writing guidelines
+- Aim for 3-5 words
+
+**3. Trailing icon** _(optional)_
+
+- Use to reinforce forward movement or navigation to a new page
+- When navigation to an external page, use the MiniOpenIcon.
+
+## Variants
+
+### Inline (default)
+
+Use in paragraphs, styled with color and underline to improve link visibility within text-heavy content.
+
+### Interface
+
+Use in menus or in instances where the context of the link makes it clear that it is clickable.
+
+### Standard
+
+Use outside of a paragraph or ‘menu’ instance.
+
+
+
+
+
+## Icons
+
+Anchors can be rendered with leading and trailing icons to provide additional context or visual distinction.
+
+
+
+Icons are also responsive to ColorMode.
+
+
+
+## Polymorphic Anchors
+
+Our Anchors are polymorphic - they can be rendered as a button or a link component. This allows for better accessibility and flexibility as this happens automatically based on the props passed to the Anchor. Please use this sparingly and when appropriate (for example, a `button` that navigates to a new page).
+
+
+
+## Playground
+
+
+
+
+
+## UX writing
+
+Writing words for a link or button? Above all else, make sure that the words alone make it clear where a button or link will take the user. Refer to the checklist below for guidance. For more tips and best practices, check out the full guide about writing for buttons and links.
+
+- Make sure it’s clear where the link or button will take the user.
+- Use sentence case, capitalizing only proper nouns.
diff --git a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx
new file mode 100644
index 0000000000..d9b2703ac0
--- /dev/null
+++ b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx
@@ -0,0 +1,87 @@
+import { Anchor, GridBox, Text } from '@codecademy/gamut';
+import {
+ MiniArrowRightIcon,
+ MiniInfoOutlineIcon,
+} from '@codecademy/gamut-icons';
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { PolymorphicAnchors, VariantsExample } from './Anchor.examples';
+
+const meta: Meta = {
+ component: Anchor,
+ args: {
+ children: 'Click me',
+ href: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
+ icon: MiniInfoOutlineIcon,
+ iconPosition: 'left',
+ target: '_blank',
+ variant: 'inline',
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {},
+};
+
+export const IconAnchor: Story = {
+ render: (args) => (
+
+
+ Left-aligned icon anchor
+
+
+ Right-aligned icon anchor
+
+
+ ),
+};
+
+export const IconAnchorExample: Story = {
+ render: (args) => (
+
+ I started painting as a hobby when I was little. I didn't know I had
+ any talent. I believe talent is just a pursued interest.e{' '}
+
+ Anybody can do what I do.
+ {' '}
+ Just go back and put one little more happy tree in there. Everybody's
+ different.{' '}
+
+ Learn more
+
+
+ ),
+};
+
+export const Modes: Story = {
+ render: () => ,
+};
+
+export const IconModes: Story = {
+ render: () => ,
+};
+
+export const PolymorphicAnchor: Story = {
+ render: () => ,
+};
diff --git a/packages/styleguide/src/lib/Typography/HiddenText/HiddenText.mdx b/packages/styleguide/src/lib/Typography/HiddenText/HiddenText.mdx
new file mode 100644
index 0000000000..7869a2dd61
--- /dev/null
+++ b/packages/styleguide/src/lib/Typography/HiddenText/HiddenText.mdx
@@ -0,0 +1,36 @@
+import { Canvas, Controls, Meta } from '@storybook/blocks';
+
+import { Callout, ComponentHeader, LinkTo } from '~styleguide/blocks';
+
+import * as HiddenTextStories from './HiddenText.stories';
+
+export const parameters = {
+ subtitle: `Visually hidden text that should still be narrated by screenreaders.`,
+ status: 'deprecated',
+ source: {
+ repo: 'gamut',
+ githubLink:
+ 'https://github.com/Codecademy/gamut/blob/cass-gm-843/packages/gamut/src/HiddenText/index.tsx#',
+ },
+};
+
+
+
+
+
+Previously, this was useful for cases where we visually indicate something not easily conveyed through semantic HTML.
+Ideally those cases should be exceedingly rare; unfortunately, some of our older pages aren't set up well for this.
+
+
+ For newer pages, use the{' '}
+ Text component and set{' '}
+ screenreader="true"
.
+ >
+ }
+/>
+
+
+
+
diff --git a/packages/styleguide/src/lib/Typography/HiddenText/HiddenText.stories.tsx b/packages/styleguide/src/lib/Typography/HiddenText/HiddenText.stories.tsx
new file mode 100644
index 0000000000..f8a45a4cab
--- /dev/null
+++ b/packages/styleguide/src/lib/Typography/HiddenText/HiddenText.stories.tsx
@@ -0,0 +1,14 @@
+import { HiddenText } from '@codecademy/gamut';
+import type { Meta, StoryObj } from '@storybook/react';
+
+const meta: Meta = {
+ component: HiddenText,
+ args: { children: 'Surprise!' },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {},
+};
diff --git a/packages/styleguide/src/lib/Typography/Text/Text.mdx b/packages/styleguide/src/lib/Typography/Text/Text.mdx
new file mode 100644
index 0000000000..7a89db7a47
--- /dev/null
+++ b/packages/styleguide/src/lib/Typography/Text/Text.mdx
@@ -0,0 +1,111 @@
+import { Canvas, Controls, Meta } from '@storybook/blocks';
+
+import { ComponentHeader, LinkTo } from '~styleguide/blocks';
+
+import * as TextStories from './Text.stories';
+
+export const parameters = {
+ subtitle:
+ 'This component is a specific primitive for handling UI Text in predictable and flexible ways.',
+ design: {
+ type: 'figma',
+ url: 'https://www.figma.com/file/rNsdbOwlw6L0ea3uAJrrz7',
+ },
+ status: 'current',
+ source: {
+ repo: 'gamut',
+ // this is easy to find by right clicking on the file in VSCode and clicking "Copy Remote File Url From..." and the selecting 'main' or amending the url path below like so: https://github.com/Codecademy/gamut/blob/main/packages/${package}/src/file/location
+ githubLink:
+ 'https://github.com/Codecademy/gamut/blob/main/packages/gamut/src/Typography/Text',
+ },
+};
+
+
+
+
+
+## Usage
+
+This is the preferred component for customizing typography. The API is progressively specific. In order to achieve the effect you are looking for there are 3 levels of precedence.
+
+1. `as` Any HTML tag that might have semantic meaning and imply specific style `h1` - `h6` and `strong`. These have default styles that will match up with the tag in normative circumstances. For example an `h1` will be the largest type style etc.
+2. `variant` In many cases we use heading tags in different ways than a text document might to maintain semantic and accessible HTML structure. In cases where this is required, you may specify a variant to overwrite the default tag styles. For example if you had an `h1` that needed to look like an `h4` you can specify `` to achieve the effect.
+3. `props` In all other cases where we might need to change typography related styles you can use system props to change behavior.
+
+### Best practices:
+
+- Use for any HTML text elements
+
+### When NOT to use:
+
+- **List items** - for items in a list, use the List + ListRow component.
+- **Anchors + Links** - for links, use the .
+
+## HTML Element variants
+
+When you use a specific element `Text` will style it with overridable defaults as our best guess behavior. These styles take lowest priority as they are merely meant to act as a useful default, both `variant` and any system prop will override the styles specified here.
+
+### Usage
+
+Below you can see how the Text component can display text in different sizes and as different HTML elements:
+
+```tsx
+import { Text } from '@codecademy/gamut';
+
+// Regular h1
+
+
+// An extra large h4
+
+
+// An extra small subheading
+
+```
+
+Here is how text would look like if only using the as prop and their specified values:
+
+
+
+## Style variants
+
+These are our base semantic font scales. These apply directly to the typography scales in figma and can be used with any arbitrary tag. These take precedence over any element based variants if configured. If none of these specifically match your need you can also override behavior with any system prop (such as `lineHeight` and `fontSize`).
+
+### Usage
+
+```tsx
+import { Text } from '@codecademy/gamut';
+
+;
+```
+
+
+
+## Utilities
+
+Text has some special props with common use cases to make your life easier.
+
+### Truncation
+
+
+
+### Font smoothing (default: false)
+
+
+
+### Screenreader (default: false)
+
+
+
+### Highlight
+
+
+
+## Playground
+
+
+
+
+
+## Accessibility considerations
+
+- Make sure to use the right semantic HTML element for the content you are displaying and respecting header order. If you're not sure, you can check out HTML elements at MDN [here](https://developer.mozilla.org/en-US/docs/Web/HTML/Element#content_sectioning).
diff --git a/packages/styleguide/src/lib/Typography/Text/Text.stories.tsx b/packages/styleguide/src/lib/Typography/Text/Text.stories.tsx
new file mode 100644
index 0000000000..c314cbc732
--- /dev/null
+++ b/packages/styleguide/src/lib/Typography/Text/Text.stories.tsx
@@ -0,0 +1,160 @@
+import { Column, LayoutGrid, Text } from '@codecademy/gamut';
+// eslint-disable-next-line gamut/import-paths
+import {
+ typographyElementVariants,
+ typographyStyleVariants,
+ typographyUtilities,
+} from '@codecademy/gamut/src/Typography/variants';
+import type { Meta, StoryObj } from '@storybook/react';
+import { Fragment } from 'react';
+
+const meta: Meta = {
+ component: Text,
+ args: {
+ children: 'Welcome to Gamut!',
+ },
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {},
+};
+
+const layoutGridStyles = { gap: 32, ml: 4 } as const;
+
+export const Elements: Story = {
+ render: () => (
+
+ {Object.keys(typographyElementVariants).map((tag) => (
+
+
+
+ {tag}
+
+
+
+ Lorem Ipsum Dolor
+
+
+ ))}
+
+ ),
+};
+
+export const Variants: Story = {
+ render: () => (
+
+ {Object.keys(typographyStyleVariants).map((variant) => (
+
+
+
+ {typographyStyleVariants[variant].fontSize}
+
+
+
+
+ {variant}
+
+
+
+ ))}
+
+ ),
+};
+
+export const Truncation: Story = {
+ render: () => (
+
+ {typographyUtilities.truncation.map((truncateType) =>
+ typographyUtilities.truncateLines.map((lines) => (
+
+
+
+ truncate="{truncateType}"
+
+ truncateLines={lines}
+
+
+
+
+ This is a very long text thingy that we want to truncate it's
+ very long indeed. This is a very long text thingy that we want
+ to truncate it's very long indeed. This is a very long text
+ thingy that we want to truncate it's very long indeed. This is a
+ very long text thingy that we want to truncate it's very long
+ indeed.
+
+
+
+ ))
+ )}
+
+ ),
+};
+
+export const FontSmoothing: Story = {
+ render: () => (
+
+ {typographyUtilities.smoothing.map((variant) => (
+
+
+
+ smooth="{variant.toString()}"
+
+
+
+
+ Am I smooth?
+
+
+
+ ))}
+
+ ),
+};
+
+export const Screenreader: Story = {
+ render: () => (
+
+ {typographyUtilities.screenreader.map((variant) => (
+
+
+
+ screenreader="{variant.toString()}"
+
+
+
+
+ {variant
+ ? 'Visible only to screenreaders'
+ : 'When set to "false", this text is visible to non-screenreaders.'}
+
+
+
+ ))}
+
+ ),
+};
+
+export const Highlight: Story = {
+ render: () => (
+
+
+
+ {`highlight="true"`}
+
+
+
+
+ A{' '}
+
+ highlighted
+ {' '}
+ example
+
+
+
+ ),
+};
diff --git a/packages/styleguide/src/lib/Typography/Text/tables.tsx b/packages/styleguide/src/lib/Typography/Text/tables.tsx
new file mode 100644
index 0000000000..b4b266a1cc
--- /dev/null
+++ b/packages/styleguide/src/lib/Typography/Text/tables.tsx
@@ -0,0 +1,21 @@
+import { Column, LayoutGrid, Text } from '@codecademy/gamut';
+// eslint-disable-next-line gamut/import-paths
+import { typographyElementVariants } from '@codecademy/gamut/src/Typography/variants';
+import { Fragment } from 'react';
+
+export const Elements: React.FC = () => (
+
+ {Object.keys(typographyElementVariants).map((tag) => (
+
+
+
+ {tag}
+
+
+
+ Lorem Ipsum Dolor
+
+
+ ))}
+
+);
diff --git a/packages/styleguide/src/static/typography/anchor.png b/packages/styleguide/src/static/typography/anchor.png
new file mode 100644
index 0000000000000000000000000000000000000000..211470f705dcdb0c997696f71f6939bbc958e2c4
GIT binary patch
literal 8360
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