File-based content management system for Nuxt.js applications with powerful querying and Vue component rendering in Markdown
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Live content editing system with field definitions, authentication, and real-time preview capabilities for content management workflows.
Creates preview-compatible field configurations for content editing interfaces.
/**
* Helper to build preview-compatible field configuration
* @param config - Field configuration object
* @returns Configured preview field
*/
function field(config: FieldConfig): PreviewField;
interface FieldConfig {
/** Field input type */
type: PickerTypes;
/** Field identifier */
name: string;
/** Display label for field */
label?: string;
/** Whether field is required */
required?: boolean;
/** Default value */
default?: unknown;
/** Field validation rules */
validation?: ValidationRule[];
/** Field-specific options */
options?: FieldOptions;
}
interface PreviewField {
type: PickerTypes;
name: string;
label: string;
required: boolean;
default?: unknown;
validation: ValidationRule[];
options: FieldOptions;
}Usage Examples:
import { field } from '@nuxt/content/preview';
// Text input field
const titleField = field({
type: 'text',
name: 'title',
label: 'Article Title',
required: true,
validation: [
{ type: 'minLength', value: 5, message: 'Title must be at least 5 characters' },
{ type: 'maxLength', value: 100, message: 'Title must not exceed 100 characters' }
]
});
// Rich text editor
const contentField = field({
type: 'richtext',
name: 'content',
label: 'Article Content',
required: true,
options: {
toolbar: ['bold', 'italic', 'link', 'code'],
placeholder: 'Write your article content...'
}
});
// Select dropdown
const categoryField = field({
type: 'select',
name: 'category',
label: 'Category',
required: true,
options: {
choices: [
{ label: 'Technology', value: 'tech' },
{ label: 'Design', value: 'design' },
{ label: 'Business', value: 'business' }
]
}
});
// Date picker
const publishDateField = field({
type: 'date',
name: 'publishedAt',
label: 'Publish Date',
default: new Date(),
options: {
format: 'YYYY-MM-DD',
minDate: new Date()
}
});Groups preview fields with schema validation and organization.
/**
* Groups preview fields with schema validation
* @param config - Group configuration object
* @returns Configured preview group
*/
function group(config: GroupConfig): PreviewGroup;
interface GroupConfig {
/** Group identifier */
name: string;
/** Display label for group */
label?: string;
/** Fields within this group */
fields: PreviewField[];
/** Group validation schema */
schema?: PartialSchema;
/** Group display options */
options?: GroupOptions;
}
interface PreviewGroup {
name: string;
label: string;
fields: PreviewField[];
schema: PartialSchema;
options: GroupOptions;
}Usage Examples:
import { field, group } from '@nuxt/content/preview';
// Article metadata group
const metadataGroup = group({
name: 'metadata',
label: 'Article Metadata',
fields: [
field({
type: 'text',
name: 'title',
label: 'Title',
required: true
}),
field({
type: 'textarea',
name: 'description',
label: 'Description',
options: { rows: 3 }
}),
field({
type: 'select',
name: 'status',
label: 'Status',
default: 'draft',
options: {
choices: [
{ label: 'Draft', value: 'draft' },
{ label: 'Published', value: 'published' },
{ label: 'Archived', value: 'archived' }
]
}
})
],
options: {
collapsible: true,
expanded: true
}
});
// Author information group
const authorGroup = group({
name: 'author',
label: 'Author Information',
fields: [
field({
type: 'text',
name: 'name',
label: 'Author Name',
required: true
}),
field({
type: 'email',
name: 'email',
label: 'Author Email'
}),
field({
type: 'image',
name: 'avatar',
label: 'Author Avatar',
options: {
accept: 'image/*',
maxSize: '2MB'
}
})
]
});type TextFieldTypes = 'text' | 'textarea' | 'email' | 'url' | 'password';
interface TextFieldOptions {
/** Placeholder text */
placeholder?: string;
/** Maximum character length */
maxLength?: number;
/** Minimum character length */
minLength?: number;
/** Input pattern regex */
pattern?: string;
/** Number of rows (textarea only) */
rows?: number;
/** Auto-resize textarea */
autoResize?: boolean;
}type RichContentTypes = 'richtext' | 'markdown' | 'code';
interface RichTextOptions {
/** Toolbar buttons to show */
toolbar?: string[];
/** Editor placeholder */
placeholder?: string;
/** Enable code blocks */
codeBlocks?: boolean;
/** Custom editor extensions */
extensions?: EditorExtension[];
}
interface MarkdownOptions {
/** Enable live preview */
preview?: boolean;
/** Syntax highlighting theme */
theme?: string;
/** Supported languages for code blocks */
languages?: string[];
}
interface CodeOptions {
/** Programming language */
language?: string;
/** Show line numbers */
lineNumbers?: boolean;
/** Editor theme */
theme?: string;
/** Tab size */
tabSize?: number;
}type SelectionTypes = 'select' | 'multiselect' | 'radio' | 'checkbox' | 'toggle';
interface SelectionOptions {
/** Available choices */
choices: Choice[];
/** Allow multiple selections */
multiple?: boolean;
/** Enable search/filtering */
searchable?: boolean;
/** Maximum selections (multiselect) */
maxSelections?: number;
}
interface Choice {
/** Display label */
label: string;
/** Option value */
value: string | number;
/** Option description */
description?: string;
/** Option disabled state */
disabled?: boolean;
/** Option group */
group?: string;
}type MediaTypes = 'image' | 'file' | 'video' | 'audio';
interface MediaOptions {
/** Accepted file types */
accept?: string;
/** Maximum file size */
maxSize?: string;
/** Image dimensions */
dimensions?: {
width?: number;
height?: number;
aspectRatio?: string;
};
/** Generate thumbnails */
thumbnails?: boolean;
/** Upload destination */
destination?: string;
}type DateTimeTypes = 'date' | 'datetime' | 'time';
interface DateTimeOptions {
/** Date format */
format?: string;
/** Minimum date */
minDate?: Date;
/** Maximum date */
maxDate?: Date;
/** Enable time picker */
enableTime?: boolean;
/** Time format (12/24 hour) */
timeFormat?: '12' | '24';
/** Default timezone */
timezone?: string;
}interface ValidationRule {
/** Validation type */
type: ValidationType;
/** Validation value/parameter */
value?: unknown;
/** Error message */
message: string;
/** Custom validation function */
validator?: (value: unknown) => boolean | Promise<boolean>;
}
type ValidationType =
| 'required' | 'minLength' | 'maxLength'
| 'min' | 'max' | 'email' | 'url'
| 'pattern' | 'custom';Usage Examples:
// Complex validation rules
const emailField = field({
type: 'email',
name: 'email',
label: 'Email Address',
required: true,
validation: [
{
type: 'required',
message: 'Email is required'
},
{
type: 'email',
message: 'Must be a valid email address'
},
{
type: 'custom',
message: 'Email domain not allowed',
validator: async (email) => {
const domain = email.split('@')[1];
const allowedDomains = ['company.com', 'partner.com'];
return allowedDomains.includes(domain);
}
}
]
});// content/blog/preview.config.ts
import { field, group } from '@nuxt/content/preview';
export default {
// Field groups for content editing
groups: [
group({
name: 'content',
label: 'Content',
fields: [
field({
type: 'text',
name: 'title',
label: 'Title',
required: true
}),
field({
type: 'richtext',
name: 'content',
label: 'Content',
required: true
})
]
}),
group({
name: 'meta',
label: 'Metadata',
fields: [
field({
type: 'date',
name: 'publishedAt',
label: 'Publish Date'
}),
field({
type: 'multiselect',
name: 'tags',
label: 'Tags',
options: {
choices: [
{ label: 'Vue.js', value: 'vue' },
{ label: 'Nuxt.js', value: 'nuxt' },
{ label: 'JavaScript', value: 'js' }
]
}
})
]
})
]
};type PickerTypes =
| 'text' | 'textarea' | 'email' | 'url' | 'password'
| 'richtext' | 'markdown' | 'code'
| 'select' | 'multiselect' | 'radio' | 'checkbox' | 'toggle'
| 'image' | 'file' | 'video' | 'audio'
| 'date' | 'datetime' | 'time'
| 'number' | 'range' | 'color';
interface PreviewFieldData {
/** Field type */
type: PickerTypes;
/** Field value */
value: unknown;
/** Field metadata */
meta: FieldMeta;
/** Validation state */
validation: ValidationState;
}
interface ConfigInputsTypes {
[fieldName: string]: PickerTypes;
}
interface PartialSchema {
/** Schema validation function */
validate: (data: unknown) => ValidationResult;
/** Schema transformation function */
transform?: (data: unknown) => unknown;
}
interface GroupOptions {
/** Group is collapsible */
collapsible?: boolean;
/** Group is expanded by default */
expanded?: boolean;
/** Group display order */
order?: number;
/** Group CSS classes */
className?: string;
/** Group conditional display */
conditional?: ConditionalRule;
}
interface ConditionalRule {
/** Field to watch for condition */
field: string;
/** Condition operator */
operator: '=' | '!=' | 'in' | 'not_in';
/** Condition value */
value: unknown;
}Install with Tessl CLI
npx tessl i tessl/npm-nuxt--content