@fnd-platform/cms
v1.0.0-alpha.18
Published
Projen project class for generating CMS admin packages in fnd-platform
Downloads
116
Maintainers
Readme
@fnd-platform/cms
Projen project class for generating headless CMS admin interfaces with Remix, shadcn/ui, content modeling, and media management in fnd-platform monorepos.
Installation
npm install -D @fnd-platform/cms
# or
pnpm add -D @fnd-platform/cmsQuick Start
Add a CMS package to your monorepo in .projenrc.ts:
import { FndMonorepoProject } from '@fnd-platform/core';
import { FndApiProject } from '@fnd-platform/api';
import { FndCmsProject } from '@fnd-platform/cms';
const monorepo = new FndMonorepoProject({
name: 'my-app',
defaultReleaseBranch: 'main',
});
const api = new FndApiProject({
parent: monorepo,
name: 'api',
outdir: 'packages/api',
});
const cms = new FndCmsProject({
parent: monorepo,
name: 'cms',
outdir: 'packages/cms',
api: api, // Link to API for content operations
port: 3001,
mediaUpload: true,
richTextEditor: 'tiptap',
});
monorepo.synth();Configuration Options
| Option | Type | Default | Description |
| ---------------- | ------------------------- | ----------------- | ---------------------------- |
| parent | FndMonorepoProject | required | Parent monorepo |
| name | string | required | Package name |
| api | FndApiProject | required | Linked API project |
| outdir | string | packages/{name} | Output directory |
| port | number | 3001 | Development server port |
| mediaUpload | boolean | true | Enable media upload features |
| richTextEditor | 'tiptap' | 'lexical' | 'tiptap' | Rich text editor library |
| shadcnTheme | ShadcnTheme | 'zinc' | Theme color |
What Gets Generated
packages/cms/
├── app/
│ ├── routes/
│ │ ├── _admin.tsx # Admin layout (protected)
│ │ ├── _admin._index.tsx # Dashboard
│ │ ├── _admin.content.tsx # Content list
│ │ ├── _admin.content.$type.tsx # Content by type
│ │ ├── _admin.content.$type.$id.tsx # Content editor
│ │ ├── _admin.content.$type.new.tsx # New content
│ │ ├── _admin.media.tsx # Media library
│ │ ├── _admin.settings.tsx # Settings
│ │ └── login.tsx # Admin login
│ ├── components/
│ │ ├── admin/ # Admin UI components
│ │ ├── editor/ # Rich text editor
│ │ └── ui/ # shadcn/ui components
│ ├── lib/
│ │ ├── api.server.ts # API client
│ │ ├── auth.server.ts # Auth utilities
│ │ └── content-types.ts # Content type definitions
│ └── content-types/ # Content type definitions
├── package.json
├── tailwind.config.js
├── vite.config.ts
└── tsconfig.jsonFeatures
- Admin Interface - Clean, modern admin UI built with shadcn/ui
- Content Modeling - Define flexible content types with various field types
- Draft/Publish Workflow - Content review and publishing workflow
- Media Library - Upload and manage images, videos, and files
- Rich Text Editor - Tiptap or Lexical-based content editing
- Role-Based Access - Admin, editor, and viewer roles
Examples
Content Type Definition
// app/content-types/blog-post.ts
import { defineContentType } from '~/lib/content-types';
export const blogPost = defineContentType({
name: 'blog-post',
label: 'Blog Post',
icon: 'FileText',
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
required: true,
maxLength: 200,
},
{
name: 'slug',
type: 'slug',
label: 'URL Slug',
required: true,
source: 'title',
},
{
name: 'content',
type: 'richtext',
label: 'Content',
required: true,
},
{
name: 'featuredImage',
type: 'media',
label: 'Featured Image',
accept: ['image/*'],
},
{
name: 'publishedAt',
type: 'datetime',
label: 'Publish Date',
},
],
});Admin Dashboard Route
// app/routes/_admin._index.tsx
import { json, type LoaderFunctionArgs } from '@remix-run/node';
import { useLoaderData } from '@remix-run/react';
import { requireAdmin } from '~/lib/auth.server';
import { contentApi } from '~/lib/api.server';
export const loader = async ({ request }: LoaderFunctionArgs) => {
await requireAdmin(request);
const [stats, recentContent] = await Promise.all([
contentApi.getStats(),
contentApi.list({ limit: 10, sort: '-updatedAt' }),
]);
return json({ stats, recentContent });
};
export default function Dashboard() {
const { stats, recentContent } = useLoaderData<typeof loader>();
return (
<div className="space-y-6">
<h1 className="text-2xl font-bold">Dashboard</h1>
{/* Dashboard content */}
</div>
);
}Content Editor Route
// app/routes/_admin.content.$type.$id.tsx
import { json, redirect, type ActionFunctionArgs } from '@remix-run/node';
import { requireAdmin } from '~/lib/auth.server';
import { contentApi } from '~/lib/api.server';
export const action = async ({ request, params }: ActionFunctionArgs) => {
await requireAdmin(request);
const formData = await request.formData();
const intent = formData.get('intent');
if (intent === 'save') {
const data = Object.fromEntries(formData);
await contentApi.update(params.id!, data);
return json({ success: true });
}
if (intent === 'publish') {
await contentApi.publish(params.id!);
return json({ success: true });
}
if (intent === 'delete') {
await contentApi.delete(params.id!);
return redirect(`/admin/content/${params.type}`);
}
return json({ error: 'Invalid action' }, { status: 400 });
};Field Types
| Type | Description | Options |
| ----------- | ----------------- | ---------------------- |
| text | Single line text | maxLength, pattern |
| textarea | Multi-line text | maxLength, rows |
| richtext | Rich text editor | toolbar, formats |
| number | Numeric input | min, max, step |
| boolean | Toggle/checkbox | default |
| select | Dropdown select | options |
| date | Date picker | min, max |
| datetime | Date and time | min, max |
| slug | URL slug | source |
| media | Media picker | accept, multiple |
| reference | Content reference | referenceType |
| tags | Tag input | suggestions |
Content Status
| Status | Description |
| ----------- | ------------------------ |
| draft | Being edited, not public |
| published | Live and visible |
| scheduled | Will publish at set time |
| archived | Hidden but preserved |
Development
# Start development server
cd packages/cms
pnpm dev
# Build for production
pnpm build
# Run tests
pnpm testAPI Reference
See the full API documentation for detailed type definitions and examples.
Project Class
FndCmsProject- Projen project class for CMS packages
Types
import type { FndCmsProjectOptions } from '@fnd-platform/cms';Requirements
- Node.js 20+
- pnpm 8+
- @fnd-platform/core
- @fnd-platform/api (for API linking)
Related
- @fnd-platform/core - Core Projen project classes
- @fnd-platform/api - API package for backend
- @fnd-platform/frontend - Public-facing frontend
- @fnd-platform/cognito-auth - Authentication
License
MIT
