Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ Conventions:
- **Use:** `admin-x-framework` for API hooks (`useBrowse`, `useEdit`, etc.)
- **Use:** `shade` design system for new components (not admin-x-design-system)
- **Translations:** Add to `packages/i18n/locales/en/ghost.json`
- **Deploy skew:** Ghost Admin and Ghost core deploy independently. New admin UI that depends on new settings, endpoints, or config must feature-detect backend support (e.g. settings-key presence in the browse response, as in `social-accounts.tsx`) and hide or no-op when absent. Labs flags alone are not a deploy-skew guard. Add an acceptance test for the “backend not deployed yet” case.

### When Working on Public UI
- **Edit:** `apps/portal`, `apps/comments-ui`, etc.
Expand All @@ -187,6 +188,8 @@ Conventions:
- **Services:** `ghost/core/core/server/services/`
- **Models:** `ghost/core/core/server/models/`
- **Frontend & theme rendering:** `ghost/core/core/frontend/`
- **TypeScript by default:** New code under `ghost/core/core/server/services/` is TypeScript unless extending an existing JS module. Follow the gifts/donations pattern: domain logic as `.ts` with named exports; thin CJS `index.js` / `*-wrapper.js` only where boot/`require` still needs them.
- **Service init:** New services get an explicit `init()` call from `ghost/core/core/boot.js` (same Promise.all as donations/gifts). Keep the wrapper’s `init()` idempotent so early callers are safe, but boot owns construction — not first request.

### Design System Usage
- **New components:** Use `shade` (shadcn/ui-inspired)
Expand Down
8 changes: 4 additions & 4 deletions apps/shade/src/components/ui/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const cardVariants = cva(
{
variants: {
variant: {
outline: 'rounded-xl border transition-all hover:shadow-xs',
outline: 'rounded-xl border border-border-default transition-all hover:shadow-xs',
plain: ''
}
},
Expand Down Expand Up @@ -44,7 +44,7 @@ const cardHeaderVariants = cva(
variants: {
variant: {
outline: 'p-6',
plain: 'border-b py-5'
plain: 'border-b border-border-default py-5'
}
},
defaultVariants: {
Expand Down Expand Up @@ -98,7 +98,7 @@ const cardContentVariants = cva(
variants: {
variant: {
outline: 'p-6 pt-0',
plain: 'border-b'
plain: 'border-b border-border-default'
}
},
defaultVariants: {
Expand Down Expand Up @@ -159,7 +159,7 @@ const EmptyCard = React.forwardRef<
>(({className, ...props}, ref) => (
<div
ref={ref}
className={cn('flex flex-col rounded-xl border bg-card p-6 text-card-foreground transition-all hover:shadow-xs', className)}
className={cn('flex flex-col rounded-xl border border-border-default bg-card p-6 text-card-foreground transition-all hover:shadow-xs', className)}
{...props}
/>
));
Expand Down
18 changes: 13 additions & 5 deletions apps/shade/test/unit/components/ui/card.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
CardFooter,
CardTitle,
CardDescription,
CardContent
CardContent,
EmptyCard
} from '../../../../src/components/ui/card';
import {render} from '../../utils/test-utils';

Expand All @@ -18,7 +19,7 @@ describe('Card Components', () => {

assert.ok(card, 'Card should be rendered');
assert.equal(card.textContent, 'Card Content', 'Card should render its content');
assert.ok(card.className.includes('rounded-xl border'), 'Should have outline variant styling');
assert.ok(card.className.includes('rounded-xl border border-border-default'), 'Should have outline variant styling');
});

it('renders Card with plain variant', () => {
Expand All @@ -36,6 +37,13 @@ describe('Card Components', () => {
assert.ok(card.className.includes('custom-card-class'), 'Should have custom class');
});

it('renders EmptyCard with the default container border', () => {
render(<EmptyCard data-testid="empty-card">Empty Card</EmptyCard>);

const card = screen.getByTestId('empty-card');
assert.ok(card.className.includes('border border-border-default'), 'Should use the default container border');
});

it('renders CardHeader with correct styling based on Card variant', () => {
render(
<Card data-testid="card">
Expand All @@ -57,7 +65,7 @@ describe('Card Components', () => {
);

const header = screen.getByTestId('card-header');
assert.ok(header.className.includes('border-b py-5'), 'Should have plain variant styling');
assert.ok(header.className.includes('border-b border-border-default py-5'), 'Should have plain variant styling');
});

it('renders CardTitle with correct styling', () => {
Expand Down Expand Up @@ -99,7 +107,7 @@ describe('Card Components', () => {
);

const content = screen.getByTestId('card-content');
assert.ok(content.className.includes('border-b'), 'Should have plain variant styling');
assert.ok(content.className.includes('border-b border-border-default'), 'Should have plain variant styling');
});

it('renders CardFooter with correct styling based on Card variant', () => {
Expand Down Expand Up @@ -145,4 +153,4 @@ describe('Card Components', () => {
assert.ok(screen.getByTestId('card-content'), 'CardContent should be rendered');
assert.ok(screen.getByTestId('card-footer'), 'CardFooter should be rendered');
});
});
});
4 changes: 2 additions & 2 deletions apps/shade/theme-variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
--text-tertiary: var(--color-gray-400);
--text-inverse: var(--color-white);
--border-subtle: var(--color-gray-200);
--border-default: var(--color-gray-200);
--border-default: color-mix(in oklab, var(--color-gray-200), var(--color-gray-300));
--border-strong: var(--color-gray-500);
--focus-ring: var(--color-gray-600);
--state-info: var(--color-blue-500);
Expand Down Expand Up @@ -83,7 +83,7 @@
--control-surface: var(--surface-elevated);
--control-readonly-surface: var(--color-gray-50);
--control-disabled-surface: var(--color-gray-100);
--control-border: var(--color-gray-200);
--control-border: color-mix(in oklab, var(--color-gray-200), var(--color-gray-300));
--table-row-hover: var(--color-gray-50);
--members-sticky-hover-bg: var(--table-row-hover);
--mobile-navbar-height: 64px;
Expand Down
Loading