diff --git a/apps/admin-x-design-system/src/global/layout/app-menu.tsx b/apps/admin-x-design-system/src/global/layout/app-menu.tsx
deleted file mode 100644
index 8f11e0aeddd..00000000000
--- a/apps/admin-x-design-system/src/global/layout/app-menu.tsx
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react';
-import {Button} from '@tryghost/shade/components';
-import {LucideIcon} from '@tryghost/shade/utils';
-
-const PageMenu: React.FC = () => {
- return (
- {
- alert('Clicked on hamburger');
- }}>
- );
-};
-
-export default PageMenu;
diff --git a/apps/admin-x-design-system/src/global/layout/global-actions.tsx b/apps/admin-x-design-system/src/global/layout/global-actions.tsx
deleted file mode 100644
index 030345f2780..00000000000
--- a/apps/admin-x-design-system/src/global/layout/global-actions.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react';
-import {Button} from '@tryghost/shade/components';
-import {LucideIcon} from '@tryghost/shade/utils';
-
-const GlobalActions: React.FC = () => {
- return (
- {}}>
- );
-};
-
-export default GlobalActions;
diff --git a/apps/admin-x-design-system/src/global/layout/page-header.stories.tsx b/apps/admin-x-design-system/src/global/layout/page-header.stories.tsx
deleted file mode 100644
index 1d95769b378..00000000000
--- a/apps/admin-x-design-system/src/global/layout/page-header.stories.tsx
+++ /dev/null
@@ -1,67 +0,0 @@
-import type {Meta, StoryObj} from '@storybook/react-vite';
-
-import PageHeader from './page-header';
-
-const meta = {
- title: 'Global / Layout / Page Header',
- component: PageHeader,
- tags: ['autodocs']
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {
- args: {
- left: 'Left content',
- center: 'Center content',
- right: 'Right content'
- }
-};
-
-export const CustomContainer: Story = {
- args: {
- left: 'Left content',
- center: 'Center content',
- right: 'Right content',
- containerClassName: 'bg-grey-50'
- }
-};
-
-export const LeftAndRight: Story = {
- args: {
- left: 'Left content',
- right: 'Right content'
- }
-};
-
-export const LeftOnly: Story = {
- args: {
- left: 'Left content'
- }
-};
-
-export const CenterOnly: Story = {
- args: {
- center: 'Center content'
- }
-};
-
-export const RightOnly: Story = {
- args: {
- right: 'Right content'
- }
-};
-
-export const CustomContent: Story = {
- args: {
- children: (
-
-
This
-
is
-
custom
-
content!
-
- )
- }
-};
diff --git a/apps/admin-x-design-system/src/global/layout/page-header.tsx b/apps/admin-x-design-system/src/global/layout/page-header.tsx
deleted file mode 100644
index 43bbd50c2c6..00000000000
--- a/apps/admin-x-design-system/src/global/layout/page-header.tsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import clsx from 'clsx';
-import React from 'react';
-
-export interface PageHeaderProps {
-
- /**
- * Use these to specifically place elements on the left | center | right of the header.
- */
- left?: React.ReactNode;
- center?: React.ReactNode;
- right?: React.ReactNode;
-
- sticky?: boolean;
- containerClassName?: string;
-
- /**
- * Or you can simply use the whole container to make sure header spacing is consistent. `children` takes precedence over `left`, `center` and `right`.
- */
- children?: React.ReactNode;
-}
-
-const PageHeader: React.FC = ({
- left,
- center,
- right,
- sticky = true,
- containerClassName,
- children
-}) => {
- const containerClasses = clsx(
- 'z-50 h-22 min-h-[92px] p-8',
- !children && 'flex items-center justify-between gap-3',
- sticky && 'sticky top-0',
- containerClassName
- );
-
- if (!children) {
- if (left) {
- const leftClasses = clsx(
- 'flex flex-auto items-center',
- (right && center) && 'basis-1/3',
- ((!right && center)) && 'basis-1/2'
- );
- left = {left}
;
- }
- if (center) {
- const centerClasses = clsx(
- 'flex flex-auto items-center justify-center',
- (left && right) && 'basis-1/3',
- ((left && !right) || (!left && right)) && 'basis-1/2'
- );
- center = {center}
;
- }
- if (right) {
- const rightClasses = clsx(
- 'flex flex-auto items-center justify-end',
- (left && center) && 'basis-1/3',
- ((!left && center)) && 'basis-1/2'
- );
- right = {right}
;
- }
- }
-
- return (
-
- {children ? children :
- <>
- {left}
- {center}
- {right}
- >
- }
-
- );
-};
-
-export default PageHeader;
diff --git a/apps/admin-x-design-system/src/global/layout/page.stories.tsx b/apps/admin-x-design-system/src/global/layout/page.stories.tsx
deleted file mode 100644
index a220f1c0207..00000000000
--- a/apps/admin-x-design-system/src/global/layout/page.stories.tsx
+++ /dev/null
@@ -1,306 +0,0 @@
-import type {Meta, StoryObj} from '@storybook/react-vite';
-
-import Page, {CustomGlobalAction} from './page';
-import ViewContainer from './view-container';
-
-import {exampleActions as exampleActionButtons} from './view-container.stories';
-import {Text} from '@tryghost/shade/primitives';
-import {LucideIcon} from '@tryghost/shade/utils';
-
-const meta = {
- title: 'Global / Layout / Page',
- component: Page,
- tags: ['autodocs'],
- parameters: {
- layout: 'fullscreen'
- }
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-const dummyContent = Placeholder content
;
-
-const customGlobalActions: CustomGlobalAction[] = [
- {
- key: 'heart',
- icon: ,
- ariaLabel: 'Favorite',
- onClick: () => {
- alert('Clicked on custom action');
- }
- }
-];
-
-const pageTabs = Page tabs slot
;
-
-export const Default: Story = {
- args: {
- pageTabs: pageTabs,
- children: dummyContent
- }
-};
-
-export const LimitToolbarWidth: Story = {
- args: {
- pageTabs: pageTabs,
- children: dummyContent,
- fullBleedToolbar: false
- }
-};
-
-export const WithHamburger: Story = {
- args: {
- pageTabs: pageTabs,
- showAppMenu: true,
- children: dummyContent
- }
-};
-
-export const WithGlobalActions: Story = {
- args: {
- pageTabs: pageTabs,
- showAppMenu: true,
- showGlobalActions: true,
- children: dummyContent
- }
-};
-
-export const CustomGlobalActions: Story = {
- args: {
- pageTabs: pageTabs,
- showAppMenu: true,
- showGlobalActions: true,
- children: dummyContent,
- customGlobalActions: customGlobalActions
- }
-};
-
-const mockIdeaCards = () => {
- const cards = [];
-
- for (let i = 0; i < 11; i++) {
- cards.push(
-
-
- {i % 3 === 0 && 'Sunset drinks cruise eat sleep repeat'}
- {i % 3 === 1 && 'Elegance Rolls Royce on my private jet'}
- {i % 3 === 2 && 'Down to the wire Bathurst 5000 Le Tour'}
-
-
- {i % 3 === 0 && 'Numea captain’s table crystal waters paradise island the scenic route great adventure. Pirate speak the road less travelled seas the day '}
- {i % 3 === 1 && 'Another day in paradise cruise life adventure bound gap year cruise time languid afternoons let the sea set you free'}
- {i % 3 === 2 && No body text }
-
-
- );
- }
- return cards;
-};
-
-const exampleCardViewContent = (
- New idea action slot}
- title='Ideas'
- type='page'
- >
-
- {mockIdeaCards()}
-
-
-);
-
-export const ExampleCardView: Story = {
- name: 'Example: Card View',
- args: {
- pageTabs: pageTabs,
- showAppMenu: true,
- showGlobalActions: true,
- children: exampleCardViewContent
- }
-};
-
-const mockPosts = () => {
- const posts = [];
-
- for (let i = 0; i < 11; i++) {
- posts.push(
-
-
-
-
-
-
-
- {i % 3 === 0 && 'Sunset drinks cruise eat sleep repeat'}
- {i % 3 === 1 && 'Elegance Rolls Royce on my private jet'}
- {i % 3 === 2 && 'Down to the wire Bathurst 5000 Le Tour'}
-
-
- {i % 3 === 0 && 'Numea captain’s table crystal waters paradise island the scenic route great adventure. Pirate speak the road less travelled seas the day '}
- {i % 3 === 1 && 'Another day in paradise cruise life adventure bound gap year cruise time languid afternoons let the sea set you free'}
- {i % 3 === 2 && 'Grand Prix gamble responsibly intensity is not a perfume The Datsun 180B Aerial ping pong knock for six watch with the boys total hospital pass.'}
-
-
-
-
- 15%
- viewed
-
-
- 55%
- opened
-
-
- Post action slot
-
-
- );
- }
- return posts;
-};
-
-const examplePostsContent = (
- New post action slot}
- title='Posts'
- type='page'
- >
-
- {<>{mockPosts()}>}
-
-
-);
-
-export const ExampleAlternativeList: Story = {
- name: 'Example: Alternative List',
- args: {
- pageTabs: pageTabs,
- showAppMenu: true,
- showGlobalActions: true,
- children: examplePostsContent
- }
-};
-
-export const ExampleDetailScreen: Story = {
- name: 'Example: Detail Page',
- args: {
- showAppMenu: true,
- breadCrumbs: Breadcrumbs slot ,
- showGlobalActions: true,
- children: <>
-
- Emerson Vaccaro
- Colombus, OH
-
- }
- primaryAction={Member action slot }
- type='page'
- >
-
-
- Last seen on 22 June 2023
- Created on 27 Jan 2021
-
-
- Emails received
- 181
-
-
- Emails opened
- 104
-
-
- Average open rate
- 57%
-
-
-
-
-
- Member data
- Edit action slot
-
-
-
Name
-
Emerson Vaccaro
-
-
-
Email
-
emerson@vaccaro.com
-
-
-
-
-
-
Newsletters
-
-
-
- Daily news
-
-
-
- Weekly roundup
-
-
-
- The Inner Circle
-
-
- This member cannot receive emails due to permanent failure (bounce).
-
-
-
-
-
Subscriptions
-
-
- $5
- Yearly
-
-
- Gold
- Renews 21 Jan 2024
-
-
-
-
-
- Activity
- View all action slot
-
-
- Logged in
- 13 days ago
-
-
- Subscribed to Daily News
- 17 days ago
-
-
- Logged in
- 21 days ago
-
-
-
-
- >
- }
-};
diff --git a/apps/admin-x-design-system/src/global/layout/page.tsx b/apps/admin-x-design-system/src/global/layout/page.tsx
deleted file mode 100644
index 17bc4f7d601..00000000000
--- a/apps/admin-x-design-system/src/global/layout/page.tsx
+++ /dev/null
@@ -1,127 +0,0 @@
-import React from 'react';
-import clsx from 'clsx';
-import AppMenu from './app-menu';
-import GlobalActions from './global-actions';
-import PageHeader from './page-header';
-import {Button} from '@tryghost/shade/components';
-
-export interface CustomGlobalAction {
- key: string;
- icon: React.ReactNode;
- ariaLabel: string;
- onClick?: () => void;
-}
-
-interface PageProps {
- mainContainerClassName?: string;
- mainClassName?: string;
- fullBleedPage?: boolean;
-
- /**
- * The pageToolbar is a WIP part of this component, it's unused ATM in Ghost Admin.
- */
- pageToolbarClassName?: string;
- fullBleedToolbar?: boolean;
-
- /**
- * TK. Part of the Page Toolbar
- */
- showAppMenu?: boolean;
-
- /**
- * Show
- */
- showGlobalActions?: boolean;
-
- /**
- * TK. Part of the Page Toolbar
- */
- customGlobalActions?: CustomGlobalAction[];
- breadCrumbs?: React.ReactNode;
-
- /**
- * TK. Part of the Page Toolbar
- */
- pageTabs?: React.ReactNode,
-
- children?: React.ReactNode;
-}
-
-/**
- * The page component is the main container in Ghost Admin. It consists of a
- * page level toolbar (`pageToolbar` — unused ATM, it's for page level views and
- * navigation in the future), and the main content area.
- *
- * ### Examples
- * You can find several examples in the sidebar. If you're building a page for the
- * current Admin you can use the ["List in Current Admin"](/story/global-layout-page--example-current-admin-list)
- * example as a starting point. The rest of the examples are showing a potential direction for a
- * future structure.
- */
-const Page: React.FC = ({
- fullBleedPage = true,
- mainContainerClassName,
- mainClassName,
- pageToolbarClassName,
- fullBleedToolbar = true,
- showAppMenu = false,
- showGlobalActions = false,
- customGlobalActions,
- breadCrumbs,
- pageTabs,
- children
-}) => {
- const left: React.ReactNode = (
- (showAppMenu || breadCrumbs || pageTabs) &&
- {showAppMenu && (
-
- )}
- {breadCrumbs}
- {pageTabs}
-
);
-
- mainClassName = clsx(
- 'flex w-full flex-auto flex-col',
- mainClassName
- );
-
- const globalActions = (
- (customGlobalActions?.length || showGlobalActions) &&
-
- {(customGlobalActions?.map((action) => {
- return (
- {action.icon}
- );
- }))}
- {showGlobalActions && }
-
);
-
- mainContainerClassName = clsx(
- 'flex h-[100vh] w-full flex-col overflow-x-hidden overflow-y-auto',
- !fullBleedPage && 'mx-auto max-w-7xl',
- mainContainerClassName
- );
-
- pageToolbarClassName = clsx(
- 'sticky top-0 z-50 flex h-22 min-h-[92px] w-full items-center justify-between gap-5 bg-white p-8 dark:bg-black',
- !fullBleedToolbar && 'mx-auto max-w-7xl',
- pageToolbarClassName
- );
-
- return (
-
- {(left || globalActions) &&
-
- }
-
- {children}
-
-
- );
-};
-
-export default Page;
diff --git a/apps/admin-x-design-system/src/global/modal/modal.stories.tsx b/apps/admin-x-design-system/src/global/modal/modal.stories.tsx
deleted file mode 100644
index e90afa48a0e..00000000000
--- a/apps/admin-x-design-system/src/global/modal/modal.stories.tsx
+++ /dev/null
@@ -1,289 +0,0 @@
-import type {Meta, StoryContext, StoryObj} from '@storybook/react-vite';
-import {ReactNode} from 'react';
-
-import NiceModal from '@ebay/nice-modal-react';
-import Modal, {ModalProps} from './modal';
-
-const ModalContainer: React.FC = ({children, ...props}) => {
- const modal = NiceModal.create(() => {
- return (
-
-
- {children}
-
-
- );
- });
- return (
-
- {
- NiceModal.show(modal);
- }}>Open modal
-
- );
-};
-
-const meta = {
- title: 'Global / Modal',
- component: Modal,
- tags: ['autodocs'],
- argTypes: {
- topRightContent: {
- control: {
- type: 'text'
- }
- }
- },
- decorators: [(_story: () => ReactNode, context: StoryContext) => (
-
-
-
- )]
-
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-const modalContent = (Modal content
);
-
-export const Default: Story = {
- args: {
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- topRightContent: 'close',
- title: 'Modal dialog',
- children: modalContent
- }
-};
-
-export const Small: Story = {
- args: {
- size: 'sm',
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Small modal',
- children: modalContent
- }
-};
-
-export const Medium: Story = {
- args: {
- size: 'md',
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Medium modal (default size)',
- children: modalContent
- }
-};
-
-export const Large: Story = {
- args: {
- size: 'lg',
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Large modal',
- children: modalContent
- }
-};
-
-export const ExtraLarge: Story = {
- args: {
- size: 'xl',
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Extra large modal',
- children: modalContent
- }
-};
-
-export const Full: Story = {
- args: {
- size: 'full',
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Full modal',
- children: modalContent
- }
-};
-
-export const Bleed: Story = {
- args: {
- size: 'bleed',
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Full bleed modal',
- children: modalContent
- }
-};
-
-export const CustomWidth: Story = {
- args: {
- width: 600,
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Custom width modal',
- children: modalContent
- }
-};
-
-export const CustomHeight: Story = {
- args: {
- size: 'md',
- height: 'full',
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Custom height modal',
- children: modalContent
- }
-};
-
-export const Square: Story = {
- args: {
- width: 320,
- height: 320,
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Square modal',
- children: modalContent
- }
-};
-
-export const CompletePage: Story = {
- args: {
- size: 'full',
- footer: <>>,
- padding: false,
- children: <>
- Full-page modal content
- >
- }
-};
-
-export const CustomButtons: Story = {
- args: {
- leftButton: Left action slot ,
- cancelLabel: 'Nope',
- okLabel: 'Yep',
- onOk: () => {
- alert('Clicked Yep!');
- },
- onCancel: undefined,
- title: 'Custom buttons',
- children: modalContent
- }
-};
-
-export const RightDrawer: Story = {
- args: {
- size: 'bleed',
- align: 'right',
- animate: false,
- width: 600,
- footer: <>>,
- children: <>
- This is a drawer style on the right
- >
- }
-};
-
-export const LeftDrawer: Story = {
- args: {
- size: 'bleed',
- align: 'left',
- animate: false,
- width: 600,
- footer: <>>,
- children: <>
- This is a drawer style on the right
- >
- }
-};
-
-const longContent = (
- <>
- Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure.
- Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure.
- Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure.
- Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure. Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure.
- Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure.
- Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure.
- Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure. Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure.
- Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure.
- Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure.
- Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure. Esse ex officia ipsum et magna reprehenderit ullamco dolore cillum cupidatat ullamco culpa. In et irure irure est id cillum officia pariatur et proident. Nulla nulla dolore qui excepteur magna eu adipisicing mollit. Eiusmod eu irure cupidatat consequat consectetur irure.
- >
-);
-
-export const StickyHeader: Story = {
- args: {
- size: 'md',
- stickyHeader: true,
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Sticky header',
- stickyFooter: true,
- children: longContent
- }
-};
-
-export const StickyFooter: Story = {
- args: {
- size: 'md',
- stickyFooter: true,
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Sticky footer',
- children: longContent
- }
-};
-
-export const Dirty: Story = {
- args: {
- size: 'md',
- dirty: true,
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- title: 'Dirty modal',
- children: Simulates if there were unsaved changes of a form. Click on Cancel
- }
-};
-
-export const FormSheet: Story = {
- args: {
- onOk: () => {
- alert('Clicked OK!');
- },
- onCancel: undefined,
- size: 'sm',
- title: 'Form sheet',
- formSheet: true,
- children: Slightly differently styled modal that can be used to display small forms inside other modals . Use it sparingly!
- }
-};
diff --git a/apps/admin-x-design-system/src/global/modal/modal.tsx b/apps/admin-x-design-system/src/global/modal/modal.tsx
deleted file mode 100644
index e92f19fa149..00000000000
--- a/apps/admin-x-design-system/src/global/modal/modal.tsx
+++ /dev/null
@@ -1,452 +0,0 @@
-import {useModal} from '@ebay/nice-modal-react';
-import clsx from 'clsx';
-import React, {useEffect, useState, forwardRef} from 'react';
-import {Button, type ButtonProps, LoadingIndicator, StickyFooter} from '@tryghost/shade/components';
-import {DirtyConfirmDialog, useDirtyConfirmation} from '@tryghost/shade/patterns';
-import {Inline, Text} from '@tryghost/shade/primitives';
-import {LucideIcon, useGlobalDirtyState} from '@tryghost/shade/utils';
-
-export type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full' | 'bleed';
-
-export interface ModalProps {
-
- /**
- * Possible values are: `sm`, `md`, `lg`, `xl, `full`, `bleed`. Yu can also use any number to set an arbitrary width.
- */
- size?: ModalSize;
- width?: 'full' | 'toSidebar' | number;
- height?: 'full' | number;
- align?: 'center' | 'left' | 'right';
-
- testId?: string;
- title?: React.ReactNode;
- okLabel?: string;
- okVariant?: ButtonProps['variant'];
- okLoading?: boolean;
- cancelLabel?: string;
- leftButton?: React.ReactNode;
- buttonsDisabled?: boolean;
- okDisabled?: boolean;
- footer?: boolean | React.ReactNode;
- header?: boolean;
- padding?: boolean;
- onOk?: () => void;
- onCancel?: () => void;
- topRightContent?: 'close' | React.ReactNode;
- hideXOnMobile?: boolean;
- afterClose?: () => void;
- children?: React.ReactNode;
- backDrop?: boolean;
- backDropClick?: boolean;
- stickyFooter?: boolean;
- stickyHeader?:boolean;
- scrolling?: boolean;
- dirty?: boolean;
- animate?: boolean;
- formSheet?: boolean;
- enableCMDS?: boolean;
- allowBackgroundInteraction?: boolean;
-}
-
-export const topLevelBackdropClasses = 'bg-[rgba(98,109,121,0.2)] backdrop-blur-[3px]';
-
-const Modal = forwardRef(({
- size = 'md',
- align = 'center',
- width,
- height,
- testId,
- title,
- okLabel = 'OK',
- okLoading = false,
- cancelLabel = 'Cancel',
- footer,
- header,
- leftButton,
- buttonsDisabled,
- okDisabled,
- padding = true,
- onOk,
- okVariant = 'default',
- onCancel,
- topRightContent,
- hideXOnMobile = false,
- afterClose,
- children,
- backDrop = true,
- backDropClick = true,
- stickyFooter = false,
- stickyHeader = false,
- scrolling = true,
- dirty = false,
- animate = true,
- formSheet = false,
- enableCMDS = true,
- allowBackgroundInteraction = false
-}, ref) => {
- const modal = useModal();
- const {setGlobalDirtyState} = useGlobalDirtyState();
- const {confirm, dialogProps} = useDirtyConfirmation();
- const [animationFinished, setAnimationFinished] = useState(false);
-
- useEffect(() => {
- setGlobalDirtyState(dirty);
- }, [dirty, setGlobalDirtyState]);
-
- useEffect(() => {
- const handleEscapeKey = (event: KeyboardEvent) => {
- if (event.key === 'Escape') {
- // Don't close modal if user is in Koenig's link input (which handles ESC itself)
- const activeEl = document.activeElement;
- if (activeEl?.hasAttribute('data-kg-link-input')) {
- return;
- }
-
- // Fix for Safari - if an element in the modal is focused, closing it will jump to
- // the bottom of the page because Safari tries to focus the "next" element in the DOM
- if (document.activeElement && document.activeElement instanceof HTMLElement) {
- document.activeElement.blur();
- }
- // Close the modal on the next tick so that the blur registers
- setTimeout(() => {
- if (onCancel) {
- onCancel();
- } else {
- confirm(dirty, () => {
- modal.remove();
- afterClose?.();
- });
- }
- });
-
- // Prevent the event from bubbling up to the window level
- event.stopPropagation();
- }
- };
-
- document.addEventListener('keydown', handleEscapeKey);
-
- // Clean up the event listener when the modal is closed
- return () => {
- document.removeEventListener('keydown', handleEscapeKey);
- };
- }, [modal, dirty, afterClose, onCancel, confirm]);
-
- // The animation classes apply a transform to the modal, which breaks anything inside using position:fixed
- // We should remove the class as soon as the animation is finished
- useEffect(() => {
- const timeout = setTimeout(() => {
- setAnimationFinished(true);
- }, 250);
-
- return () => clearTimeout(timeout);
- }, []);
-
- useEffect(() => {
- if (onOk) {
- const handleCMDS = (e: KeyboardEvent) => {
- if ((e.metaKey || e.ctrlKey) && e.key === 's') {
- e.preventDefault();
- onOk();
- }
- };
- if (enableCMDS) {
- window.addEventListener('keydown', handleCMDS);
- return () => {
- window.removeEventListener('keydown', handleCMDS);
- };
- }
- }
- });
-
- let contentClasses;
-
- const removeModal = () => {
- confirm(dirty, () => {
- modal.remove();
- afterClose?.();
- });
- };
-
- let modalClasses = clsx(
- 'relative z-50 flex max-h-[100%] w-full flex-col justify-between overflow-x-hidden bg-background text-foreground',
- align === 'center' && 'mx-auto',
- align === 'left' && 'mr-auto',
- align === 'right' && 'ml-auto',
- size !== 'bleed' && 'rounded',
- formSheet ? 'shadow-md' : 'shadow-xl',
- (animate && !formSheet && !animationFinished && align === 'center') && 'animate-modal-in',
- (animate && !formSheet && !animationFinished && align === 'right') && 'animate-modal-in-from-right',
- (formSheet && !animationFinished) && 'animate-modal-in-reverse',
- scrolling ? 'overflow-y-auto' : 'overflow-y-hidden'
- );
-
- let backdropClasses = clsx(
- 'fixed inset-0 z-[1000] h-[100dvh] w-[100dvw]',
- allowBackgroundInteraction && 'pointer-events-none'
- );
-
- let paddingClasses = '';
- let headerClasses = clsx(
- (!topRightContent || topRightContent === 'close') ? '' : 'flex items-center justify-between gap-5'
- );
-
- if (stickyHeader) {
- headerClasses = clsx(
- headerClasses,
- 'sticky -top-px z-[300] -mb-4 bg-background pb-4!'
- );
- }
-
- switch (size) {
- case 'sm':
- modalClasses = clsx(
- modalClasses,
- 'max-w-[480px]'
- );
- backdropClasses = clsx(
- backdropClasses,
- 'p-4 md:p-[8vmin]'
- );
- paddingClasses = 'p-8';
- headerClasses = clsx(
- headerClasses,
- '-inset-x-8'
- );
- break;
-
- case 'md':
- modalClasses = clsx(
- modalClasses,
- 'max-w-[720px]'
- );
- backdropClasses = clsx(
- backdropClasses,
- 'p-4 md:p-[8vmin]'
- );
- paddingClasses = 'p-8';
- headerClasses = clsx(
- headerClasses,
- '-inset-x-8'
- );
- break;
-
- case 'lg':
- modalClasses = clsx(
- modalClasses,
- 'max-w-[1020px]'
- );
- backdropClasses = clsx(
- backdropClasses,
- 'p-4 md:p-[4vmin]'
- );
- paddingClasses = 'p-7';
- headerClasses = clsx(
- headerClasses,
- '-inset-x-8'
- );
- break;
-
- case 'xl':
- modalClasses = clsx(
- modalClasses,
- 'max-w-[1240px]0'
- );
- backdropClasses = clsx(
- backdropClasses,
- 'p-4 md:p-[3vmin]'
- );
- paddingClasses = 'p-10';
- headerClasses = clsx(
- headerClasses,
- '-inset-x-10 -top-10'
- );
- break;
-
- case 'full':
- modalClasses = clsx(
- modalClasses,
- 'h-full'
- );
- backdropClasses = clsx(
- backdropClasses,
- 'p-4 md:p-[3vmin]'
- );
- paddingClasses = 'p-10';
- headerClasses = clsx(
- headerClasses,
- '-inset-x-10'
- );
- break;
-
- case 'bleed':
- modalClasses = clsx(
- modalClasses,
- 'h-full'
- );
- paddingClasses = 'p-10';
- headerClasses = clsx(
- headerClasses,
- '-inset-x-10'
- );
- break;
-
- default:
- backdropClasses = clsx(
- backdropClasses,
- 'p-4 md:p-[8vmin]'
- );
- paddingClasses = 'p-8';
- headerClasses = clsx(
- headerClasses,
- '-inset-x-8'
- );
- break;
- }
-
- if (!padding) {
- paddingClasses = 'p-0';
- }
-
- modalClasses = clsx(
- modalClasses
- );
-
- headerClasses = clsx(
- headerClasses,
- paddingClasses,
- 'pb-0'
- );
-
- contentClasses = clsx(
- paddingClasses,
- 'py-0'
- );
-
- // Set bottom padding for backdrop when the menu is on
- backdropClasses = clsx(
- backdropClasses,
- 'max-[800px]:!pb-20'
- );
-
- const footerClasses = clsx(
- `${paddingClasses} ${stickyFooter ? 'py-6' : ''}`,
- 'flex w-full items-center justify-between'
- );
-
- contentClasses = clsx(
- contentClasses,
- ((size === 'full' || size === 'bleed' || height === 'full' || typeof height === 'number') && 'grow')
- );
-
- const handleBackdropClick = (e: React.MouseEvent) => {
- if (e.target === e.currentTarget && backDropClick) {
- removeModal();
- }
- };
-
- const modalStyles:{width?: string; height?: string; maxWidth?: string; maxHeight?: string;} = {};
-
- if (typeof width === 'number') {
- modalStyles.width = '100%';
- modalStyles.maxWidth = width + 'px';
- } else if (width === 'full') {
- modalClasses = clsx(
- modalClasses,
- 'w-full'
- );
- } else if (width === 'toSidebar') {
- modalClasses = clsx(
- modalClasses,
- 'w-full max-w-[calc(100dvw_-_280px)] lg:max-w-full min-[1280px]:max-w-[calc(100dvw_-_320px)]'
- );
- }
-
- if (typeof height === 'number') {
- modalStyles.height = '100%';
- modalStyles.maxHeight = height + 'px';
- } else if (height === 'full') {
- modalClasses = clsx(
- modalClasses,
- 'h-full'
- );
- }
-
- let footerContent;
- if (footer) {
- footerContent = footer;
- } else if (footer === false) {
- contentClasses += ' pb-0 ';
- } else {
- footerContent = (
-
-
- {leftButton}
-
-
- {cancelLabel && (
-
- {cancelLabel}
-
- )}
- {okLabel && (
-
- {okLoading && }
- {okLabel}
-
- )}
-
-
- );
- }
-
- footerContent = (stickyFooter ?
-
- {footerContent}
-
- :
- <>
- {footerContent}
- >
- );
-
- return (
- <>
-
-
-
- {header === false ? '' : (!topRightContent || topRightContent === 'close' ?
- (
- {title && {title} }
-
-
-
-
-
- )
- :
- (
- {title && {title} }
- {topRightContent}
- ))}
-
- {children}
-
- {footerContent}
-
-
-
- >
- );
-});
-
-Modal.displayName = 'Modal';
-
-export default Modal;
diff --git a/apps/admin-x-design-system/src/global/modal/preview-modal.stories.tsx b/apps/admin-x-design-system/src/global/modal/preview-modal.stories.tsx
deleted file mode 100644
index 2680ea0a9db..00000000000
--- a/apps/admin-x-design-system/src/global/modal/preview-modal.stories.tsx
+++ /dev/null
@@ -1,96 +0,0 @@
-import type {Meta, StoryContext, StoryObj} from '@storybook/react-vite';
-import {ReactNode} from 'react';
-
-import NiceModal from '@ebay/nice-modal-react';
-import PreviewModal, {PreviewModalProps} from './preview-modal';
-import {Text} from '@tryghost/shade/primitives';
-
-const PreviewModalContainer: React.FC = ({...props}) => {
- return (
- {
- NiceModal.show(PreviewModal, {...props});
- }}>Open preview modal
- );
-};
-
-const meta = {
- title: 'Global / Modal / Preview Modal',
- component: PreviewModal,
- tags: ['autodocs'],
- decorators: [(_story: () => ReactNode, context: StoryContext) => (
-
-
-
- )],
- argTypes: {
- sidebar: {control: 'text'},
- preview: {control: 'text'},
- sidebarButtons: {control: 'text'},
- sidebarHeader: {control: 'text'}
- }
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {
- args: {
- title: 'Preview modal',
- preview: (
-
- Scrollable preview area
-
- ),
- sidebar: (
-
- Scrollable sidebar area
-
- ),
- previewToolbarTabs: Preview tabs slot ,
- deviceSelector: Device selector slot
- }
-};
-
-export const NoPreviewToolbar: Story = {
- args: {
- ...Default.args,
- previewToolbar: false
- }
-};
-
-export const CustomButtons: Story = {
- args: {
- ...Default.args,
- cancelLabel: 'Meh',
- okLabel: 'Alrite',
- okVariant: 'default'
- }
-};
-
-export const CustomSidebarHeader: Story = {
- args: {
- ...Default.args,
- sidebarHeader: (
-
- A custom header here
-
- )
- }
-};
-
-export const FullBleed: Story = {
- args: {
- ...Default.args,
- size: 'bleed'
- }
-};
-
-export const BreadcrumbsToolbar: Story = {
- args: {
- ...Default.args,
- previewToolbarTabs: undefined,
- previewToolbarBreadcrumbs: (
- Toolbar breadcrumbs slot
- )
- }
-};
diff --git a/apps/admin-x-design-system/src/index.ts b/apps/admin-x-design-system/src/index.ts
index 350d99264ff..c31f30ffdf4 100644
--- a/apps/admin-x-design-system/src/index.ts
+++ b/apps/admin-x-design-system/src/index.ts
@@ -6,11 +6,6 @@ export {default as XLogo} from './assets/images/x-logo.svg?react';
export {default as DesktopChromeHeader} from './global/chrome/desktop-chrome-header';
export type {DesktopChromeHeaderProps} from './global/chrome/desktop-chrome-header';
-export {default as Modal, topLevelBackdropClasses} from './global/modal/modal';
-export type {ModalProps} from './global/modal/modal';
-export {default as PreviewModal, PreviewModalContent} from './global/modal/preview-modal';
-export type {PreviewModalProps} from './global/modal/preview-modal';
-
export {default as Banner} from './global/banner';
export type {BannerProps} from './global/banner';
export {default as ErrorBoundary} from './global/error-boundary';
@@ -21,10 +16,6 @@ export {default as Separator} from './global/separator';
export type {SeparatorProps} from './global/separator';
export {default as Tooltip} from './global/tooltip';
export type {TooltipProps} from './global/tooltip';
-export {default as PageHeader} from './global/layout/page-header';
-export type {PageHeaderProps} from './global/layout/page-header';
-export {default as Page} from './global/layout/page';
-export type {CustomGlobalAction} from './global/layout/page';
export {default as ViewContainer} from './global/layout/view-container';
export type {View} from './global/layout/view-container';
export type {PrimaryActionProps} from './global/layout/view-container';
@@ -33,10 +24,6 @@ export {default as SettingNavItem} from './settings/setting-nav-item';
export type {SettingNavItemProps} from './settings/setting-nav-item';
export {default as SettingNavSection} from './settings/setting-nav-section';
export type {SettingNavSectionProps} from './settings/setting-nav-section';
-export {default as SettingSection} from './settings/setting-section';
-export type {SettingSectionProps} from './settings/setting-section';
-export {default as SettingSectionHeader} from './settings/setting-section-header';
-export type {SettingSectionHeaderProps} from './settings/setting-section-header';
export {debounce} from './utils/debounce';
export {formatUrl} from './utils/format-url';
diff --git a/apps/admin-x-design-system/src/settings/setting-section-header.stories.tsx b/apps/admin-x-design-system/src/settings/setting-section-header.stories.tsx
deleted file mode 100644
index 09a8923a606..00000000000
--- a/apps/admin-x-design-system/src/settings/setting-section-header.stories.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import type {Meta, StoryObj} from '@storybook/react-vite';
-
-import SettingSectionHeader from './setting-section-header';
-
-const meta = {
- title: 'Settings / Setting Section / Header',
- component: SettingSectionHeader,
- tags: ['autodocs']
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {
- args: {
- title: 'Section header'
- }
-};
diff --git a/apps/admin-x-design-system/src/settings/setting-section-header.tsx b/apps/admin-x-design-system/src/settings/setting-section-header.tsx
deleted file mode 100644
index 1aff466f65e..00000000000
--- a/apps/admin-x-design-system/src/settings/setting-section-header.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-import clsx from 'clsx';
-import React from 'react';
-
-export interface SettingSectionHeaderProps {
- title: string;
- sticky?: boolean;
-}
-
-const SettingSectionHeader: React.FC = ({title, sticky = false}) => {
- const classNames = clsx(
- 'z-20 mb-px pb-10 text-2xl font-semibold tracking-tight',
- (sticky ? 'sticky top-0 mt-[calc(-8vmin-4px)] bg-gradient-to-t from-transparent via-white via-20% to-white pt-[calc(8vmin-4px)] dark:bg-black' : 'mt-[-5px]')
- );
-
- return (
- {title}
- );
-};
-
-export default SettingSectionHeader;
diff --git a/apps/admin-x-design-system/src/settings/setting-section.stories.tsx b/apps/admin-x-design-system/src/settings/setting-section.stories.tsx
deleted file mode 100644
index eb6c9157d7c..00000000000
--- a/apps/admin-x-design-system/src/settings/setting-section.stories.tsx
+++ /dev/null
@@ -1,21 +0,0 @@
-import {ReactNode} from 'react';
-import type {Meta, StoryObj} from '@storybook/react-vite';
-
-import SettingSection from './setting-section';
-
-const meta = {
- title: 'Settings / Setting Section',
- component: SettingSection,
- tags: ['autodocs'],
- decorators: [(_story: () => ReactNode) => {_story()}
]
-} satisfies Meta;
-
-export default meta;
-type Story = StoryObj;
-
-export const Default: Story = {
- args: {
- title: 'Section header',
- children: Setting groups render in this section.
- }
-};
diff --git a/apps/admin-x-design-system/src/settings/setting-section.tsx b/apps/admin-x-design-system/src/settings/setting-section.tsx
deleted file mode 100644
index 00c61fd7eec..00000000000
--- a/apps/admin-x-design-system/src/settings/setting-section.tsx
+++ /dev/null
@@ -1,29 +0,0 @@
-import clsx from 'clsx';
-import React from 'react';
-import SettingSectionHeader from './setting-section-header';
-
-export interface SettingSectionProps {
- title?: string;
- isVisible?: boolean;
- children?: React.ReactNode;
-}
-
-const SettingSection: React.FC = ({title, isVisible = true, children}) => {
- const containerClassNames = clsx(
- 'mb-[10vh]',
- isVisible ? '' : 'hidden'
- );
-
- return (
-
- {title &&
}
- {children &&
-
- {children}
-
- }
-
- );
-};
-
-export default SettingSection;
diff --git a/apps/admin-x-settings/src/components/searchable-section.tsx b/apps/admin-x-settings/src/components/searchable-section.tsx
index 0e62e6fb939..64fc756402a 100644
--- a/apps/admin-x-settings/src/components/searchable-section.tsx
+++ b/apps/admin-x-settings/src/components/searchable-section.tsx
@@ -1,11 +1,29 @@
-import {SettingSection, type SettingSectionProps} from '@tryghost/admin-x-design-system';
+import {Box, Stack, Text} from '@tryghost/shade/primitives';
import {useSearch} from './providers/settings-app-provider';
-const SearchableSection: React.FC & {keywords: string[]}> = ({keywords, ...props}) => {
+interface SearchableSectionProps {
+ children?: React.ReactNode;
+ keywords: string[];
+ title?: string;
+}
+
+const SearchableSection: React.FC = ({children, keywords, title}) => {
const {checkVisible, noResult} = useSearch();
+ const isVisible = checkVisible(keywords) || noResult;
return (
-
+
+ {title && (
+
+ {title}
+
+ )}
+ {children && (
+
+ {children}
+
+ )}
+
);
};
diff --git a/apps/admin-x-settings/src/components/settings/advanced/code/code-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/code/code-modal.tsx
index b614b469057..72566fa2b05 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/code/code-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/code/code-modal.tsx
@@ -4,8 +4,8 @@ import React, {useEffect, useMemo, useRef, useState} from 'react';
import useSettingGroup from '../../../../hooks/use-setting-group';
import {Button, Tabs, TabsContent, TabsList, TabsTrigger} from '@tryghost/shade/components';
import {Inline, Text} from '@tryghost/shade/primitives';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type ReactCodeMirrorRef} from '@uiw/react-codemirror';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {getSettingValues} from '@tryghost/admin-x-framework/api/settings';
import {useSaveButton} from '../../../../hooks/use-save-button';
@@ -62,7 +62,7 @@ const CodeModal: React.FC = ({afterClose}) => {
};
});
- return = ({afterClose}) => {
- ;
+ ;
};
export default NiceModal.create(CodeModal);
diff --git a/apps/admin-x-settings/src/components/settings/advanced/history-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/history-modal.tsx
index 1475cccbe4a..2ce1cb0cbd6 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/history-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/history-modal.tsx
@@ -4,8 +4,8 @@ import {type Action, getActionTitle, getContextResource, getLinkTarget, isBulkAc
import {ActionList, ActionListItem, ActionListItemContent, Avatar, Button, Field, FieldLabel, LoadingIndicator, MultiSelectCombobox, NoValueLabel, NoValueLabelIcon, Popover, PopoverContent, PopoverTrigger, Switch, inputSurface} from '@tryghost/shade/components';
import {ChevronDown, History, Pen, Plus, Trash2, X} from 'lucide-react';
import {Inline, Stack} from '@tryghost/shade/primitives';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type RoutingModalProps, useRouting} from '@tryghost/admin-x-framework/routing';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {type User} from '@tryghost/admin-x-framework/api/users';
import {formatNumber} from '@tryghost/shade/utils';
import {keepPreviousData} from '@tanstack/react-query';
@@ -311,7 +311,7 @@ const HistoryModal = NiceModal.create(({params}) => {
const hasActiveFilters = excludedEvents.length > 0 || excludedResources.length > 0 || params?.user;
return (
- {
updateRoute('history');
}}
@@ -387,7 +387,7 @@ const HistoryModal = NiceModal.create(({params}) => {
{data?.isEnd && data.actions.length > 0 && End of history log
}
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/advanced/integrations/add-integration-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/integrations/add-integration-modal.tsx
index 512587631d1..7bd9760857c 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/integrations/add-integration-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/integrations/add-integration-modal.tsx
@@ -3,8 +3,8 @@ import NiceModal, {useModal} from '@ebay/nice-modal-react';
import React, {useEffect, useState} from 'react';
import {Field, FieldError, FieldGroup, FieldLabel, Input} from '@tryghost/shade/components';
import {HostLimitError, useLimiter} from '../../../../hooks/use-limiter';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type RoutingModalProps, useRouting} from '@tryghost/admin-x-framework/routing';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {useCreateIntegration} from '@tryghost/admin-x-framework/api/integrations';
import {useHandleError} from '@tryghost/admin-x-framework/hooks';
@@ -32,7 +32,7 @@ const AddIntegrationModal: React.FC = () => {
}
}, [limiter, modal, updateRoute]);
- return {
updateRoute('integrations');
}}
@@ -65,7 +65,7 @@ const AddIntegrationModal: React.FC = () => {
- ;
+ ;
};
export default NiceModal.create(AddIntegrationModal);
diff --git a/apps/admin-x-settings/src/components/settings/advanced/integrations/content-api-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/integrations/content-api-modal.tsx
index 079732db332..f38d3b4753d 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/integrations/content-api-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/integrations/content-api-modal.tsx
@@ -3,7 +3,7 @@ import IntegrationHeader from './integration-header';
import NiceModal from '@ebay/nice-modal-react';
import {Button} from '@tryghost/shade/components';
import {LucideIcon} from '@tryghost/shade/utils';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {getGhostPaths} from '@tryghost/admin-x-framework/helpers';
import {useBrowseIntegrations} from '@tryghost/admin-x-framework/api/integrations';
import {useRouting} from '@tryghost/admin-x-framework/routing';
@@ -17,7 +17,7 @@ const ContentApiModal = NiceModal.create(() => {
const contentApiKey = integration?.api_keys?.find(key => key.type === 'content');
return (
- {
updateRoute('integrations');
}}
@@ -51,7 +51,7 @@ const ContentApiModal = NiceModal.create(() => {
{id: 'api-url', label: 'API URL', text: window.location.origin + getGhostPaths().subdir}
]} />
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/advanced/integrations/custom-integration-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/integrations/custom-integration-modal.tsx
index c93efd8f09c..13b11fa6a7b 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/integrations/custom-integration-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/integrations/custom-integration-modal.tsx
@@ -8,8 +8,8 @@ import {type APIKey, useRefreshAPIKey} from '@tryghost/admin-x-framework/api/api
import {Field, FieldError, FieldGroup, FieldLabel, Input} from '@tryghost/shade/components';
import {ImageUpload, ImageUploadAction, ImageUploadActions, ImageUploadDropzone, ImageUploadImage, ImageUploadPreview} from '@tryghost/shade/patterns';
import {type Integration, useBrowseIntegrations, useEditIntegration} from '@tryghost/admin-x-framework/api/integrations';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type RoutingModalProps, useRouting} from '@tryghost/admin-x-framework/routing';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {Trash2} from 'lucide-react';
import {getGhostPaths} from '@tryghost/admin-x-framework/helpers';
import {getImageUrl, useUploadImage} from '@tryghost/admin-x-framework/api/images';
@@ -80,7 +80,7 @@ const CustomIntegrationModalContent: React.FC<{integration: Integration}> = ({in
});
};
- return {
updateRoute('integrations');
}}
@@ -166,7 +166,7 @@ const CustomIntegrationModalContent: React.FC<{integration: Integration}> = ({in
- ;
+ ;
};
const CustomIntegrationModal: React.FC = ({params}) => {
diff --git a/apps/admin-x-settings/src/components/settings/advanced/integrations/first-promoter-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/integrations/first-promoter-modal.tsx
index 27ee2b6be59..ca819754ae0 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/integrations/first-promoter-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/integrations/first-promoter-modal.tsx
@@ -2,8 +2,8 @@ import BrandIcon from '../../../icons/brand-icon';
import IntegrationHeader from './integration-header';
import NiceModal from '@ebay/nice-modal-react';
import {Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSet, Input, Switch} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type Setting, getSettingValues, useEditSettings} from '@tryghost/admin-x-framework/api/settings';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {useEffect, useState} from 'react';
import {useGlobalData} from '../../../providers/global-data-provider';
import {useHandleError} from '@tryghost/admin-x-framework/hooks';
@@ -57,7 +57,7 @@ const FirstPromoterModal = NiceModal.create(() => {
};
return (
- {
updateRoute('integrations');
}}
@@ -108,7 +108,7 @@ const FirstPromoterModal = NiceModal.create(() => {
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/advanced/integrations/pintura-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/integrations/pintura-modal.tsx
index 1fecd8dc4fe..fcaf7935f16 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/integrations/pintura-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/integrations/pintura-modal.tsx
@@ -3,8 +3,8 @@ import IntegrationHeader from './integration-header';
import NiceModal from '@ebay/nice-modal-react';
import pinturaScreenshot from '../../../../assets/images/pintura-screenshot.png';
import {Dropzone, Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSet, Switch} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type Setting, getSettingValues, useEditSettings} from '@tryghost/admin-x-framework/api/settings';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {toast} from 'sonner';
import {useEffect, useState} from 'react';
import {useGlobalData} from '../../../providers/global-data-provider';
@@ -75,7 +75,7 @@ const PinturaModal = NiceModal.create(() => {
const isDirty = !(enabled === pinturaEnabled);
return (
- {
updateRoute('integrations');
}}
@@ -140,7 +140,7 @@ const PinturaModal = NiceModal.create(() => {
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/advanced/integrations/slack-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/integrations/slack-modal.tsx
index dece8590c39..d2d21986326 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/integrations/slack-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/integrations/slack-modal.tsx
@@ -4,7 +4,7 @@ import NiceModal from '@ebay/nice-modal-react';
import useSettingGroup from '../../../../hooks/use-setting-group';
import validator from 'validator';
import {Button, Field, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSet, Input} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {getSettingValues, useTestSlack} from '@tryghost/admin-x-framework/api/settings';
import {toast} from 'sonner';
import {useRouting} from '@tryghost/admin-x-framework/routing';
@@ -39,7 +39,7 @@ const SlackModal = NiceModal.create(() => {
const isDirty = localSettings.some(setting => setting.dirty);
return (
- {
updateRoute('integrations');
}}
@@ -81,7 +81,7 @@ const SlackModal = NiceModal.create(() => {
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/advanced/integrations/transistor-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/integrations/transistor-modal.tsx
index a036cb57ccb..5221d41e437 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/integrations/transistor-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/integrations/transistor-modal.tsx
@@ -5,8 +5,8 @@ import ConfirmationModal from '../../../confirmation-modal';
import IntegrationHeader from './integration-header';
import NiceModal from '@ebay/nice-modal-react';
import {Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldLegend, FieldSet, Switch} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type Setting, getSettingValues, useEditSettings} from '@tryghost/admin-x-framework/api/settings';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {getGhostPaths} from '@tryghost/admin-x-framework/helpers';
import {useBrowseIntegrations} from '@tryghost/admin-x-framework/api/integrations';
import {useEffect, useState} from 'react';
@@ -90,7 +90,7 @@ const TransistorModal = NiceModal.create(() => {
};
return (
- {
updateRoute('integrations');
}}
@@ -146,7 +146,7 @@ const TransistorModal = NiceModal.create(() => {
}
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/advanced/integrations/unsplash-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/integrations/unsplash-modal.tsx
index 2ec5e77a281..81c8e654a37 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/integrations/unsplash-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/integrations/unsplash-modal.tsx
@@ -2,8 +2,8 @@ import BrandIcon from '../../../icons/brand-icon';
import IntegrationHeader from './integration-header';
import NiceModal from '@ebay/nice-modal-react';
import {Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, Switch} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type Setting, getSettingValues, useEditSettings} from '@tryghost/admin-x-framework/api/settings';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {useEffect, useState} from 'react';
import {useGlobalData} from '../../../providers/global-data-provider';
import {useHandleError} from '@tryghost/admin-x-framework/hooks';
@@ -45,7 +45,7 @@ const UnsplashModal = NiceModal.create(() => {
const isDirty = !(enabled === unsplashEnabled);
return (
- {
updateRoute('integrations');
}}
@@ -73,7 +73,7 @@ const UnsplashModal = NiceModal.create(() => {
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/advanced/integrations/webhook-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/integrations/webhook-modal.tsx
index c7489b4da04..fa44425bf12 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/integrations/webhook-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/integrations/webhook-modal.tsx
@@ -3,7 +3,7 @@ import React from 'react';
import validator from 'validator';
import webhookEventOptions from './webhook-event-options';
import {Field, FieldError, FieldGroup, FieldLabel, Input, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {type Webhook, useCreateWebhook, useEditWebhook} from '@tryghost/admin-x-framework/api/webhooks';
import {useForm, useHandleError} from '@tryghost/admin-x-framework/hooks';
@@ -52,7 +52,7 @@ const WebhookModal: React.FC = ({webhook, integrationId}) =>
}
});
- return = ({webhook, integrationId}) =>
- ;
+ ;
};
export default NiceModal.create(WebhookModal);
diff --git a/apps/admin-x-settings/src/components/settings/advanced/integrations/zapier-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/integrations/zapier-modal.tsx
index 9d948c1487d..2dad2112bbf 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/integrations/zapier-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/integrations/zapier-modal.tsx
@@ -6,7 +6,7 @@ import NiceModal from '@ebay/nice-modal-react';
import ZapierLogo from '../../../../assets/images/zapier-logo.svg';
import {ActionList, ActionListItem, ActionListItemActions, ActionListItemContent, Button} from '@tryghost/shade/components';
import {LucideIcon} from '@tryghost/shade/utils';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {getGhostPaths} from '@tryghost/admin-x-framework/helpers';
import {useBrowseIntegrations} from '@tryghost/admin-x-framework/api/integrations';
import {useEffect, useState} from 'react';
@@ -68,7 +68,7 @@ const ZapierModal = NiceModal.create(() => {
};
return (
- {
updateRoute('integrations');
}}
@@ -130,7 +130,7 @@ const ZapierModal = NiceModal.create(() => {
))}
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/advanced/labs/feature-toggle.tsx b/apps/admin-x-settings/src/components/settings/advanced/labs/feature-toggle.tsx
index 549f313f906..54bb1a10fcc 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/labs/feature-toggle.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/labs/feature-toggle.tsx
@@ -2,7 +2,7 @@ import NiceModal, {useModal} from '@ebay/nice-modal-react';
import React from 'react';
import trackEvent from '../../../../utils/analytics';
import {type ConfigResponseType, configDataType} from '@tryghost/admin-x-framework/api/config';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {Switch} from '@tryghost/shade/components';
import {getSettingValue, useEditSettings} from '@tryghost/admin-x-framework/api/settings';
import {useGlobalData} from '../../../providers/global-data-provider';
@@ -55,7 +55,7 @@ const FeatureToggleConfirmationModal = NiceModal.create
{prompt}
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/advanced/labs/yaml-file-editor-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/labs/yaml-file-editor-modal.tsx
index 8d508d6ec12..ff266a3b8bf 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/labs/yaml-file-editor-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/labs/yaml-file-editor-modal.tsx
@@ -4,7 +4,7 @@ import React, {useEffect, useMemo, useState} from 'react';
import {APIError, JSONError} from '@tryghost/admin-x-framework/errors';
import {Button} from '@tryghost/shade/components';
import {Inline, Text} from '@tryghost/shade/primitives';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {getGhostPaths} from '@tryghost/admin-x-framework/helpers';
import {toast} from 'sonner';
import {useHandleError} from '@tryghost/admin-x-framework/hooks';
@@ -142,7 +142,7 @@ const YamlFileEditorModal: React.FC = ({
const canSave = !isLoading && !loadError && !isSaving;
return (
- = ({
)}
-
+
);
};
diff --git a/apps/admin-x-settings/src/components/settings/advanced/migration-tools/universal-import-modal.tsx b/apps/admin-x-settings/src/components/settings/advanced/migration-tools/universal-import-modal.tsx
index 6a9263a5262..a6ec042eeb7 100644
--- a/apps/admin-x-settings/src/components/settings/advanced/migration-tools/universal-import-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/advanced/migration-tools/universal-import-modal.tsx
@@ -2,7 +2,7 @@ import ConfirmationModal from '../../../confirmation-modal';
import NiceModal, {useModal} from '@ebay/nice-modal-react';
import React, {useState} from 'react';
import {Button, Dropzone} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {useHandleError} from '@tryghost/admin-x-framework/hooks';
import {useImportContent} from '@tryghost/admin-x-framework/api/db';
@@ -13,7 +13,7 @@ const UniversalImportModal: React.FC = () => {
const handleError = useHandleError();
return (
-
@@ -57,7 +57,7 @@ const UniversalImportModal: React.FC = () => {
-
+
);
};
diff --git a/apps/admin-x-settings/src/components/settings/email/newsletters/add-newsletter-modal.tsx b/apps/admin-x-settings/src/components/settings/email/newsletters/add-newsletter-modal.tsx
index 6d573a01c8d..a1f61270900 100644
--- a/apps/admin-x-settings/src/components/settings/email/newsletters/add-newsletter-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/email/newsletters/add-newsletter-modal.tsx
@@ -4,8 +4,8 @@ import React, {useEffect, useState} from 'react';
import useFeatureFlag from '../../../../hooks/use-feature-flag';
import {Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, Input, Switch, Textarea} from '@tryghost/shade/components';
import {HostLimitError, useLimiter} from '../../../../hooks/use-limiter';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type RoutingModalProps, useRouting} from '@tryghost/admin-x-framework/routing';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {formatNumber} from '@tryghost/shade/utils';
import {useAddNewsletter} from '@tryghost/admin-x-framework/api/newsletters';
import {useBrowseMembers} from '@tryghost/admin-x-framework/api/members';
@@ -89,7 +89,7 @@ const AddNewsletterModal: React.FC = () => {
return null;
}
- return {
updateRoute(returnRoute);
}}
@@ -130,7 +130,7 @@ const AddNewsletterModal: React.FC = () => {
updateForm(state => ({...state, optInExistingSubscribers: checked}))} />
- ;
+ ;
};
export default NiceModal.create(AddNewsletterModal);
diff --git a/apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx b/apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
index 8a3011f6b27..3f5e8edee26 100644
--- a/apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/email/newsletters/newsletter-detail-modal.tsx
@@ -14,7 +14,7 @@ import {HostLimitError, useLimiter} from '../../../../hooks/use-limiter';
import {ImageUpload, ImageUploadAction, ImageUploadActions, ImageUploadDropzone, ImageUploadImage, ImageUploadPreview} from '@tryghost/shade/patterns';
import {LucideIcon, formatNumber} from '@tryghost/shade/utils';
import {type Newsletter, useBrowseNewsletters, useEditNewsletter} from '@tryghost/admin-x-framework/api/newsletters';
-import {PreviewModalContent} from '@tryghost/admin-x-design-system';
+import {PreviewModalContent} from '../../preview-modal';
import {type RoutingModalProps, useRouting} from '@tryghost/admin-x-framework/routing';
import {Stack, Text} from '@tryghost/shade/primitives';
import {Trash2} from 'lucide-react';
diff --git a/apps/admin-x-settings/src/components/settings/general/about.tsx b/apps/admin-x-settings/src/components/settings/general/about.tsx
index ee2216380f6..1102a65c1c6 100644
--- a/apps/admin-x-settings/src/components/settings/general/about.tsx
+++ b/apps/admin-x-settings/src/components/settings/general/about.tsx
@@ -1,8 +1,8 @@
import NiceModal from '@ebay/nice-modal-react';
import {GhostLogo, Separator} from '@tryghost/shade/components';
import {LucideIcon} from '@tryghost/shade/utils';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type RoutingModalProps, useRouting} from '@tryghost/admin-x-framework/routing';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {linkToGitHubReleases} from '../../../utils/link-to-github-releases';
import {showDatabaseWarning} from '../../../utils/show-database-warning';
import {useGlobalData} from '../../providers/global-data-provider';
@@ -51,7 +51,7 @@ const AboutModal = NiceModal.create(() => {
}
return (
- {
updateRoute('');
}}
@@ -113,7 +113,7 @@ const AboutModal = NiceModal.create(() => {
Copyright © 2013 – {copyrightYear()} Ghost Foundation, released under the MIT license . Ghost is a registered trademark of Ghost Foundation Ltd .
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/general/invite-user-modal.tsx b/apps/admin-x-settings/src/components/settings/general/invite-user-modal.tsx
index 3488c9beeed..08c8439ce06 100644
--- a/apps/admin-x-settings/src/components/settings/general/invite-user-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/general/invite-user-modal.tsx
@@ -3,7 +3,7 @@ import validator from 'validator';
import {APIError, ValidationError} from '@tryghost/admin-x-framework/errors';
import {Field, FieldContent, FieldDescription, FieldError, FieldLabel, FieldLegend, FieldSeparator, FieldSet, Input, RadioGroup, RadioGroupItem} from '@tryghost/shade/components';
import {HostLimitError, useLimiter} from '../../../hooks/use-limiter';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {toast} from 'sonner';
import {useAddInvite, useBrowseInvites} from '@tryghost/admin-x-framework/api/invites';
import {useBrowseRoles} from '@tryghost/admin-x-framework/api/roles';
@@ -207,7 +207,7 @@ const InviteUserModal = NiceModal.create(() => {
}
return (
- {
updateRoute('staff');
}}
@@ -263,7 +263,7 @@ const InviteUserModal = NiceModal.create(() => {
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/general/user-detail-modal.tsx b/apps/admin-x-settings/src/components/settings/general/user-detail-modal.tsx
index 162dd4185eb..d34e18212cd 100644
--- a/apps/admin-x-settings/src/components/settings/general/user-detail-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/general/user-detail-modal.tsx
@@ -15,10 +15,10 @@ import {type ErrorMessages, useForm, useHandleError} from '@tryghost/admin-x-fra
import {HostLimitError, useLimiter} from '../../../hooks/use-limiter';
import {ImageUpload, ImageUploadAction, ImageUploadActions, ImageUploadDropzone, ImageUploadImage, ImageUploadPreview} from '@tryghost/shade/patterns';
import {LucideIcon} from '@tryghost/shade/utils';
-import {Modal} from '@tryghost/admin-x-design-system';
import {Pencil, Trash2} from 'lucide-react';
import {type RoutingModalProps, useRouting} from '@tryghost/admin-x-framework/routing';
import {SOCIAL_PLATFORM_CONFIGS, SOCIAL_PLATFORM_KEYS, getSocialValidationError} from '../../../utils/social-urls/index';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {Text} from '@tryghost/shade/primitives';
import {type User, canAccessSettings, hasAdminAccess, isAdminUser, isAuthorOrContributor, isEditorUser, isOwnerUser, useDeleteUser, useEditUser, useGetUserBySlug, useMakeOwner} from '@tryghost/admin-x-framework/api/users';
import {getImageUrl, useUploadImage} from '@tryghost/admin-x-framework/api/images';
@@ -323,7 +323,7 @@ const UserDetailModalContent: React.FC<{user: User; onDeletingUserChange: (isDel
};
return (
-
- {/* legacy Modal overlay is z-[1000]; keep the portalled menu above it */}
+ {/* legacy SettingsModal overlay is z-[1000]; keep the portalled menu above it */}
{canMakeOwner && (
@@ -449,7 +449,7 @@ const UserDetailModalContent: React.FC<{user: User; onDeletingUserChange: (isDel
-
+
);
};
diff --git a/apps/admin-x-settings/src/components/settings/growth/embed-signup/embed-signup-form-modal.tsx b/apps/admin-x-settings/src/components/settings/growth/embed-signup/embed-signup-form-modal.tsx
index 1afe4d27519..42c5046b5a6 100644
--- a/apps/admin-x-settings/src/components/settings/growth/embed-signup/embed-signup-form-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/growth/embed-signup/embed-signup-form-modal.tsx
@@ -2,7 +2,7 @@ import EmbedSignupPreview from './embed-signup-preview';
import EmbedSignupSidebar, {type SelectedLabelTypes} from './embed-signup-sidebar';
import NiceModal, {useModal} from '@ebay/nice-modal-react';
import useSettingGroup from '../../../../hooks/use-setting-group';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {generateCode} from '../../../../utils/generate-embed-code';
import {getSettingValues} from '@tryghost/admin-x-framework/api/settings';
import {useEffect, useState} from 'react';
@@ -93,7 +93,7 @@ const EmbedSignupFormModal = NiceModal.create(() => {
};
return (
- {
updateRoute('embed-signup-form');
}}
@@ -127,7 +127,7 @@ const EmbedSignupFormModal = NiceModal.create(() => {
setCustomColor={setCustomColor}
/>
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/growth/explore/testimonials-modal.tsx b/apps/admin-x-settings/src/components/settings/growth/explore/testimonials-modal.tsx
index 0fce4bf0250..289692498a7 100644
--- a/apps/admin-x-settings/src/components/settings/growth/explore/testimonials-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/growth/explore/testimonials-modal.tsx
@@ -5,7 +5,7 @@ import NiceModal, {useModal} from '@ebay/nice-modal-react';
import React from 'react';
import {Avatar, Field, FieldError, FieldGroup, FieldLabel, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea} from '@tryghost/shade/components';
import {Button, LoadingIndicator} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {getSettingValues} from '@tryghost/admin-x-framework/api/settings';
import {toast} from 'sonner';
import {useForm, useHandleError} from '@tryghost/admin-x-framework/hooks';
@@ -96,7 +96,7 @@ const TestimonialsModal = NiceModal.create(() => {
];
return (
- {
updateRoute('explore');
}}
@@ -233,7 +233,7 @@ const TestimonialsModal = NiceModal.create(() => {
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/growth/offers/add-offer-modal.tsx b/apps/admin-x-settings/src/components/settings/growth/offers/add-offer-modal.tsx
index 345349c1289..3a9ae2dff61 100644
--- a/apps/admin-x-settings/src/components/settings/growth/offers/add-offer-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/growth/offers/add-offer-modal.tsx
@@ -2,7 +2,7 @@ import PortalFrame from '../../membership/portal/portal-frame';
import {Button, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, Input, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, RadioGroup, RadioGroupItem, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Textarea} from '@tryghost/shade/components';
import {type ErrorMessages, useForm} from '@tryghost/admin-x-framework/hooks';
import {JSONError} from '@tryghost/admin-x-framework/errors';
-import {PreviewModalContent} from '@tryghost/admin-x-design-system';
+import {PreviewModalContent} from '../../preview-modal';
import {formatNumber} from '@tryghost/shade/utils';
import {getHomepageUrl} from '@tryghost/admin-x-framework/api/site';
import {getOfferPortalPreviewUrl, type offerPortalPreviewUrlTypes} from '../../../../utils/get-offers-portal-preview-url';
diff --git a/apps/admin-x-settings/src/components/settings/growth/offers/edit-offer-modal.tsx b/apps/admin-x-settings/src/components/settings/growth/offers/edit-offer-modal.tsx
index e32eea9eeff..615321fa7e3 100644
--- a/apps/admin-x-settings/src/components/settings/growth/offers/edit-offer-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/growth/offers/edit-offer-modal.tsx
@@ -6,7 +6,7 @@ import {Button, Field, FieldDescription, FieldError, FieldGroup, FieldLabel, Inp
import {type ErrorMessages, useForm, useHandleError} from '@tryghost/admin-x-framework/hooks';
import {JSONError} from '@tryghost/admin-x-framework/errors';
import {type Offer, useBrowseOffersById, useEditOffer} from '@tryghost/admin-x-framework/api/offers';
-import {PreviewModalContent} from '@tryghost/admin-x-design-system';
+import {PreviewModalContent} from '../../preview-modal';
import {createOfferRedemptionFilterUrl} from './offer-helpers';
import {formatNumber} from '@tryghost/shade/utils';
import {getHomepageUrl} from '@tryghost/admin-x-framework/api/site';
diff --git a/apps/admin-x-settings/src/components/settings/growth/offers/edit-retention-offer-modal.tsx b/apps/admin-x-settings/src/components/settings/growth/offers/edit-retention-offer-modal.tsx
index f07fc0cf8c5..5a0579aa70b 100644
--- a/apps/admin-x-settings/src/components/settings/growth/offers/edit-retention-offer-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/growth/offers/edit-retention-offer-modal.tsx
@@ -4,7 +4,7 @@ import {type ErrorMessages, useForm} from '@tryghost/admin-x-framework/hooks';
import {Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, Input, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, RadioGroup, RadioGroupItem, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Switch, Textarea} from '@tryghost/shade/components';
import {JSONError} from '@tryghost/admin-x-framework/errors';
import {type Offer, useAddOffer, useBrowseOffers, useEditOffer, useInvalidateOffers} from '@tryghost/admin-x-framework/api/offers';
-import {PreviewModalContent} from '@tryghost/admin-x-design-system';
+import {PreviewModalContent} from '../../preview-modal';
import {createOfferRedemptionsFilterUrl, formatOfferTimestamp, generateRetentionOfferName} from './offer-helpers';
import {formatNumber} from '@tryghost/shade/utils';
import {getOfferPortalPreviewUrl, type offerPortalPreviewUrlTypes} from '../../../../utils/get-offers-portal-preview-url';
diff --git a/apps/admin-x-settings/src/components/settings/growth/offers/offer-success.tsx b/apps/admin-x-settings/src/components/settings/growth/offers/offer-success.tsx
index 4461675ccb5..125795635a3 100644
--- a/apps/admin-x-settings/src/components/settings/growth/offers/offer-success.tsx
+++ b/apps/admin-x-settings/src/components/settings/growth/offers/offer-success.tsx
@@ -2,8 +2,8 @@ import BrandIcon from '../../../icons/brand-icon';
import SettingsBreadcrumbs from '../../settings-breadcrumbs';
import {Button, Input} from '@tryghost/shade/components';
import {LucideIcon} from '@tryghost/shade/utils';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type Offer, useBrowseOffersById} from '@tryghost/admin-x-framework/api/offers';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {currencyToDecimal} from '../../../../utils/currency';
import {formatNumber} from '@tryghost/shade/utils';
import {getHomepageUrl} from '@tryghost/admin-x-framework/api/site';
@@ -69,7 +69,7 @@ const OfferSuccess: React.FC<{id: string}> = ({id}) => {
window.open(`http://www.linkedin.com/shareArticle?mini=true&url=${encodeURI(offerLink)}&title=${getShareText()}`, '_blank');
};
- return {
updateRoute('offers');
}}
@@ -105,7 +105,7 @@ const OfferSuccess: React.FC<{id: string}> = ({id}) => {
- ;
+ ;
};
export default OfferSuccess;
diff --git a/apps/admin-x-settings/src/components/settings/growth/offers/offers-index.tsx b/apps/admin-x-settings/src/components/settings/growth/offers/offers-index.tsx
index 15b13eb01fa..1c08d1260f1 100644
--- a/apps/admin-x-settings/src/components/settings/growth/offers/offers-index.tsx
+++ b/apps/admin-x-settings/src/components/settings/growth/offers/offers-index.tsx
@@ -1,9 +1,9 @@
import {Badge, Button, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger, Table, TableBody, TableCell, TableHead, TableHeader, TableRow} from '@tryghost/shade/components';
import {Inline, Stack} from '@tryghost/shade/primitives';
import {LucideIcon, formatNumber} from '@tryghost/shade/utils';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type Offer, useBrowseOffers} from '@tryghost/admin-x-framework/api/offers';
import {type RetentionOffer, getRetentionOffers} from './offers-retention';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {type Tier, getPaidActiveTiers, useBrowseTiers} from '@tryghost/admin-x-framework/api/tiers';
import {createOfferRedemptionFilterUrl, createOfferRedemptionsFilterUrl} from './offer-helpers';
import {currencyToDecimal, getSymbol} from '../../../../utils/currency';
@@ -410,7 +410,7 @@ export const OffersIndexModal: React.FC = () => {
;
- return {
updateRoute('offers');
}}
@@ -428,5 +428,5 @@ export const OffersIndexModal: React.FC = () => {
{listLayoutOutput}
- ;
+ ;
};
diff --git a/apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx b/apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx
index ae76b536c08..8ddee4ae9e1 100644
--- a/apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx
+++ b/apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal-confirm.tsx
@@ -6,7 +6,7 @@ import trackEvent from '../../../../utils/analytics';
import {Button} from '@tryghost/shade/components';
import {type EditOrAddRecommendation, useAddRecommendation} from '@tryghost/admin-x-framework/api/recommendations';
import {LucideIcon} from '@tryghost/shade/utils';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {toast} from 'sonner';
import {useForm, useHandleError} from '@tryghost/admin-x-framework/hooks';
import {useRouting} from '@tryghost/admin-x-framework/routing';
@@ -73,7 +73,7 @@ const AddRecommendationModalConfirm: React.FC = ({r
);
- return {
// Closed without saving: reset route
updateRoute('recommendations');
@@ -113,7 +113,7 @@ const AddRecommendationModalConfirm: React.FC = ({r
}}
>
- ;
+ ;
};
export default NiceModal.create(AddRecommendationModalConfirm);
diff --git a/apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx b/apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx
index 7939efebc95..f1cd4df437d 100644
--- a/apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/growth/recommendations/add-recommendation-modal.tsx
@@ -5,8 +5,8 @@ import {AlreadyExistsError} from '@tryghost/admin-x-framework/errors';
import {type EditOrAddRecommendation, useCheckRecommendation} from '@tryghost/admin-x-framework/api/recommendations';
import {type ErrorMessages, useForm} from '@tryghost/admin-x-framework/hooks';
import {Field, FieldDescription, FieldError, FieldGroup, FieldLabel, Input, LoadingIndicator} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type RoutingModalProps, useRouting} from '@tryghost/admin-x-framework/routing';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {formatUrl} from '../../../../utils/format-url';
import {toast} from 'sonner';
@@ -157,7 +157,7 @@ const AddRecommendationModal: React.FC {
// Closed without saving: reset route
updateRoute('recommendations');
@@ -173,10 +173,10 @@ const AddRecommendationModal: React.FC
- ;
+ ;
}
- return {
// Closed without saving: reset route
updateRoute('recommendations');
@@ -221,7 +221,7 @@ const AddRecommendationModal: React.FC{errors.url} : Need inspiration? Explore thousands of sites to recommend }
- ;
+ ;
};
export default NiceModal.create(AddRecommendationModal);
diff --git a/apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx b/apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx
index 56154d0977d..320d2b2ca1d 100644
--- a/apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/growth/recommendations/edit-recommendation-modal.tsx
@@ -3,9 +3,9 @@ import NiceModal, {useModal} from '@ebay/nice-modal-react';
import React from 'react';
import RecommendationDescriptionForm, {validateDescriptionForm} from './recommendation-description-form';
import {Button} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type Recommendation, useDeleteRecommendation, useEditRecommendation} from '@tryghost/admin-x-framework/api/recommendations';
import {type RoutingModalProps, useRouting} from '@tryghost/admin-x-framework/routing';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {toast} from 'sonner';
import {useForm, useHandleError} from '@tryghost/admin-x-framework/hooks';
@@ -60,7 +60,7 @@ const EditRecommendationModal: React.FCDelete
);
- return {
// Closed without saving: reset route
updateRoute('recommendations');
@@ -86,7 +86,7 @@ const EditRecommendationModal: React.FC
- ;
+ ;
};
export default NiceModal.create(EditRecommendationModal);
diff --git a/apps/admin-x-settings/src/components/settings/membership/custom-fields/custom-field-modal.tsx b/apps/admin-x-settings/src/components/settings/membership/custom-fields/custom-field-modal.tsx
index bb8c8da04fa..1aa410becab 100644
--- a/apps/admin-x-settings/src/components/settings/membership/custom-fields/custom-field-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/membership/custom-fields/custom-field-modal.tsx
@@ -4,7 +4,7 @@ import NiceModal, {useModal} from '@ebay/nice-modal-react';
import React from 'react';
import {Button, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, Field, FieldDescription, FieldError, FieldGroup, FieldLabel, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue} from '@tryghost/shade/components';
import {LucideIcon} from '@tryghost/shade/utils';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {ValidationError, getErrorMessage} from '@tryghost/admin-x-framework/errors';
import {memberCustomFieldUserTypes, useCreateMemberCustomField, useDeleteMemberCustomField, useEditMemberCustomField, userTypeForField} from '@tryghost/admin-x-framework/api/member-custom-fields';
import {toast} from 'sonner';
@@ -180,7 +180,7 @@ const CustomFieldModal = NiceModal.create<{field?: MemberCustomField}>(({field})
);
return (
- (({field})
{isEdit && Type can’t be changed after creation }
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/membership/member-emails/welcome-email-modal.tsx b/apps/admin-x-settings/src/components/settings/membership/member-emails/welcome-email-modal.tsx
index ed0accb5c74..dd668fb02b0 100644
--- a/apps/admin-x-settings/src/components/settings/membership/member-emails/welcome-email-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/membership/member-emails/welcome-email-modal.tsx
@@ -6,7 +6,7 @@ import MemberEmailEditor from './member-email-editor';
import WelcomeEmailPreviewFrame from './welcome-email-preview-frame';
import {DirtyConfirmDialog, useDirtyConfirmation} from '@tryghost/shade/patterns';
import {FieldError, Input} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {getSettingValues} from '@tryghost/admin-x-framework/api/settings';
import {getWelcomeEmailValidationErrors} from './welcome-email-validation';
import {useBrowseAutomatedEmails, useEditAutomatedEmail, usePreviewWelcomeEmail} from '@tryghost/admin-x-framework/api/automated-emails';
@@ -203,7 +203,7 @@ const WelcomeEmailModal = NiceModal.create(({emailType =
}, [setFormState, updateForm]);
return (
- {
updateRoute('memberemails');
}}
@@ -330,7 +330,7 @@ const WelcomeEmailModal = NiceModal.create(({emailType =
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/membership/portal/portal-modal.tsx b/apps/admin-x-settings/src/components/settings/membership/portal/portal-modal.tsx
index 721773d4023..1a621654971 100644
--- a/apps/admin-x-settings/src/components/settings/membership/portal/portal-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/membership/portal/portal-modal.tsx
@@ -7,7 +7,7 @@ import React, {useEffect, useState} from 'react';
import SignupOptions from './signup-options';
import useQueryParams from '../../../../hooks/use-query-params';
import {type Dirtyable, useForm, useHandleError} from '@tryghost/admin-x-framework/hooks';
-import {PreviewModalContent} from '@tryghost/admin-x-design-system';
+import {PreviewModalContent} from '../../preview-modal';
import {type Setting, type SettingValue, getSettingValues, useEditSettings} from '@tryghost/admin-x-framework/api/settings';
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@tryghost/shade/components';
import {type Tier, useBrowseTiers, useEditTier} from '@tryghost/admin-x-framework/api/tiers';
diff --git a/apps/admin-x-settings/src/components/settings/membership/stripe/stripe-connect-modal.tsx b/apps/admin-x-settings/src/components/settings/membership/stripe/stripe-connect-modal.tsx
index ef006400c59..de56923381f 100644
--- a/apps/admin-x-settings/src/components/settings/membership/stripe/stripe-connect-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/membership/stripe/stripe-connect-modal.tsx
@@ -13,7 +13,7 @@ import {Button, Field, FieldError, FieldGroup, FieldLabel, Input, Switch, Textar
import {HostLimitError, useLimiter} from '../../../../hooks/use-limiter';
import {JSONError} from '@tryghost/admin-x-framework/errors';
import {LucideIcon} from '@tryghost/shade/utils';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {Text} from '@tryghost/shade/primitives';
import {checkStripeEnabled, getSettingValue, getSettingValues, useDeleteStripeSettings, useEditSettings} from '@tryghost/admin-x-framework/api/settings';
import {getGhostPaths} from '@tryghost/admin-x-framework/helpers';
@@ -313,7 +313,7 @@ const StripeConnectModal: React.FC = () => {
contents = ;
}
- return {
updateRoute('tiers');
}}
@@ -325,7 +325,7 @@ const StripeConnectModal: React.FC = () => {
hideXOnMobile
>
{contents}
- ;
+ ;
};
export default NiceModal.create(StripeConnectModal);
diff --git a/apps/admin-x-settings/src/components/settings/membership/tiers/tier-detail-modal.tsx b/apps/admin-x-settings/src/components/settings/membership/tiers/tier-detail-modal.tsx
index c092f9f17ee..dc9d34ba454 100644
--- a/apps/admin-x-settings/src/components/settings/membership/tiers/tier-detail-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/membership/tiers/tier-detail-modal.tsx
@@ -9,8 +9,8 @@ import useUrlInput from '../../../../hooks/use-url-input';
import {Button, Combobox, ComboboxContent, ComboboxTrigger, ComboboxValue, Field, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSet, Input, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, MultiSelectCombobox, SortableList, Switch} from '@tryghost/shade/components';
import {type ErrorMessages, useForm, useHandleError} from '@tryghost/admin-x-framework/hooks';
import {LucideIcon} from '@tryghost/shade/utils';
-import {Modal} from '@tryghost/admin-x-design-system';
import {type RoutingModalProps, useRouting} from '@tryghost/admin-x-framework/routing';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {Text} from '@tryghost/shade/primitives';
import {type Tier, useAddTier, useBrowseTiers, useEditTier} from '@tryghost/admin-x-framework/api/tiers';
import {currencies, currencySelectGroups, validateCurrencyAmount} from '../../../../utils/currency';
@@ -179,7 +179,7 @@ const TierDetailModalContent: React.FC<{tier?: Tier}> = ({tier}) => {
}
}
- return {
updateRoute('tiers');
}}
@@ -382,7 +382,7 @@ const TierDetailModalContent: React.FC<{tier?: Tier}> = ({tier}) => {
- ;
+ ;
};
const TierDetailModal: React.FC = ({params}) => {
diff --git a/apps/admin-x-design-system/src/global/modal/preview-modal.tsx b/apps/admin-x-settings/src/components/settings/preview-modal.tsx
similarity index 69%
rename from apps/admin-x-design-system/src/global/modal/preview-modal.tsx
rename to apps/admin-x-settings/src/components/settings/preview-modal.tsx
index 568b266e149..409d4605ee0 100644
--- a/apps/admin-x-design-system/src/global/modal/preview-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/preview-modal.tsx
@@ -1,11 +1,11 @@
-import NiceModal, {useModal} from '@ebay/nice-modal-react';
-import clsx from 'clsx';
import React, {useEffect} from 'react';
-import Modal, {ModalSize} from './modal';
+import {ExternalLink} from 'lucide-react';
+import {useModal} from '@ebay/nice-modal-react';
+
+import {Box, Inline, Text, type TextElement, type TextLeading, type TextSize} from '@tryghost/shade/primitives';
import {Button, type ButtonProps} from '@tryghost/shade/components';
-import {DirtyConfirmDialog, useDirtyConfirmation} from '@tryghost/shade/patterns';
-import {Inline, Text, type TextElement, type TextLeading, type TextSize} from '@tryghost/shade/primitives';
-import {LucideIcon, useGlobalDirtyState} from '@tryghost/shade/utils';
+import {DirtyConfirmDialog, SettingsModal, type SettingsModalSize, useDirtyConfirmation} from '@tryghost/shade/patterns';
+import {cn, useGlobalDirtyState} from '@tryghost/shade/utils';
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6;
@@ -36,20 +36,24 @@ const headingLeading: Record = {
6: 'body'
};
+/**
+ * Compatibility shell for settings preview modals while the legacy NiceModal
+ * flows are migrated to consumer-controlled Shade compositions.
+ */
export interface PreviewModalProps {
testId?: string;
title?: string;
titleHeadingLevel?: HeadingLevel;
- size?: ModalSize;
+ size?: SettingsModalSize;
width?: 'full' | number;
height?: 'full' | number;
sidebar?: boolean | React.ReactNode;
preview?: React.ReactNode;
- dirty?: boolean
+ dirty?: boolean;
cancelLabel?: string;
okLabel?: string;
okVariant?: ButtonProps['variant'];
- buttonsDisabled?: boolean
+ buttonsDisabled?: boolean;
previewToolbar?: boolean;
leftToolbar?: boolean;
rightToolbar?: boolean;
@@ -142,12 +146,12 @@ export const PreviewModalContent: React.FC = ({
let previewBgClass = '';
if (previewBgColor === 'grey') {
- previewBgClass = 'bg-grey-50 dark:bg-black';
+ previewBgClass = 'bg-preview-canvas';
} else if (previewBgColor === 'greygradient') {
- previewBgClass = 'bg-gradient-to-tr from-white to-[#f9f9fa] dark:from-grey-950 dark:to-black';
+ previewBgClass = 'bg-gradient-to-tr from-preview-gradient-start to-preview-gradient-end';
}
- const containerClasses = clsx(
+ const containerClasses = cn(
'absolute inset-y-0 right-[400px] left-0 flex w-full min-w-100 grow flex-col overflow-y-auto',
previewBgClass
);
@@ -155,27 +159,27 @@ export const PreviewModalContent: React.FC = ({
let viewSiteButton;
if (siteLink) {
viewSiteButton = (
-
+
+ View site
+
);
}
preview = (
-
- {previewToolbar &&
- {leftToolbar &&
+
+ {previewToolbar &&
+ {leftToolbar &&
{toolbarLeft}
-
}
- {rightToolbar &&
+ }
+ {rightToolbar &&
{deviceSelector}
{viewSiteButton}
-
}
- }
-
+ }
+ }
+
{preview}
-
-
+
+
);
}
@@ -187,7 +191,7 @@ export const PreviewModalContent: React.FC = ({
});
return (
- = ({
width={width}
hideXOnMobile
>
-
-
+
+
{preview}
-
+
{sidebar &&
-
+
{sidebarHeader ? sidebarHeader : (
-
+
= ({
{okLabel}
)}
-
+
)}
-
+
{sidebar}
-
-
+
+
}
-
+
-
+
);
};
-
-export default NiceModal.create(PreviewModalContent);
diff --git a/apps/admin-x-settings/src/components/settings/site/announcement-bar-modal.tsx b/apps/admin-x-settings/src/components/settings/site/announcement-bar-modal.tsx
index f0598d1dac8..bfcf7229309 100644
--- a/apps/admin-x-settings/src/components/settings/site/announcement-bar-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/site/announcement-bar-modal.tsx
@@ -6,7 +6,7 @@ import React, {useRef, useState} from 'react';
import useSettingGroup from '../../../hooks/use-setting-group';
import {Checkbox, Field, FieldGroup, FieldLabel, FieldLegend, FieldSet, PreviewChrome, Tabs, TabsList, TabsTrigger, ToggleGroup, ToggleGroupItem} from '@tryghost/shade/components';
import {Laptop, Smartphone} from 'lucide-react';
-import {PreviewModalContent} from '@tryghost/admin-x-design-system';
+import {PreviewModalContent} from '../preview-modal';
import {debounce} from '../../../utils/debounce';
import {getHomepageUrl} from '@tryghost/admin-x-framework/api/site';
import {getSettingValues} from '@tryghost/admin-x-framework/api/settings';
diff --git a/apps/admin-x-settings/src/components/settings/site/design-modal.tsx b/apps/admin-x-settings/src/components/settings/site/design-modal.tsx
index 411130567d7..d4e073851a5 100644
--- a/apps/admin-x-settings/src/components/settings/site/design-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/site/design-modal.tsx
@@ -6,7 +6,7 @@ import useQueryParams from '../../../hooks/use-query-params';
import {type CustomThemeSetting, useBrowseCustomThemeSettings, useEditCustomThemeSettings} from '@tryghost/admin-x-framework/api/custom-theme-settings';
import {Laptop, Smartphone} from 'lucide-react';
import {PreviewChrome, Tabs, TabsContent, TabsList, TabsTrigger, ToggleGroup, ToggleGroupItem} from '@tryghost/shade/components';
-import {PreviewModalContent} from '@tryghost/admin-x-design-system';
+import {PreviewModalContent} from '../preview-modal';
import {type Setting, type SettingValue, getSettingValues, useEditSettings} from '@tryghost/admin-x-framework/api/settings';
import {getHomepageUrl} from '@tryghost/admin-x-framework/api/site';
import {useBrowsePosts} from '@tryghost/admin-x-framework/api/posts';
diff --git a/apps/admin-x-settings/src/components/settings/site/navigation-modal.tsx b/apps/admin-x-settings/src/components/settings/site/navigation-modal.tsx
index 6308330e698..efaccec7bc4 100644
--- a/apps/admin-x-settings/src/components/settings/site/navigation-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/site/navigation-modal.tsx
@@ -2,7 +2,7 @@ import NavigationEditForm from './navigation/navigation-edit-form';
import NiceModal, {useModal} from '@ebay/nice-modal-react';
import useNavigationEditor, {type NavigationItem} from '../../../hooks/site/use-navigation-editor';
import useSettingGroup from '../../../hooks/use-setting-group';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import {Tabs, TabsContent, TabsList, TabsTrigger} from '@tryghost/shade/components';
import {getSettingValues} from '@tryghost/admin-x-framework/api/settings';
import {useCallback, useMemo, useState} from 'react';
@@ -45,7 +45,7 @@ const NavigationModal = NiceModal.create(() => {
const [selectedTab, setSelectedTab] = useState('primary-nav');
return (
- {
updateRoute('navigation');
}}
@@ -76,7 +76,7 @@ const NavigationModal = NiceModal.create(() => {
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/site/theme-modal.tsx b/apps/admin-x-settings/src/components/settings/site/theme-modal.tsx
index f002f527ee2..a84da87d125 100644
--- a/apps/admin-x-settings/src/components/settings/site/theme-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/site/theme-modal.tsx
@@ -10,8 +10,8 @@ import ThemePreview from './theme/theme-preview';
import {Button, Dropzone, LoadingIndicator, Tabs, TabsList, TabsTrigger} from '@tryghost/shade/components';
import {type InstalledTheme, type Theme, type ThemesInstallResponseType, isDefaultOrLegacyTheme, useActivateTheme, useBrowseThemes, useInstallTheme, useUploadTheme} from '@tryghost/admin-x-framework/api/themes';
import {JSONError} from '@tryghost/admin-x-framework/errors';
-import {Modal, PageHeader} from '@tryghost/admin-x-design-system';
import {type OfficialTheme} from '../../providers/settings-app-provider';
+import {PageHeader, SettingsModal} from '@tryghost/shade/patterns';
import {toast} from 'sonner';
import {useCheckThemeLimitError} from '../../../hooks/use-check-theme-limit-error';
import {useHandleError} from '@tryghost/admin-x-framework/hooks';
@@ -258,7 +258,14 @@ const ThemeToolbar: React.FC = ({
;
return (<>
-
+
+
+ {left}
+
+
+ {right}
+
+
@@ -502,7 +509,7 @@ const ChangeThemeModal: React.FC = ({source, themeRef}) =
}
return (
- {
updateRoute('');
}}
@@ -553,7 +560,7 @@ const ChangeThemeModal: React.FC = ({source, themeRef}) =
}
-
+
);
};
diff --git a/apps/admin-x-settings/src/components/settings/site/theme/theme-editor-confirm-modal.tsx b/apps/admin-x-settings/src/components/settings/site/theme/theme-editor-confirm-modal.tsx
index 4e88afd4773..296457de574 100644
--- a/apps/admin-x-settings/src/components/settings/site/theme/theme-editor-confirm-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/site/theme/theme-editor-confirm-modal.tsx
@@ -1,6 +1,6 @@
import NiceModal, {useModal} from '@ebay/nice-modal-react';
import React from 'react';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
import type {ButtonProps} from '@tryghost/shade/components';
export type ThemeEditorConfirmModalProps = {
@@ -26,7 +26,7 @@ const ThemeEditorConfirmModal = NiceModal.create((
};
return (
- ((
{prompt}
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/site/theme/theme-editor-input-modal.tsx b/apps/admin-x-settings/src/components/settings/site/theme/theme-editor-input-modal.tsx
index 07185c570a5..b2467573539 100644
--- a/apps/admin-x-settings/src/components/settings/site/theme/theme-editor-input-modal.tsx
+++ b/apps/admin-x-settings/src/components/settings/site/theme/theme-editor-input-modal.tsx
@@ -1,7 +1,7 @@
import NiceModal, {useModal} from '@ebay/nice-modal-react';
import React, {useState} from 'react';
import {Field, FieldLabel, Input} from '@tryghost/shade/components';
-import {Modal} from '@tryghost/admin-x-design-system';
+import {SettingsModal} from '@tryghost/shade/patterns';
export type ThemeEditorInputModalProps = {
title: string;
@@ -31,7 +31,7 @@ const ThemeEditorInputModal = NiceModal.create(({
};
return (
- (({
setValue(event.target.value)} />
-
+
);
});
diff --git a/apps/admin-x-settings/src/components/settings/site/theme/theme-preview.tsx b/apps/admin-x-settings/src/components/settings/site/theme/theme-preview.tsx
index 04ea46f00dd..af76bda0ffe 100644
--- a/apps/admin-x-settings/src/components/settings/site/theme/theme-preview.tsx
+++ b/apps/admin-x-settings/src/components/settings/site/theme/theme-preview.tsx
@@ -4,7 +4,7 @@ import {Button, Field, FieldLabel, PreviewChrome, Select, SelectContent, SelectI
import {Inline} from '@tryghost/shade/primitives';
import {LucideIcon} from '@tryghost/shade/utils';
import {type OfficialTheme, type ThemeVariant} from '../../../providers/settings-app-provider';
-import {PageHeader} from '@tryghost/admin-x-design-system';
+import {PageHeader} from '@tryghost/shade/patterns';
import {type Theme, isDefaultOrLegacyTheme} from '@tryghost/admin-x-framework/api/themes';
const hasVariants = (theme: OfficialTheme) => theme.variants && theme.variants.length > 0;
@@ -122,8 +122,15 @@ const ThemePreview: React.FC<{
return (
-
-
+
+
+ {left}
+
+
+ {right}
+
+
+
{previewMode === 'desktop' ?