diff --git a/apps/admin-x-settings/.storybook/adminx-theme.tsx b/apps/admin-x-settings/.storybook/adminx-theme.tsx new file mode 100644 index 0000000000..8a64dd18c8 --- /dev/null +++ b/apps/admin-x-settings/.storybook/adminx-theme.tsx @@ -0,0 +1,38 @@ +import {create} from '@storybook/theming/create'; + +export default create({ + base: 'light', + // Typography + fontBase: '"Inter", sans-serif', + fontCode: 'monospace', + + brandTitle: 'AdminX Design System', + brandUrl: 'https://ghost.org', + brandImage: 'https://github.com/peterzimon/playground/assets/353959/c4358b4e-232f-4dba-8abb-adb3142ccd89', + brandTarget: '_self', + + // + colorPrimary: '#30CF43', + colorSecondary: '#15171A', + + // UI + appBg: '#ffffff', + appContentBg: '#ffffff', + appBorderColor: '#EBEEF0', + appBorderRadius: 0, + + // Text colors + textColor: '#15171A', + textInverseColor: '#ffffff', + + // Toolbar default and active colors + barTextColor: '#9E9E9E', + barSelectedColor: '#15171A', + barBg: '#ffffff', + + // Form colors + inputBg: '#ffffff', + inputBorder: '#15171A', + inputTextColor: '#15171A', + inputBorderRadius: 2, +}); \ No newline at end of file diff --git a/apps/admin-x-settings/.storybook/manager.tsx b/apps/admin-x-settings/.storybook/manager.tsx new file mode 100644 index 0000000000..8e66cc97e3 --- /dev/null +++ b/apps/admin-x-settings/.storybook/manager.tsx @@ -0,0 +1,6 @@ +import {addons} from '@storybook/manager-api'; +import adminxTheme from './adminx-theme'; + +addons.setConfig({ + theme: adminxTheme +}); \ No newline at end of file diff --git a/apps/admin-x-settings/.storybook/preview.tsx b/apps/admin-x-settings/.storybook/preview.tsx index e24b544c09..268a8befcd 100644 --- a/apps/admin-x-settings/.storybook/preview.tsx +++ b/apps/admin-x-settings/.storybook/preview.tsx @@ -4,6 +4,10 @@ import '../src/styles/demo.css'; import type { Preview } from "@storybook/react"; import '../src/admin-x-ds/providers/DesignSystemProvider'; import DesignSystemProvider from '../src/admin-x-ds/providers/DesignSystemProvider'; +import adminxTheme from './adminx-theme'; +import { themes } from '@storybook/theming'; + +import '../src/admin-x-ds/assets/styles/storybook.css'; const preview: Preview = { parameters: { @@ -17,9 +21,12 @@ const preview: Preview = { options: { storySort: { mathod: 'alphabetical', - order: ['Global', ['Chrome', 'Form', 'Modal', 'Layout', 'List', '*'], 'Settings', ['Setting Section', 'Setting Group', '*'], 'Experimental'], + order: ['Welcome', 'Foundations', ['Style Guide', 'Colors', 'Icons', 'ErrorHandling'], 'Global', ['Form', 'Chrome', 'Modal', 'Layout', 'List', 'Table', '*'], 'Settings', ['Setting Section', 'Setting Group', '*'], 'Experimental'], }, }, + docs: { + theme: adminxTheme, + }, }, decorators: [ (Story, context) => { diff --git a/apps/admin-x-settings/src/admin-x-ds/assets/styles/storybook.css b/apps/admin-x-settings/src/admin-x-ds/assets/styles/storybook.css new file mode 100644 index 0000000000..aecd958520 --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/assets/styles/storybook.css @@ -0,0 +1,214 @@ +.sbdocs-wrapper { + padding: 3vmin !important; +} + +.sbdocs-wrapper .sbdocs-content { + max-width: 1320px; +} + +.sb-doc { + max-width: 740px; + width: 100%; + margin: 0 auto !important; +} + +.sb-doc, +.sb-doc a, +.sb-doc h1, +.sb-doc h2, +.sb-doc h3, +.sb-doc h4, +.sb-doc h5, +.sb-doc h6, +.sb-doc p, +.sb-doc ul li, +.sbdocs-title, +.sb-doc ol li { + font-family: Inter, sans-serif !important; + padding: 0 !important; +} + +.sb-doc a { + color: #30CF43; +} + +.sb-doc h1 { + font-size: 48px !important; + letter-spacing: -0.04em !important; + margin-bottom: 20px; +} + +.sb-doc h2 { + margin-top: 40px !important; + font-size: 27px; + border: none; + margin-bottom: 2px; +} + +.sb-doc h3 { + margin-top: 40px !important; + margin-bottom: 4px !important; + font-size: 20px; +} + +.sb-doc h4 { + margin: 0 0 4px !important; +} + +.sb-doc p, +.sb-doc div, +.sb-doc ul li, +.sb-doc ol li { + font-size: 15px; + line-height: 1.5em; +} + +.sb-doc ul li, +.sb-doc ol li { + margin-bottom: 8px; +} + +.sb-doc h2 + p, +.sb-doc h3 + p { + margin-top: 8px; +} + +.sb-doc img, +.sb-wide img { + margin-top: 40px !important; + margin-bottom: 40px !important; +} + +.sb-doc img.small { + max-width: 520px; + margin: 0 auto; + display: block; +} + +.sb-doc p.excerpt { + font-size: 19px; + letter-spacing: -0.02em; +} + +.sb-doc .highlight { + padding: 12px 20px; + border-radius: 4px; + background: #EBEEF0; +} + +.sb-doc .highlight.purple { + background: #F0E9FA; +} + +.sb-doc .highlight.purple a { + color: #8E42FF; +} + +/* Welcome */ +.sb-doc img.main-image { + margin-top: -2vmin !important; + margin-left: -44px; + margin-right: -32px; + margin-bottom: 0 !important; + max-width: unset; + width: calc(100% + 64px); +} + +.sb-doc .main-structure-container { + display: flex; + gap: 32px; + margin: 32px 0 80px; +} + +.sb-doc .main-structure-container div { + flex-basis: 33%; +} + +.sb-doc .main-structure-container div p { + display: flex; + flex-direction: column; + gap: 4px; +} + +.sb-doc .main-structure-container img { + margin: 12px 0 !important; + width: 32px; + height: 32px; +} + +.sb-doc .main-structure-container div h4 { + border-bottom: 1px solid #EBEEF0; + padding-bottom: 8px !important; + margin-bottom: 8px !important; +} + +.sb-doc .main-structure-container div p { + margin: 0; + font-size: 13.5px; +} + +/* Colors */ +.color-grid { + display: flex; + gap: 20px; + flex-wrap: wrap; + margin-top: 20px; +} + +.color-grid div { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + padding: 12px; + border-radius: 4px; + border: 1px solid #EBEEF0; +} + +.color-grid .swatch { + display: block; + background: #EFEFEF; + border-radius: 100%; + width: 28px; + height: 28px; +} + +.swatch.green { + background: #30CF43; +} + +.swatch.black { + background: #15171A; +} + +.swatch.white { + background: #FFFFFF; + border: 1px solid #EBEEF0; +} + +.swatch.lime { + background: #B5FF18; +} +.swatch.blue { + background: #14B8FF; +} +.swatch.purple { + background: #8E42FF; +} +.swatch.pink { + background: #FB2D8D; +} +.swatch.yellow { + background: #FFB41F; +} +.swatch.red { + background: #F50B23; +} + +/* Icons */ + +.sb-doc .streamline { + display: grid; + grid-template-columns: auto 240px; + gap: 32px; +} \ No newline at end of file diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/About.mdx b/apps/admin-x-settings/src/admin-x-ds/docs/About.mdx deleted file mode 100644 index be3c0a43e4..0000000000 --- a/apps/admin-x-settings/src/admin-x-ds/docs/About.mdx +++ /dev/null @@ -1,41 +0,0 @@ -import { Meta } from '@storybook/blocks'; - - - - - -
- -# AdminX Design System - -This is a documentation of the design system of Ghost AdminX. - -## Why? - -The purpose of any design system is to bring order to chaos and this is not any diffrent here either. Historically we maintained consistency in the Ghost Admin via using components and global CSS as much as possible. However due to the growth of the product and the loose system, more and more exotic patterns and styles emerged—which resulted in inconsistency. - -The main goal of the design system (any design system) is to bring order into chaos by defining and documenting **reusable components**. - -## Install - -ATM the design system is part of the AdminX Settings project but soon it will be decoupled with the intention to be able to (re)use it in any future React based Admin projects. Eventually it should be an independent package that could be added to any React app. - -`yarn add @tryghost/admin-x-ds` - -
\ No newline at end of file diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/Colors.mdx b/apps/admin-x-settings/src/admin-x-ds/docs/Colors.mdx new file mode 100644 index 0000000000..7a2e68224c --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/docs/Colors.mdx @@ -0,0 +1,56 @@ +import { Meta, ColorPalette, ColorItem } from '@storybook/blocks'; + + + + +
+# Colors + +

You'll find all the official Ghost colors and more in Tailwind, but here's a list of them in case you want to use them elsewhere.

+ + + + + + + + + +
\ No newline at end of file diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/Develop.mdx b/apps/admin-x-settings/src/admin-x-ds/docs/Develop.mdx deleted file mode 100644 index 018c239ddb..0000000000 --- a/apps/admin-x-settings/src/admin-x-ds/docs/Develop.mdx +++ /dev/null @@ -1,73 +0,0 @@ -import { Meta } from '@storybook/blocks'; -import SBStructure from './assets/ds-structure.png'; - - - - - -
- -# Development - -Here's a guideline of how new components should be developed to match the goal of the design system. - -
- -## Structure - -The design system contains **reusable components**. These components live in one of the following groups: - -### Global -Contains common components that are used across all parts (in all apps) of the admin: buttons, checkboxes, lists, input fields etc—the usual suspects. You can check them in the "Global" group in the sidebar. - -### App specific -The Admin is broken down to multiple React apps, each with its own set custom of reusable components. **These components are also part of the design system** which allows potential reusability in the future, and forces designers and developers to think in terms of the design system. - -### What about non-reusable components? - -With all fairness, **most of the components should be part of the design system**. Of course there pages, containers etc. in each app which are obviously **non-reusable**, however these should be built up of _mostly_ reusable components. - -

If you can't decide whether a component is reusable or not, then default to adding it to the design system!

- -
- -

- -### Example: settings app - -[TBD: Settings structure] - -
- -## How to develop new components? - -If there's a single thing you should remember is this: - -

Storybook is **the central tool** of the design system, it is **not** an afterthought. It is the **starting point** of the development of any new component.

- -### Steps to develop new components -[TBD: expand] - -1. Create the react component in the desgn system with a rudimentary interface -2. Create a new story (you can use `Boilerplate.stories.tsx` to get started) -3. Develop the details of the new react component -4. Create stories for all interesting use cases. There should be a story for the most common parameter combinations. -5. Test the new component in your app. If something is off, think about how you can solve it in the system—avoid visual hacking in the app. - -
\ No newline at end of file diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/ErrorHandling.mdx b/apps/admin-x-settings/src/admin-x-ds/docs/ErrorHandling.mdx index 25dafd2fab..93bcfbe6e2 100644 --- a/apps/admin-x-settings/src/admin-x-ds/docs/ErrorHandling.mdx +++ b/apps/admin-x-settings/src/admin-x-ds/docs/ErrorHandling.mdx @@ -3,68 +3,43 @@ import SBLocalError from './assets/local-error-example.png'; import SBPageError from './assets/page-error-example.png'; import SBGlobalError from './assets/global-error-example.png'; - - - +
-# Error handling in AdminX +# Error handling -The three most common errors in Ghost Admin should fall into one of the following categories: +

Consistent error handling throughout the whole product is a key to great user experience.

-1. **Inline errors** — errors related typically to input fields in forms -2. **Contextual errors** — errors which are related to a screen, page or a modal and the tasks the user is doing at that specific context. -3. **System errors** — global errors which are relevant no matter what the actual screen is or the user's actual task +Errors in Ghost Admin fall into one of three categories: -## Inline errors +1. **Field errors** — errors related to various [input] fields in forms +2. **Page errors** — errors which are related to a screen, page or a modal. +3. **System errors** — product level, global errors -Inline errors are typically related to form validation and appear most commonly close to a form element. An example of an inline error is when the user doesn't fill a mandatory input field and an error message appears near the field. +## Field errors -Example of a inline error: +Field errors are shown during frontend form validation, and appear close to the related form field. The most typical example of it is when the user doesn't fill a mandatory input field and an error message appears like this: - -

+ -Frontend form validation usually happens without an API roundtrip, ideally right after the user finishes editing a field (`onFocusOut`): - -1. User fills the form -2. Clicks on the next form field (focus is out of the current input field) -3. The system does form field validation and — in case of an error — shows the related inline field error - -All the form fields in AdminX have a built in capability to show inline errors via the `error` prop set to `true` and using the `hint` prop to set the error message. Example: [Textfield](/story/global-form-textfield--error) +This kind of error is usually used for inline frontend form validation, which mostly happens without an API roundtrip. The error is shown right after the user finishes editing the field and focuses out of it (`onBlur`). Ideally, all validation should be inline: that is, as soon as the user has finished filling in a field, an indicator should appear nearby if the field contains an error. This type of error message is easily noticeable; moreover, fixing the error immediately after the field has been completed requires the least interaction cost for users: they don’t need to locate it or navigate to the field, nor do they have to switch context from a new field to return to an old field they thought they had completed successfully. -Of course, there will be situations where inline validation won’t be possible and data entered by the user will need to be sent to a server for verification. ([ref](https://www.nngroup.com/articles/errors-forms-design-guidelines/)) +Of course, there will be situations where inline validation won’t be possible and data entered by the user will need to be sent to a server for verification. ([ref](https://www.nngroup.com/articles/errors-forms-design-guidelines/)). + +So the steps to show a field error are: + +1. User fills a field in the form +2. Clicks outside the field (`onBlur`) +3. The system does frontend field validation and — in case of an error — shows the related error + +All form elements (input fields, selects etc.) in AdminX have a built in capability to show form errors via the `error` prop set to `true` and using the `hint` prop to set the error message. (Example: [Textfield](/story/global-form-textfield--error)) ## Page errors -Page errors are related to the actual page, modal or the task but unlike inline errors, they always appear on the top of the page. An important property of page errors is that they _disappear_ if the user navigates away from the page. - -A common example of page errors is a summary of form validation errors or an API error or a summary of errors on submitting a form. +Page errors are related to the actual page, modal or the task but unlike inline errors, they always appear on the top of the page. An important property of page errors is that they _disappear_ if the user navigates away from the page. A common example of page errors is a summary of form validation errors or an API error or a summary of errors on submitting a form. A typical example when page errors would be used: @@ -77,7 +52,6 @@ A typical example when page errors would be used:
-

@@ -90,7 +64,6 @@ For example:
-


diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/Icons.mdx b/apps/admin-x-settings/src/admin-x-ds/docs/Icons.mdx new file mode 100644 index 0000000000..975ec84f2e --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/docs/Icons.mdx @@ -0,0 +1,45 @@ +import { Meta } from '@storybook/blocks'; +import StreamlineSettings from './assets/streamline-settings.png'; + + + +
+ +# Icons + +

We use the [Streamline icon library](https://www.streamlinehq.com/) in Ghost Admin. Here are some iconography best practices.

+ +### Overview +The icons are part of the AdminX design system so they can be reusable in any Ghost Admin app. Use the [Icon](/docs/global-icon--docs) component to display available icons in standard icon sizes. + +### Adding new icons + +There are some rules we have to follow in order to maintain consistent iconography: + +
+
+ - All icons must be SVG format. + - Icons must be exported using **strokes** as lines and **not** filled areas. The stroke width must be **1.5px**. This allows more flexibility but still maintains consistency (and less filesize). + - All icon should be exported in a 24x24 pixel container. + - All icons should use `currentColor` as their colors for strokes. This lets us color the icon easily in CSS. + - Icons must be exported with transparent background. + +

+ + #### Exporting using the Streamline app + + For the best result we recommend using the Streamline app to copy the SVG code of new icons with the following settings: + + - Format: SVG + - Size: 24px + - Stroke: 1.5px + - Responsive size: OFF + - Outline stroke: **OFF** + - Background: transparent + - Asset currentcolor: **ON** + - Background currentcolor: OFF +
+ +
+ +
\ No newline at end of file diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/Welcome.mdx b/apps/admin-x-settings/src/admin-x-ds/docs/Welcome.mdx new file mode 100644 index 0000000000..6d5c1180e4 --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/docs/Welcome.mdx @@ -0,0 +1,49 @@ +import { Meta } from '@storybook/blocks'; +import WelcomeImage from './assets/adminx-screenshot.png'; +import BlocksIcon from './assets/blocks.svg'; +import CircleMenu from './assets/circle-menu.svg'; +import AppsIcon from './assets/apps.svg'; + + + +
+ + + +# AdminX Design System + +

Here you can find our design guidelines, component documentation, and resources for building apps in Ghost Admin.

+ +
This is a work in progress. As of today, the Storybook system is part of AdminX Settings app but it's about to be a separated into its own package.
+ +### What's inside + +The AdminX Design System is a collection of React UI building blocks for designers and developers to create apps for Ghost Admin. Its main purpose is to provide a library of available components and maintain consistency across the whole product. + +
+
+ +

Foundations

+

Basic global design patterns like colors and icons

+ [Read more →](/docs/foundations-colors--docs) +
+
+ +

Global components

+

UI building blocks to be used across all apps in Ghost Admin

+ [Browse →](/docs/global-form-checkbox--docs) +
+
+ +

App specific

+

Reusable components of individual React apps in Ghost Admin

+ [Example →](/docs/settings-setting-section--docs) +
+
+ +The system uses Storybook — if you're new to it, we recommend reading about what it is and how to use it, on [storybook.js.org](https://storybook.js.org). + +

+ + +
\ No newline at end of file diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/assets/adminx-screenshot.png b/apps/admin-x-settings/src/admin-x-ds/docs/assets/adminx-screenshot.png new file mode 100644 index 0000000000..8ffbcbe43e Binary files /dev/null and b/apps/admin-x-settings/src/admin-x-ds/docs/assets/adminx-screenshot.png differ diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/assets/apps.svg b/apps/admin-x-settings/src/admin-x-ds/docs/assets/apps.svg new file mode 100644 index 0000000000..1c3a0db30d --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/docs/assets/apps.svg @@ -0,0 +1 @@ +app-window-multiple \ No newline at end of file diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/assets/blocks.svg b/apps/admin-x-settings/src/admin-x-ds/docs/assets/blocks.svg new file mode 100644 index 0000000000..cb422b8773 --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/docs/assets/blocks.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/assets/circle-menu.svg b/apps/admin-x-settings/src/admin-x-ds/docs/assets/circle-menu.svg new file mode 100644 index 0000000000..510dcb00f7 --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/docs/assets/circle-menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/assets/ds-structure.png b/apps/admin-x-settings/src/admin-x-ds/docs/assets/ds-structure.png index 6e3953c052..ae9616d461 100644 Binary files a/apps/admin-x-settings/src/admin-x-ds/docs/assets/ds-structure.png and b/apps/admin-x-settings/src/admin-x-ds/docs/assets/ds-structure.png differ diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/assets/streamline-settings.png b/apps/admin-x-settings/src/admin-x-ds/docs/assets/streamline-settings.png new file mode 100644 index 0000000000..84a9594e00 Binary files /dev/null and b/apps/admin-x-settings/src/admin-x-ds/docs/assets/streamline-settings.png differ diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/assets/style-guide-layout.png b/apps/admin-x-settings/src/admin-x-ds/docs/assets/style-guide-layout.png new file mode 100644 index 0000000000..0b78a129f1 Binary files /dev/null and b/apps/admin-x-settings/src/admin-x-ds/docs/assets/style-guide-layout.png differ diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/assets/style-guide.png b/apps/admin-x-settings/src/admin-x-ds/docs/assets/style-guide.png new file mode 100644 index 0000000000..07da58479a Binary files /dev/null and b/apps/admin-x-settings/src/admin-x-ds/docs/assets/style-guide.png differ diff --git a/apps/admin-x-settings/src/admin-x-ds/docs/assets/tower.svg b/apps/admin-x-settings/src/admin-x-ds/docs/assets/tower.svg new file mode 100644 index 0000000000..2d4eff633c --- /dev/null +++ b/apps/admin-x-settings/src/admin-x-ds/docs/assets/tower.svg @@ -0,0 +1 @@ + \ No newline at end of file