Extracted AdminX design system to a separate package (#18878)
refs https://github.com/TryGhost/Product/issues/4105 --- <!-- Leave the line below if you'd like GitHub Copilot to generate a summary from your commit --> <!-- copilot:summary --> ### <samp>🤖 Generated by Copilot at 2edba98</samp> This pull request introduces a new monorepo package called `admin-x-design`, which contains components, design guidelines and documentation for building apps in Ghost Admin. It also moves some existing components and files from the deprecated `admin-x-settings` package to the new `admin-x-design` package, and updates some styles and rules to use TailwindCSS. The purpose of these changes is to improve the consistency, maintainability and usability of the Ghost Admin UI.
16
.github/scripts/dev.js
vendored
@ -50,20 +50,26 @@ const COMMAND_TYPESCRIPT = {
|
||||
env: {}
|
||||
};
|
||||
|
||||
const COMMAND_ADMINX = {
|
||||
const COMMANDS_ADMINX = [{
|
||||
name: 'adminXDS',
|
||||
command: 'nx watch --projects=apps/admin-x-design -- nx run \\$NX_PROJECT_NAME:build --skip-nx-cache',
|
||||
cwd: path.resolve(__dirname, '../..'),
|
||||
prefixColor: '#C35831',
|
||||
env: {}
|
||||
}, {
|
||||
name: 'adminX',
|
||||
command: 'yarn dev',
|
||||
command: 'yarn nx build && yarn dev',
|
||||
cwd: path.resolve(__dirname, '../../apps/admin-x-settings'),
|
||||
prefixColor: '#C35831',
|
||||
env: {}
|
||||
};
|
||||
}];
|
||||
|
||||
if (DASH_DASH_ARGS.includes('ghost')) {
|
||||
commands = [COMMAND_GHOST, COMMAND_TYPESCRIPT];
|
||||
} else if (DASH_DASH_ARGS.includes('admin')) {
|
||||
commands = [COMMAND_ADMIN, COMMAND_ADMINX];
|
||||
commands = [COMMAND_ADMIN, ...COMMANDS_ADMINX];
|
||||
} else {
|
||||
commands = [COMMAND_GHOST, COMMAND_TYPESCRIPT, COMMAND_ADMIN, COMMAND_ADMINX];
|
||||
commands = [COMMAND_GHOST, COMMAND_TYPESCRIPT, COMMAND_ADMIN, ...COMMANDS_ADMINX];
|
||||
}
|
||||
|
||||
if (DASH_DASH_ARGS.includes('portal') || DASH_DASH_ARGS.includes('all')) {
|
||||
|
41
apps/admin-x-design/.eslintrc.cjs
Normal file
@ -0,0 +1,41 @@
|
||||
module.exports = {
|
||||
extends: [
|
||||
'plugin:ghost/ts',
|
||||
'plugin:react/recommended',
|
||||
'plugin:react-hooks/recommended'
|
||||
],
|
||||
plugins: [
|
||||
'ghost',
|
||||
'react-refresh',
|
||||
'tailwindcss'
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect'
|
||||
}
|
||||
},
|
||||
rules: {
|
||||
// suppress errors for missing 'import React' in JSX files, as we don't need it
|
||||
'react/react-in-jsx-scope': 'off',
|
||||
// ignore prop-types for now
|
||||
'react/prop-types': 'off',
|
||||
|
||||
'react/jsx-sort-props': ['error', {
|
||||
reservedFirst: true,
|
||||
callbacksLast: true,
|
||||
shorthandLast: true,
|
||||
locale: 'en'
|
||||
}],
|
||||
'react/button-has-type': 'error',
|
||||
'react/no-array-index-key': 'error',
|
||||
'react/jsx-key': 'off',
|
||||
|
||||
'tailwindcss/classnames-order': ['error', {config: 'tailwind.config.cjs'}],
|
||||
'tailwindcss/enforces-negative-arbitrary-values': ['warn', {config: 'tailwind.config.cjs'}],
|
||||
'tailwindcss/enforces-shorthand': ['warn', {config: 'tailwind.config.cjs'}],
|
||||
'tailwindcss/migration-from-tailwind-2': ['warn', {config: 'tailwind.config.cjs'}],
|
||||
'tailwindcss/no-arbitrary-value': 'off',
|
||||
'tailwindcss/no-custom-classname': 'off',
|
||||
'tailwindcss/no-contradicting-classname': ['error', {config: 'tailwind.config.cjs'}]
|
||||
}
|
||||
};
|
2
apps/admin-x-design/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
es
|
||||
types
|
@ -1,5 +1,5 @@
|
||||
import {resolve} from "path";
|
||||
import type { StorybookConfig } from "@storybook/react-vite";
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
|
||||
addons: [
|
||||
@ -17,14 +17,11 @@ const config: StorybookConfig = {
|
||||
docs: {
|
||||
autodocs: "tag",
|
||||
},
|
||||
// staticDirs: ['../public/fonts'],
|
||||
async viteFinal(config, options) {
|
||||
config.resolve.alias = {
|
||||
crypto: require.resolve('rollup-plugin-node-builtins'),
|
||||
// @TODO: Remove this when @tryghost/nql is updated
|
||||
mingo: resolve(__dirname, '../../../node_modules/mingo/dist/mingo.js')
|
||||
config.resolve!.alias = {
|
||||
crypto: require.resolve('rollup-plugin-node-builtins')
|
||||
}
|
||||
return config;
|
||||
},
|
||||
}
|
||||
};
|
||||
export default config;
|
@ -1,13 +1,11 @@
|
||||
import React from 'react';
|
||||
|
||||
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 '../styles.css';
|
||||
import './storybook.css';
|
||||
|
||||
import '../src/admin-x-ds/assets/styles/storybook.css';
|
||||
import type { Preview } from "@storybook/react";
|
||||
import DesignSystemProvider from '../src/providers/DesignSystemProvider';
|
||||
import adminxTheme from './adminx-theme';
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
@ -33,12 +31,12 @@ const preview: Preview = {
|
||||
let {scheme} = context.globals;
|
||||
|
||||
return (
|
||||
<div className={`admin-x-settings ${scheme === 'dark' ? 'dark' : ''}`} style={{
|
||||
<div className={`admin-x-design admin-x-base ${scheme === 'dark' ? 'dark' : ''}`} style={{
|
||||
padding: '24px',
|
||||
background: (scheme === 'dark' ? '#131416' : '')
|
||||
}}>
|
||||
{/* 👇 Decorators in Storybook also accept a function. Replace <Story/> with Story() to enable it */}
|
||||
<DesignSystemProvider>
|
||||
<DesignSystemProvider fetchKoenigLexical={async () => {}}>
|
||||
<Story />
|
||||
</DesignSystemProvider>
|
||||
</div>);
|
@ -1,3 +1,32 @@
|
||||
/*
|
||||
* We load Inter in Ember admin, so loading it explicitly here makes the final rendering
|
||||
* in Storybook match the final rendering when embedded in Ember
|
||||
*/
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
src: url("./Inter.ttf") format("truetype-variations");
|
||||
font-weight: 100 900;
|
||||
}
|
||||
|
||||
:root {
|
||||
font-size: 62.5%;
|
||||
line-height: 1.5;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
html, body, #root {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
letter-spacing: unset;
|
||||
}
|
||||
|
||||
.sbdocs-wrapper {
|
||||
padding: 3vmin !important;
|
||||
}
|
23
apps/admin-x-design/README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# Admin X Design
|
||||
|
||||
Components, design guidelines and documentation for building apps in Ghost Admin
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
## Develop
|
||||
|
||||
This is a monorepo package.
|
||||
|
||||
Follow the instructions for the top-level repo.
|
||||
1. `git clone` this repo & `cd` into it as usual
|
||||
2. Run `yarn` to install top-level dependencies.
|
||||
|
||||
|
||||
|
||||
## Test
|
||||
|
||||
- `yarn lint` run just eslint
|
||||
- `yarn test` run lint and tests
|
||||
|
75
apps/admin-x-design/package.json
Normal file
@ -0,0 +1,75 @@
|
||||
{
|
||||
"name": "@tryghost/admin-x-design",
|
||||
"type": "module",
|
||||
"version": "0.0.0",
|
||||
"repository": "https://github.com/TryGhost/Ghost/tree/main/packages/admin-x-design",
|
||||
"author": "Ghost Foundation",
|
||||
"private": true,
|
||||
"main": "es/index.js",
|
||||
"types": "types/index.d.ts",
|
||||
"sideEffects": false,
|
||||
"scripts": {
|
||||
"build": "vite build && tsc -p tsconfig.declaration.json",
|
||||
"prepare": "yarn build",
|
||||
"test": "yarn test:types",
|
||||
"test:types": "tsc --noEmit",
|
||||
"lint:code": "eslint --ext .js,.ts,.cjs,.tsx src/ --cache",
|
||||
"lint": "yarn lint:code && yarn lint:test",
|
||||
"lint:test": "eslint -c test/.eslintrc.cjs --ext .js,.ts,.cjs,.tsx test/ --cache",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
"files": [
|
||||
"es",
|
||||
"types",
|
||||
"tailwind.cjs",
|
||||
"tailwind.config.cjs"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@codemirror/lang-html": "^6.4.5",
|
||||
"@storybook/addon-essentials": "7.4.0",
|
||||
"@storybook/addon-interactions": "7.4.0",
|
||||
"@storybook/addon-links": "7.4.0",
|
||||
"@storybook/addon-styling": "1.3.7",
|
||||
"@storybook/blocks": "7.4.0",
|
||||
"@storybook/react": "7.4.0",
|
||||
"@storybook/react-vite": "7.4.0",
|
||||
"@storybook/testing-library": "0.2.2",
|
||||
"@vitejs/plugin-react": "4.1.1",
|
||||
"c8": "8.0.1",
|
||||
"eslint-plugin-react-hooks": "4.6.0",
|
||||
"eslint-plugin-react-refresh": "0.4.3",
|
||||
"eslint-plugin-tailwindcss": "3.13.0",
|
||||
"mocha": "10.2.0",
|
||||
"rollup-plugin-node-builtins": "2.1.2",
|
||||
"sinon": "17.0.0",
|
||||
"ts-node": "10.9.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"storybook": "7.4.0",
|
||||
"typescript": "5.2.2",
|
||||
"vite": "4.5.0",
|
||||
"vite-plugin-svgr": "3.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dnd-kit/core": "6.0.8",
|
||||
"@dnd-kit/sortable": "7.0.2",
|
||||
"@ebay/nice-modal-react": "1.2.13",
|
||||
"@sentry/react": "7.77.0",
|
||||
"@tailwindcss/forms": "0.5.6",
|
||||
"@tailwindcss/line-clamp": "0.4.4",
|
||||
"@uiw/react-codemirror": "^4.21.9",
|
||||
"autoprefixer": "10.4.16",
|
||||
"clsx": "2.0.0",
|
||||
"postcss": "8.4.31",
|
||||
"postcss-import": "15.1.0",
|
||||
"react-colorful": "^5.1.2",
|
||||
"react-hot-toast": "2.4.1",
|
||||
"react-select": "5.8.0",
|
||||
"tailwindcss": "3.3.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0"
|
||||
}
|
||||
}
|
8
apps/admin-x-design/postcss.config.js
Normal file
@ -0,0 +1,8 @@
|
||||
export default {
|
||||
plugins: {
|
||||
'postcss-import': {},
|
||||
'tailwindcss/nesting': {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {}
|
||||
}
|
||||
};
|
@ -1,5 +1,4 @@
|
||||
.admin-x-settings {
|
||||
|
||||
.admin-x-base {
|
||||
/*
|
||||
1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
|
||||
2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
|
||||
@ -329,7 +328,7 @@
|
||||
input::placeholder,
|
||||
textarea::placeholder {
|
||||
opacity: 1; /* 1 */
|
||||
color: theme('colors.grey.500'); /* 2 */
|
||||
@apply text-grey-500; /* 2 */
|
||||
}
|
||||
|
||||
button:focus-visible,
|
||||
@ -364,5 +363,4 @@
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
}
|
27
apps/admin-x-design/src/DesignSystemApp.tsx
Normal file
@ -0,0 +1,27 @@
|
||||
import clsx from 'clsx';
|
||||
import React from 'react';
|
||||
import {FetchKoenigLexical} from './global/form/HtmlEditor';
|
||||
import DesignSystemProvider from './providers/DesignSystemProvider';
|
||||
|
||||
export interface DesignSystemAppProps extends React.HTMLProps<HTMLDivElement> {
|
||||
darkMode: boolean;
|
||||
fetchKoenigLexical: FetchKoenigLexical;
|
||||
}
|
||||
|
||||
const DesignSystemApp: React.FC<DesignSystemAppProps> = ({darkMode, fetchKoenigLexical, className, children, ...props}) => {
|
||||
const appClassName = clsx(
|
||||
'admin-x-base',
|
||||
darkMode && 'dark',
|
||||
className
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={appClassName} {...props}>
|
||||
<DesignSystemProvider fetchKoenigLexical={fetchKoenigLexical}>
|
||||
{children}
|
||||
</DesignSystemProvider>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DesignSystemApp;
|
Before Width: | Height: | Size: 401 B After Width: | Height: | Size: 401 B |
Before Width: | Height: | Size: 364 B After Width: | Height: | Size: 364 B |
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 363 B |
Before Width: | Height: | Size: 608 B After Width: | Height: | Size: 608 B |
Before Width: | Height: | Size: 403 B After Width: | Height: | Size: 403 B |
Before Width: | Height: | Size: 402 B After Width: | Height: | Size: 402 B |
Before Width: | Height: | Size: 451 B After Width: | Height: | Size: 451 B |
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 450 B |
Before Width: | Height: | Size: 452 B After Width: | Height: | Size: 452 B |
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 354 B |
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 354 B |
Before Width: | Height: | Size: 448 B After Width: | Height: | Size: 448 B |
Before Width: | Height: | Size: 532 B After Width: | Height: | Size: 532 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 851 B After Width: | Height: | Size: 851 B |
Before Width: | Height: | Size: 608 B After Width: | Height: | Size: 608 B |
Before Width: | Height: | Size: 423 B After Width: | Height: | Size: 423 B |
Before Width: | Height: | Size: 275 B After Width: | Height: | Size: 275 B |
Before Width: | Height: | Size: 315 B After Width: | Height: | Size: 315 B |
Before Width: | Height: | Size: 313 B After Width: | Height: | Size: 313 B |
Before Width: | Height: | Size: 311 B After Width: | Height: | Size: 311 B |
Before Width: | Height: | Size: 314 B After Width: | Height: | Size: 314 B |
Before Width: | Height: | Size: 417 B After Width: | Height: | Size: 417 B |
Before Width: | Height: | Size: 352 B After Width: | Height: | Size: 352 B |
Before Width: | Height: | Size: 502 B After Width: | Height: | Size: 502 B |
Before Width: | Height: | Size: 645 B After Width: | Height: | Size: 645 B |
Before Width: | Height: | Size: 642 B After Width: | Height: | Size: 642 B |
Before Width: | Height: | Size: 388 B After Width: | Height: | Size: 388 B |
Before Width: | Height: | Size: 1019 B After Width: | Height: | Size: 1019 B |
Before Width: | Height: | Size: 479 B After Width: | Height: | Size: 479 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 347 B After Width: | Height: | Size: 347 B |
Before Width: | Height: | Size: 420 B After Width: | Height: | Size: 420 B |
Before Width: | Height: | Size: 827 B After Width: | Height: | Size: 827 B |
Before Width: | Height: | Size: 587 B After Width: | Height: | Size: 587 B |
Before Width: | Height: | Size: 469 B After Width: | Height: | Size: 469 B |
Before Width: | Height: | Size: 848 B After Width: | Height: | Size: 848 B |
Before Width: | Height: | Size: 904 B After Width: | Height: | Size: 904 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 636 B After Width: | Height: | Size: 636 B |
Before Width: | Height: | Size: 924 B After Width: | Height: | Size: 924 B |
Before Width: | Height: | Size: 741 B After Width: | Height: | Size: 741 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 543 B After Width: | Height: | Size: 543 B |
Before Width: | Height: | Size: 547 B After Width: | Height: | Size: 547 B |
Before Width: | Height: | Size: 436 B After Width: | Height: | Size: 436 B |
Before Width: | Height: | Size: 698 B After Width: | Height: | Size: 698 B |
Before Width: | Height: | Size: 906 B After Width: | Height: | Size: 906 B |
Before Width: | Height: | Size: 419 B After Width: | Height: | Size: 419 B |
Before Width: | Height: | Size: 977 B After Width: | Height: | Size: 977 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 885 B After Width: | Height: | Size: 885 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 575 B After Width: | Height: | Size: 575 B |
Before Width: | Height: | Size: 729 B After Width: | Height: | Size: 729 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 827 B After Width: | Height: | Size: 827 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 706 B After Width: | Height: | Size: 706 B |
Before Width: | Height: | Size: 601 B After Width: | Height: | Size: 601 B |
Before Width: | Height: | Size: 990 B After Width: | Height: | Size: 990 B |
Before Width: | Height: | Size: 516 B After Width: | Height: | Size: 516 B |
Before Width: | Height: | Size: 516 B After Width: | Height: | Size: 516 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 631 B After Width: | Height: | Size: 631 B |
Before Width: | Height: | Size: 176 B After Width: | Height: | Size: 176 B |
Before Width: | Height: | Size: 524 B After Width: | Height: | Size: 524 B |
Before Width: | Height: | Size: 825 B After Width: | Height: | Size: 825 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 479 B After Width: | Height: | Size: 479 B |
Before Width: | Height: | Size: 237 B After Width: | Height: | Size: 237 B |
Before Width: | Height: | Size: 723 B After Width: | Height: | Size: 723 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 607 B After Width: | Height: | Size: 607 B |
Before Width: | Height: | Size: 230 B After Width: | Height: | Size: 230 B |