mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-29 15:12:58 +03:00
Added dropdown menu
This commit is contained in:
parent
1b684fe029
commit
e3fbe0a262
8644
apps/post-analytics-spike/dist/index-67f61ed8.mjs
vendored
8644
apps/post-analytics-spike/dist/index-67f61ed8.mjs
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
12601
apps/post-analytics-spike/dist/index-ae342ef9.mjs
vendored
Normal file
12601
apps/post-analytics-spike/dist/index-ae342ef9.mjs
vendored
Normal file
File diff suppressed because one or more lines are too long
1
apps/post-analytics-spike/dist/index-ae342ef9.mjs.map
vendored
Normal file
1
apps/post-analytics-spike/dist/index-ae342ef9.mjs.map
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
import { N as t, j as o } from "./index-67f61ed8.mjs";
|
||||
import { N as t, j as o } from "./index-ae342ef9.mjs";
|
||||
const a = t.create(() => /* @__PURE__ */ o.jsx(o.Fragment, {})), s = { DemoModal: a };
|
||||
export {
|
||||
s as default
|
||||
};
|
||||
//# sourceMappingURL=modals-ee4bac33.mjs.map
|
||||
//# sourceMappingURL=modals-8a9038c8.mjs.map
|
@ -1 +1 @@
|
||||
{"version":3,"file":"modals-ee4bac33.mjs","sources":["../src/components/DemoModal.tsx","../src/components/modals.tsx"],"sourcesContent":["import NiceModal from '@ebay/nice-modal-react';\n// import {Heading, Modal} from '@tryghost/shade';\n// import {useRouting} from '@tryghost/admin-x-framework/routing';\n\nconst DemoModal = NiceModal.create(() => {\n // const {updateRoute} = useRouting();\n // const modal = NiceModal.useModal();\n\n return ( <></>\n // <Modal\n // afterClose={() => {\n // updateRoute('');\n // }}\n // cancelLabel=''\n // okLabel='Close'\n // size='sm'\n // title='About'\n // onOk={() => {\n // updateRoute('');\n // modal.remove();\n // }}\n // >\n // <div className='mt-3 flex flex-col gap-4'>\n // <p>{`You're looking at a React app inside Ghost Admin. It uses common AdminX framework and Design System packages, and works seamlessly with the current Admin's routing.`}</p>\n // <p>{`At the moment the look and feel follows the current Admin's style to blend in with existing pages. However the system is built in a very flexible way to allow easy updates in the future.`}</p>\n // <Heading className='-mb-2 mt-4' level={5}>Contents</Heading>\n // <p>{`The demo uses a mocked list of members — it's `}<strong>not</strong> {`the actual or future design of members in Ghost Admin. Instead, the pages showcase common design patterns like a list and detail, navigation, modals and toasts.`}</p>\n // </div>\n // </Modal>\n );\n});\n\nexport default DemoModal;\n","import DemoModal from './DemoModal';\nimport {ModalComponent} from '@tryghost/admin-x-framework/routing';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst modals = {DemoModal} satisfies {[key: string]: ModalComponent<any>};\n\nexport default modals;\n\nexport type ModalName = keyof typeof modals;\n"],"names":["DemoModal","NiceModal","jsx","Fragment","modals"],"mappings":";AAIA,MAAMA,IAAYC,EAAU,OAAO,MAIpBC,gBAAAA,EAAA,IAAAC,YAAA,CAAA,CAAA,CAsBd,GC1BKC,IAAS,EAAC,WAAAJ,EAAS;"}
|
||||
{"version":3,"file":"modals-8a9038c8.mjs","sources":["../src/components/DemoModal.tsx","../src/components/modals.tsx"],"sourcesContent":["import NiceModal from '@ebay/nice-modal-react';\n// import {Heading, Modal} from '@tryghost/shade';\n// import {useRouting} from '@tryghost/admin-x-framework/routing';\n\nconst DemoModal = NiceModal.create(() => {\n // const {updateRoute} = useRouting();\n // const modal = NiceModal.useModal();\n\n return ( <></>\n // <Modal\n // afterClose={() => {\n // updateRoute('');\n // }}\n // cancelLabel=''\n // okLabel='Close'\n // size='sm'\n // title='About'\n // onOk={() => {\n // updateRoute('');\n // modal.remove();\n // }}\n // >\n // <div className='mt-3 flex flex-col gap-4'>\n // <p>{`You're looking at a React app inside Ghost Admin. It uses common AdminX framework and Design System packages, and works seamlessly with the current Admin's routing.`}</p>\n // <p>{`At the moment the look and feel follows the current Admin's style to blend in with existing pages. However the system is built in a very flexible way to allow easy updates in the future.`}</p>\n // <Heading className='-mb-2 mt-4' level={5}>Contents</Heading>\n // <p>{`The demo uses a mocked list of members — it's `}<strong>not</strong> {`the actual or future design of members in Ghost Admin. Instead, the pages showcase common design patterns like a list and detail, navigation, modals and toasts.`}</p>\n // </div>\n // </Modal>\n );\n});\n\nexport default DemoModal;\n","import DemoModal from './DemoModal';\nimport {ModalComponent} from '@tryghost/admin-x-framework/routing';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst modals = {DemoModal} satisfies {[key: string]: ModalComponent<any>};\n\nexport default modals;\n\nexport type ModalName = keyof typeof modals;\n"],"names":["DemoModal","NiceModal","jsx","Fragment","modals"],"mappings":";AAIA,MAAMA,IAAYC,EAAU,OAAO,MAIpBC,gBAAAA,EAAA,IAAAC,YAAA,CAAA,CAAA,CAsBd,GC1BKC,IAAS,EAAC,WAAAJ,EAAS;"}
|
File diff suppressed because one or more lines are too long
@ -1,4 +1,4 @@
|
||||
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, Heading, Icon } from "@tryghost/shade";
|
||||
import { Breadcrumb, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuTrigger, Heading, Icon } from "@tryghost/shade";
|
||||
|
||||
const PostAnalytics = () => {
|
||||
return (
|
||||
@ -21,9 +21,24 @@ const PostAnalytics = () => {
|
||||
<div className="flex items-start justify-between mt-2">
|
||||
<Heading size="pagetitle">Post analytics</Heading>
|
||||
<div className="flex items-center mt-1 gap-2">
|
||||
<Button variant='outline'><Icon name="reload" /> Refresh</Button>
|
||||
<Button variant='outline'><Icon name="share" /> Share</Button>
|
||||
<Button variant='outline'><Icon name="ellipsis" /></Button>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline"><Icon name="ellipsis" /></Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="min-w-48">
|
||||
<DropdownMenuItem>
|
||||
<span>Edit post</span>
|
||||
<DropdownMenuShortcut>⇧⌘E</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>
|
||||
<span>View in browser</span>
|
||||
<DropdownMenuShortcut>⇧⌘O</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem className="text-red">Delete</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
@ -1,6 +1,6 @@
|
||||
const adminXPreset = require('@tryghost/shade/tailwind.cjs');
|
||||
|
||||
module.exports = {
|
||||
presets: [adminXPreset('.post-analytics-spike')],
|
||||
presets: [adminXPreset('.shade')],
|
||||
content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}', '../../node_modules/@tryghost/shade/es/**/*.{js,ts,jsx,tsx}']
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ const preview: Preview = {
|
||||
options: {
|
||||
storySort: {
|
||||
method: 'alphabetical',
|
||||
order: ['GHDS 1.0', 'Welcome', 'Foundations', ['Style Guide', 'Colors', 'Icons', 'ErrorHandling'], 'Global', ['Form', 'Chrome', 'Modal', 'Layout', ['View Container', 'Page Header', 'Page'], 'List', 'Table', '*'], 'Settings', ['Setting Section', 'Setting Group', '*'], 'Experimental'],
|
||||
order: ['Welcome', 'Foundations', ['Style Guide', 'Colors', 'Icons', 'ErrorHandling'], 'Typography', 'Components', 'Meta'],
|
||||
},
|
||||
},
|
||||
docs: {
|
||||
@ -76,7 +76,7 @@ const preview: Preview = {
|
||||
let {scheme} = context.globals;
|
||||
|
||||
return (
|
||||
<div className={`shade admin-x-base ${scheme === 'dark' ? 'dark' : ''}`} style={{
|
||||
<div className={`shade ${scheme === 'dark' ? 'dark' : ''}`} style={{
|
||||
// padding: '24px',
|
||||
// width: 'unset',
|
||||
height: 'unset',
|
||||
|
@ -67,6 +67,7 @@
|
||||
"@ebay/nice-modal-react": "1.2.13",
|
||||
"@radix-ui/react-avatar": "1.1.0",
|
||||
"@radix-ui/react-checkbox": "1.1.1",
|
||||
"@radix-ui/react-dropdown-menu": "^2.1.2",
|
||||
"@radix-ui/react-form": "0.0.3",
|
||||
"@radix-ui/react-popover": "1.1.1",
|
||||
"@radix-ui/react-radio-group": "1.2.0",
|
||||
|
@ -1,4 +1,4 @@
|
||||
.admin-x-base {
|
||||
.shade {
|
||||
/*
|
||||
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)
|
||||
|
@ -10,7 +10,7 @@ export interface ShadeAppProps extends React.HTMLProps<HTMLDivElement> {
|
||||
|
||||
const ShadeApp: React.FC<ShadeAppProps> = ({darkMode, fetchKoenigLexical, className, children, ...props}) => {
|
||||
const appClassName = clsx(
|
||||
'admin-x-base',
|
||||
'shade',
|
||||
darkMode && 'dark',
|
||||
className
|
||||
);
|
||||
|
@ -1,6 +1,6 @@
|
||||
import type {Meta, StoryObj} from '@storybook/react';
|
||||
|
||||
import BoilerPlate from './Boilerplate';
|
||||
import BoilerPlate from './boilerplate';
|
||||
|
||||
const meta = {
|
||||
title: 'Meta / Boilerplate',
|
@ -3,7 +3,7 @@ import type {Meta, StoryObj} from '@storybook/react';
|
||||
import {Heading} from './heading';
|
||||
|
||||
const meta = {
|
||||
title: 'GHDS 1.0 / Heading',
|
||||
title: 'Typography / Heading',
|
||||
component: Heading,
|
||||
tags: ['autodocs']
|
||||
} satisfies Meta<typeof Heading>;
|
||||
|
@ -3,7 +3,7 @@ import type {Meta, StoryObj} from '@storybook/react';
|
||||
import Banner from './banner';
|
||||
|
||||
const meta = {
|
||||
title: 'Global / Banner',
|
||||
title: 'Components / Banner',
|
||||
component: Banner,
|
||||
tags: ['autodocs']
|
||||
} satisfies Meta<typeof Banner>;
|
||||
|
@ -3,7 +3,7 @@ import type {Meta, StoryObj} from '@storybook/react';
|
||||
import Icon from './icon';
|
||||
|
||||
const meta = {
|
||||
title: 'Global / Icon',
|
||||
title: 'Components / Icon',
|
||||
component: Icon,
|
||||
tags: ['autodocs']
|
||||
} satisfies Meta<typeof Icon>;
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
} from './breadcrumb';
|
||||
|
||||
const meta = {
|
||||
title: 'GHDS 1.0 / Breadcrumb',
|
||||
title: 'Components / Breadcrumb',
|
||||
component: Breadcrumb,
|
||||
tags: ['autodocs']
|
||||
} satisfies Meta<typeof Breadcrumb>;
|
||||
|
@ -3,7 +3,7 @@ import type {Meta, StoryObj} from '@storybook/react';
|
||||
import {Button} from './button';
|
||||
|
||||
const meta = {
|
||||
title: 'GHDS 1.0 / Button',
|
||||
title: 'Components / Button',
|
||||
component: Button,
|
||||
tags: ['autodocs']
|
||||
} satisfies Meta<typeof Button>;
|
||||
|
40
apps/shade/src/components/ui/dropdown-menu.stories.tsx
Normal file
40
apps/shade/src/components/ui/dropdown-menu.stories.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import type {Meta, StoryObj} from '@storybook/react';
|
||||
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import {Button} from './button';
|
||||
|
||||
const meta = {
|
||||
title: 'Components / Dropdown Menu',
|
||||
component: DropdownMenu,
|
||||
tags: ['autodocs']
|
||||
} satisfies Meta<typeof DropdownMenu>;
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof DropdownMenu>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
children: (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger>
|
||||
<Button variant="outline">Open</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuLabel>My Account</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>Profile</DropdownMenuItem>
|
||||
<DropdownMenuItem>Billing</DropdownMenuItem>
|
||||
<DropdownMenuItem>Team</DropdownMenuItem>
|
||||
<DropdownMenuItem>Subscription</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
};
|
200
apps/shade/src/components/ui/dropdown-menu.tsx
Normal file
200
apps/shade/src/components/ui/dropdown-menu.tsx
Normal file
@ -0,0 +1,200 @@
|
||||
import * as React from 'react';
|
||||
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
|
||||
import {Check, ChevronRight, Circle} from 'lucide-react';
|
||||
|
||||
import {cn} from '@/lib/utils';
|
||||
|
||||
const DropdownMenu = DropdownMenuPrimitive.Root;
|
||||
|
||||
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
||||
|
||||
const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
||||
|
||||
const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
||||
|
||||
const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
||||
|
||||
const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
||||
|
||||
const DropdownMenuSubTrigger = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({className, inset, children, ...props}, ref) => (
|
||||
<DropdownMenuPrimitive.SubTrigger
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'flex cursor-default gap-2 select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-neutral-100 data-[state=open]:bg-neutral-100 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:focus:bg-neutral-800 dark:data-[state=open]:bg-neutral-800',
|
||||
inset && 'pl-8',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ChevronRight className="ml-auto" />
|
||||
</DropdownMenuPrimitive.SubTrigger>
|
||||
));
|
||||
DropdownMenuSubTrigger.displayName =
|
||||
DropdownMenuPrimitive.SubTrigger.displayName;
|
||||
|
||||
const DropdownMenuSubContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>
|
||||
>(({className, ...props}, ref) => (
|
||||
<DropdownMenuPrimitive.SubContent
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuSubContent.displayName =
|
||||
DropdownMenuPrimitive.SubContent.displayName;
|
||||
|
||||
const DropdownMenuContent = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>
|
||||
>(({className, sideOffset = 4, ...props}, ref) => (
|
||||
<DropdownMenuPrimitive.Portal>
|
||||
<div className='shade'>
|
||||
<DropdownMenuPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'z-50 min-w-[8rem] overflow-hidden rounded-md border border-neutral-200 bg-white p-1 text-neutral-950 shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-50',
|
||||
className
|
||||
)}
|
||||
sideOffset={sideOffset}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
</DropdownMenuPrimitive.Portal>
|
||||
));
|
||||
DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
|
||||
|
||||
const DropdownMenuItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({className, inset, ...props}, ref) => (
|
||||
<DropdownMenuPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex cursor-pointer select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 dark:focus:bg-neutral-800 dark:focus:text-neutral-50',
|
||||
inset && 'pl-8',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
|
||||
|
||||
const DropdownMenuCheckboxItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>
|
||||
>(({className, children, checked, ...props}, ref) => (
|
||||
<DropdownMenuPrimitive.CheckboxItem
|
||||
ref={ref}
|
||||
checked={checked}
|
||||
className={cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Check className="h-4 w-4" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.CheckboxItem>
|
||||
));
|
||||
DropdownMenuCheckboxItem.displayName =
|
||||
DropdownMenuPrimitive.CheckboxItem.displayName;
|
||||
|
||||
const DropdownMenuRadioItem = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>
|
||||
>(({className, children, ...props}, ref) => (
|
||||
<DropdownMenuPrimitive.RadioItem
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-neutral-100 focus:text-neutral-900 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:focus:bg-neutral-800 dark:focus:text-neutral-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
|
||||
<DropdownMenuPrimitive.ItemIndicator>
|
||||
<Circle className="h-2 w-2 fill-current" />
|
||||
</DropdownMenuPrimitive.ItemIndicator>
|
||||
</span>
|
||||
{children}
|
||||
</DropdownMenuPrimitive.RadioItem>
|
||||
));
|
||||
DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
|
||||
|
||||
const DropdownMenuLabel = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> & {
|
||||
inset?: boolean
|
||||
}
|
||||
>(({className, inset, ...props}, ref) => (
|
||||
<DropdownMenuPrimitive.Label
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'px-2 py-1.5 text-sm font-semibold',
|
||||
inset && 'pl-8',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
|
||||
|
||||
const DropdownMenuSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||||
>(({className, ...props}, ref) => (
|
||||
<DropdownMenuPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn('-mx-1 my-1 h-px bg-neutral-100 dark:bg-neutral-800', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
|
||||
|
||||
const DropdownMenuShortcut = ({
|
||||
className,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn('ml-auto text-xs tracking-widest opacity-60', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
DropdownMenuShortcut.displayName = 'DropdownMenuShortcut';
|
||||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup
|
||||
};
|
@ -2,7 +2,7 @@ import ErrorBoundary from './error-boundary';
|
||||
import type {Meta, StoryObj} from '@storybook/react';
|
||||
|
||||
const meta = {
|
||||
title: 'Global / Error Boundary',
|
||||
title: 'Components / Error Boundary',
|
||||
component: ErrorBoundary,
|
||||
tags: ['autodocs']
|
||||
} satisfies Meta<typeof ErrorBoundary>;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Meta, ColorPalette, ColorItem } from '@storybook/blocks';
|
||||
|
||||
|
||||
<Meta title="Foundations / Colors" />
|
||||
<Meta title="Docs / Colors" />
|
||||
|
||||
<div className="sb-doc">
|
||||
# Colors
|
||||
|
@ -3,7 +3,7 @@ import SBLocalError from './assets/local-error-example.png';
|
||||
import SBPageError from './assets/page-error-example.png';
|
||||
import SBGlobalError from './assets/global-error-example.png';
|
||||
|
||||
<Meta title="Foundations / Error handling" />
|
||||
<Meta title="Docs / Error handling" />
|
||||
|
||||
<div className="sb-doc">
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Meta } from '@storybook/blocks';
|
||||
import StreamlineSettings from './assets/streamline-settings.png';
|
||||
|
||||
<Meta title="Foundations / Icons" />
|
||||
<Meta title="Docs / Icons" />
|
||||
|
||||
<div className="sb-doc">
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Meta } from '@storybook/blocks';
|
||||
import SBPageViewContainer from './assets/page-viewcontainer.png';
|
||||
|
||||
<Meta title="Foundations / Layout" />
|
||||
<Meta title="Docs / Layout" />
|
||||
|
||||
<div className="sb-doc">
|
||||
|
||||
|
@ -10,13 +10,9 @@ import AppsIcon from './assets/apps.svg';
|
||||
|
||||
<img src={WelcomeImage} className='main-image' />
|
||||
|
||||
# AdminX Design System
|
||||
# Shade
|
||||
|
||||
<p className='excerpt'>Here you can find our design guidelines, component documentation, and resources for building apps in Ghost Admin.</p>
|
||||
|
||||
### 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.
|
||||
Shade is Ghost's design system. It's a collection of React UI building blocks for designers and developers to create apps for the Ghost Admin.
|
||||
|
||||
<section className="main-structure-container">
|
||||
<div>
|
||||
|
@ -4,6 +4,7 @@ export type {IconProps} from './components/ui/icon';
|
||||
export * from './components/typography/heading';
|
||||
export * from './components/ui/breadcrumb';
|
||||
export * from './components/ui/button';
|
||||
export * from './components/ui/dropdown-menu';
|
||||
|
||||
export {default as useGlobalDirtyState} from './hooks/useGlobalDirtyState';
|
||||
export {usePagination} from './hooks/usePagination';
|
||||
|
@ -35,7 +35,7 @@
|
||||
font-weight: 100 900;
|
||||
}
|
||||
|
||||
.admin-x-base {
|
||||
.shade {
|
||||
& {
|
||||
@apply font-sans text-black text-base leading-normal;
|
||||
}
|
||||
@ -74,7 +74,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.admin-x-base {
|
||||
.shade {
|
||||
line-height: 1.5;
|
||||
-ms-text-size-adjust: 100%;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
@ -92,28 +92,28 @@
|
||||
}
|
||||
|
||||
@media (max-width: 800px) {
|
||||
.admin-x-base {
|
||||
.shade {
|
||||
height: calc(100vh - 55px);
|
||||
}
|
||||
}
|
||||
|
||||
.admin-x-base.dark {
|
||||
.shade.dark {
|
||||
color: #fafafb;
|
||||
}
|
||||
|
||||
.admin-x-base.dark .gh-loading-orb-container {
|
||||
.shade.dark .gh-loading-orb-container {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.admin-x-base.dark .gh-loading-orb {
|
||||
.shade.dark .gh-loading-orb {
|
||||
filter: invert(100%);
|
||||
}
|
||||
|
||||
.admin-x-base .no-scrollbar::-webkit-scrollbar {
|
||||
.shade .no-scrollbar::-webkit-scrollbar {
|
||||
display: none; /* Chrome */
|
||||
}
|
||||
|
||||
.admin-x-base .no-scrollbar {
|
||||
.shade .no-scrollbar {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
|
87
yarn.lock
87
yarn.lock
@ -4314,6 +4314,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.0.tgz#6df8d983546cfd1999c8512f3a8ad85a6e7fcee8"
|
||||
integrity sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==
|
||||
|
||||
"@radix-ui/react-context@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.1.tgz#82074aa83a472353bb22e86f11bcbd1c61c4c71a"
|
||||
integrity sha512-UASk9zi+crv9WteK/NU4PLvOoL3OuE6BWVKNF6hPRBtYBDXQ2u5iu3O59zUlJiTVvkyuycnqrztsHVJwcK9K+Q==
|
||||
|
||||
"@radix-ui/react-direction@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b"
|
||||
@ -4349,6 +4354,30 @@
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
"@radix-ui/react-use-escape-keydown" "1.1.0"
|
||||
|
||||
"@radix-ui/react-dismissable-layer@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.1.tgz#cbdcb739c5403382bdde5f9243042ba643883396"
|
||||
integrity sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==
|
||||
dependencies:
|
||||
"@radix-ui/primitive" "1.1.0"
|
||||
"@radix-ui/react-compose-refs" "1.1.0"
|
||||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
"@radix-ui/react-use-escape-keydown" "1.1.0"
|
||||
|
||||
"@radix-ui/react-dropdown-menu@^2.1.2":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.2.tgz#acc49577130e3c875ef0133bd1e271ea3392d924"
|
||||
integrity sha512-GVZMR+eqK8/Kes0a36Qrv+i20bAPXSn8rCBTHx30w+3ECnR5o3xixAlqcVaYvLeyKUsm0aqyhWfmUcqufM8nYA==
|
||||
dependencies:
|
||||
"@radix-ui/primitive" "1.1.0"
|
||||
"@radix-ui/react-compose-refs" "1.1.0"
|
||||
"@radix-ui/react-context" "1.1.1"
|
||||
"@radix-ui/react-id" "1.1.0"
|
||||
"@radix-ui/react-menu" "2.1.2"
|
||||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-use-controllable-state" "1.1.0"
|
||||
|
||||
"@radix-ui/react-focus-guards@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad"
|
||||
@ -4361,6 +4390,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz#8e9abb472a9a394f59a1b45f3dd26cfe3fc6da13"
|
||||
integrity sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==
|
||||
|
||||
"@radix-ui/react-focus-guards@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz#8635edd346304f8b42cae86b05912b61aef27afe"
|
||||
integrity sha512-pSIwfrT1a6sIoDASCSpFwOasEwKTZWDw/iBdtnqKO7v6FeOzYJ7U53cPzYFVR3geGGXgVHaH+CdngrrAzqUGxg==
|
||||
|
||||
"@radix-ui/react-focus-scope@1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.3.tgz#9c2e8d4ed1189a1d419ee61edd5c1828726472f9"
|
||||
@ -4416,6 +4450,30 @@
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "1.0.3"
|
||||
|
||||
"@radix-ui/react-menu@2.1.2":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.1.2.tgz#91f6815845a4298dde775563ed2d80b7ad667899"
|
||||
integrity sha512-lZ0R4qR2Al6fZ4yCCZzu/ReTFrylHFxIqy7OezIpWF4bL0o9biKo0pFIvkaew3TyZ9Fy5gYVrR5zCGZBVbO1zg==
|
||||
dependencies:
|
||||
"@radix-ui/primitive" "1.1.0"
|
||||
"@radix-ui/react-collection" "1.1.0"
|
||||
"@radix-ui/react-compose-refs" "1.1.0"
|
||||
"@radix-ui/react-context" "1.1.1"
|
||||
"@radix-ui/react-direction" "1.1.0"
|
||||
"@radix-ui/react-dismissable-layer" "1.1.1"
|
||||
"@radix-ui/react-focus-guards" "1.1.1"
|
||||
"@radix-ui/react-focus-scope" "1.1.0"
|
||||
"@radix-ui/react-id" "1.1.0"
|
||||
"@radix-ui/react-popper" "1.2.0"
|
||||
"@radix-ui/react-portal" "1.1.2"
|
||||
"@radix-ui/react-presence" "1.1.1"
|
||||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-roving-focus" "1.1.0"
|
||||
"@radix-ui/react-slot" "1.1.0"
|
||||
"@radix-ui/react-use-callback-ref" "1.1.0"
|
||||
aria-hidden "^1.1.1"
|
||||
react-remove-scroll "2.6.0"
|
||||
|
||||
"@radix-ui/react-popover@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-popover/-/react-popover-1.1.1.tgz#604b783cdb3494ed4f16a58c17f0e81e61ab7775"
|
||||
@ -4486,6 +4544,14 @@
|
||||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-portal@1.1.2":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.2.tgz#51eb46dae7505074b306ebcb985bf65cc547d74e"
|
||||
integrity sha512-WeDYLGPxJb/5EGBoedyJbT0MpoULmwnIPMJMSldkuiMsBAv7N1cRdsTWZWht9vpPOiN3qyiGAtbK2is47/uMFg==
|
||||
dependencies:
|
||||
"@radix-ui/react-primitive" "2.0.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-presence@1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.0.tgz#227d84d20ca6bfe7da97104b1a8b48a833bfb478"
|
||||
@ -4494,6 +4560,14 @@
|
||||
"@radix-ui/react-compose-refs" "1.1.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-presence@1.1.1":
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.1.tgz#98aba423dba5e0c687a782c0669dcd99de17f9b1"
|
||||
integrity sha512-IeFXVi4YS1K0wVZzXNrbaaUvIJ3qdY+/Ih4eHFhWA9SwGR9UDX7Ck8abvL57C4cv3wwMvUE0OG69Qc3NCcTe/A==
|
||||
dependencies:
|
||||
"@radix-ui/react-compose-refs" "1.1.0"
|
||||
"@radix-ui/react-use-layout-effect" "1.1.0"
|
||||
|
||||
"@radix-ui/react-primitive@1.0.3":
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0"
|
||||
@ -27085,7 +27159,7 @@ react-refresh@^0.14.0:
|
||||
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
|
||||
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
|
||||
|
||||
react-remove-scroll-bar@^2.3.3, react-remove-scroll-bar@^2.3.4:
|
||||
react-remove-scroll-bar@^2.3.3, react-remove-scroll-bar@^2.3.4, react-remove-scroll-bar@^2.3.6:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz#3e585e9d163be84a010180b18721e851ac81a29c"
|
||||
integrity sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==
|
||||
@ -27115,6 +27189,17 @@ react-remove-scroll@2.5.7:
|
||||
use-callback-ref "^1.3.0"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-remove-scroll@2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.6.0.tgz#fb03a0845d7768a4f1519a99fdb84983b793dc07"
|
||||
integrity sha512-I2U4JVEsQenxDAKaVa3VZ/JeJZe0/2DxPWL8Tj8yLKctQJQiZM52pn/GWFpSp8dftjM3pSAHVJZscAnC/y+ySQ==
|
||||
dependencies:
|
||||
react-remove-scroll-bar "^2.3.6"
|
||||
react-style-singleton "^2.2.1"
|
||||
tslib "^2.1.0"
|
||||
use-callback-ref "^1.3.0"
|
||||
use-sidecar "^1.1.2"
|
||||
|
||||
react-select@5.8.2:
|
||||
version "5.8.2"
|
||||
resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.8.2.tgz#0d7ccb1895d61aafcd090fbf65aa9e506225a854"
|
||||
|
Loading…
Reference in New Issue
Block a user