Studio Customization
Trokky Studio is the React-based admin interface for managing content. It can be customized to match your brand and workflow.
Overview
Section titled “Overview”Studio features include:
- Document editing with auto-generated forms
- Media library with drag-and-drop uploads
- Reference browsing and linking
- Dark mode support
- Customizable navigation and branding
Basic Configuration
Section titled “Basic Configuration”const trokky = await TrokkyExpress.create({ studio: { enabled: true, branding: { title: 'My CMS', }, }, // ...});Branding
Section titled “Branding”Logo and Title
Section titled “Logo and Title”studio: { branding: { title: 'Acme CMS', logo: '/logo.svg', // URL or path logoAlt: 'Acme Logo', favicon: '/favicon.ico', },}Colors
Section titled “Colors”studio: { branding: { colors: { primary: '#3b82f6', // Primary brand color secondary: '#64748b', // Secondary color accent: '#f59e0b', // Accent color }, },}Custom CSS
Section titled “Custom CSS”studio: { branding: { customCss: ` :root { --studio-sidebar-bg: #1a1a2e; --studio-header-bg: #16213e; } `, },}Navigation Structure
Section titled “Navigation Structure”Default Structure
Section titled “Default Structure”By default, Studio generates navigation from your schemas. Customize with the structure option:
studio: { structure: [ { type: 'list', schemaType: 'post', title: 'Blog Posts', icon: 'document', }, { type: 'list', schemaType: 'author', title: 'Authors', icon: 'user', }, { type: 'divider', }, { type: 'singleton', schemaType: 'siteSettings', title: 'Settings', icon: 'cog', }, ],}Grouping Items
Section titled “Grouping Items”studio: { structure: [ { type: 'group', title: 'Content', icon: 'folder', items: [ { type: 'list', schemaType: 'post', title: 'Posts' }, { type: 'list', schemaType: 'page', title: 'Pages' }, ], }, { type: 'group', title: 'Taxonomy', items: [ { type: 'list', schemaType: 'category', title: 'Categories' }, { type: 'list', schemaType: 'tag', title: 'Tags' }, ], }, { type: 'group', title: 'Settings', items: [ { type: 'singleton', schemaType: 'siteSettings' }, { type: 'singleton', schemaType: 'navigation' }, ], }, ],}Dynamic Structure
Section titled “Dynamic Structure”Generate structure dynamically based on user:
studio: { structure: (user) => { const items = [ { type: 'list', schemaType: 'post', title: 'Posts' }, { type: 'list', schemaType: 'page', title: 'Pages' }, ];
// Admin-only sections if (user.role === 'admin') { items.push({ type: 'group', title: 'Administration', items: [ { type: 'singleton', schemaType: 'siteSettings' }, { type: 'link', title: 'Users', url: '/studio/users' }, ], }); }
return items; },}Document List Customization
Section titled “Document List Customization”Filtering
Section titled “Filtering”{ type: 'list', schemaType: 'post', title: 'Published Posts', filter: { status: 'published', },}Default Ordering
Section titled “Default Ordering”{ type: 'list', schemaType: 'post', title: 'Posts', defaultOrdering: { field: 'publishedAt', direction: 'desc', },}Columns
Section titled “Columns”{ type: 'list', schemaType: 'post', columns: [ { field: 'title', title: 'Title', width: '40%' }, { field: 'author.name', title: 'Author', width: '20%' }, { field: 'status', title: 'Status', width: '15%' }, { field: '_updatedAt', title: 'Updated', width: '25%' }, ],}Form Customization
Section titled “Form Customization”Field Groups
Section titled “Field Groups”Organize fields into collapsible groups:
// In schema definition{ name: 'post', title: 'Blog Post', groups: [ { name: 'content', title: 'Content' }, { name: 'meta', title: 'Meta', collapsed: true }, { name: 'seo', title: 'SEO', collapsed: true }, ], fields: [ { name: 'title', type: 'string', group: 'content' }, { name: 'content', type: 'richtext', group: 'content' }, { name: 'author', type: 'reference', group: 'meta' }, { name: 'publishedAt', type: 'datetime', group: 'meta' }, { name: 'seoTitle', type: 'string', group: 'seo' }, { name: 'seoDescription', type: 'text', group: 'seo' }, ],}Conditional Fields
Section titled “Conditional Fields”Show/hide fields based on other values:
{ name: 'type', type: 'select', options: { list: [ { value: 'internal', title: 'Internal Link' }, { value: 'external', title: 'External Link' }, ], },},{ name: 'internalPage', type: 'reference', options: { to: 'page' }, hidden: ({ document }) => document.type !== 'internal',},{ name: 'externalUrl', type: 'string', hidden: ({ document }) => document.type !== 'external',}Read-Only Fields
Section titled “Read-Only Fields”{ name: 'slug', type: 'slug', readOnly: ({ currentUser }) => currentUser.role !== 'admin',}Actions
Section titled “Actions”Document Actions
Section titled “Document Actions”Add custom actions to documents:
studio: { documentActions: [ { label: 'Publish', icon: 'publish', action: async (doc, { client }) => { await client.documents.update(doc._type, doc._id, { status: 'published', publishedAt: new Date().toISOString(), }); }, visible: (doc) => doc.status === 'draft', }, { label: 'Unpublish', icon: 'unpublish', action: async (doc, { client }) => { await client.documents.update(doc._type, doc._id, { status: 'draft', }); }, visible: (doc) => doc.status === 'published', }, ],}Global Actions
Section titled “Global Actions”Add actions to the Studio toolbar:
studio: { globalActions: [ { label: 'Deploy', icon: 'rocket', action: async ({ client }) => { await fetch('/api/deploy', { method: 'POST' }); }, roles: ['admin'], }, ],}Widgets
Section titled “Widgets”Dashboard Widgets
Section titled “Dashboard Widgets”Customize the Studio dashboard:
studio: { dashboard: { widgets: [ { type: 'recentDocuments', title: 'Recent Posts', schemaType: 'post', limit: 5, }, { type: 'documentCount', title: 'Content Stats', schemaTypes: ['post', 'page', 'author'], }, { type: 'custom', title: 'Quick Links', component: 'QuickLinksWidget', }, ], },}Previews
Section titled “Previews”Document Preview
Section titled “Document Preview”Configure live preview for documents:
studio: { preview: { enabled: true, url: (doc) => { if (doc._type === 'post') { return `http://localhost:3001/posts/${doc.slug}`; } return null; }, },}Preview Pane
Section titled “Preview Pane”Show preview alongside the editor:
studio: { preview: { position: 'right', // 'right', 'bottom', or 'popup' width: '50%', refreshOnChange: true, },}Access Control
Section titled “Access Control”Hide Schema Types
Section titled “Hide Schema Types”studio: { access: { // Hide schemas from certain roles schemas: { siteSettings: ['admin'], // Admin only post: ['admin', 'editor', 'writer'], page: ['admin', 'editor'], }, },}Disable Features
Section titled “Disable Features”studio: { features: { mediaLibrary: true, darkMode: true, search: true, bulkActions: ['admin', 'editor'], // Role-restricted },}Development Mode
Section titled “Development Mode”Hot Reload
Section titled “Hot Reload”In development, Studio supports hot reloading:
studio: { dev: { hotReload: true, port: 5173, },}Debug Mode
Section titled “Debug Mode”studio: { debug: { showFieldNames: true, // Show field names in forms logApiCalls: true, // Log API requests },}Production Build
Section titled “Production Build”Building Studio
Section titled “Building Studio”npm run studio:buildThis generates optimized static files that are served by the Trokky server.
Custom Build Path
Section titled “Custom Build Path”studio: { buildDir: './studio-build', basePath: '/admin', // Serve at /admin instead of /studio}Next Steps
Section titled “Next Steps”- Deployment - Deploy to production
- Configuration Reference - Full configuration options
- HTTP API - API documentation