diff --git a/LLM_MCP_GUIDE.md b/LLM_MCP_GUIDE.md index dc55805..ac05685 100644 --- a/LLM_MCP_GUIDE.md +++ b/LLM_MCP_GUIDE.md @@ -17,6 +17,19 @@ This guide explains how to use the HomAroma MCP tools safely and consistently. ## Create Page Response Contract +Use `create_page_with_section` only when the slug does not exist. It atomically +creates a new page and its first section; it does not update an existing page. +If it returns `PAGE_SLUG_EXISTS`, use the returned `pageId` with +`add_page_section`. + +To add another block to an existing page: + +1. Call `get_dynamic_page_detail` with the slug. +2. Call `get_page_block_schema` for the desired block type. +3. Call `add_page_section` with the returned page `id`. +4. Call `reorder_page_sections` if the new block must move relative to existing blocks. +5. Read the page back with `get_dynamic_page_detail`. + `create_dynamic_page` now returns a structured response that is easy for LLMs to parse: - `success` @@ -80,6 +93,16 @@ Use one string only for URLs, slugs, IDs, and booleans/numbers as appropriate. - `content` is required and localized - HTML is allowed in `content` +### `ARTICLE_MEDIA` + +- `body` is required, localized plain text; do not send HTML +- `heading`, `imageAlt`, and `imageCaption` are localized +- `imageUrl` is a plain URL or website-relative media path +- `imageAlt` is required whenever `imageUrl` is present +- `imagePosition` accepts `left`, `right`, or `top` +- `width` accepts `narrow`, `standard`, or `wide` +- `background` accepts `default` or `muted` + ### `SCENT_NOTES_BREAKDOWN` - `title` and `description` are localized @@ -120,11 +143,13 @@ Use one string only for URLs, slugs, IDs, and booleans/numbers as appropriate. ## Recommended Flow -1. Find the page id from slug or metadata. -2. Create or update the page title translations. -3. Add sections using the dedicated block tool when possible. -4. Read back the page with `get_dynamic_page_detail`. -5. If a section has auto-populated fields, trust the read-back result over the raw update payload. +1. Determine whether the page already exists. +2. For a new page, use `create_page_with_section` for the page and first block. +3. For an existing page, get its id and use `add_page_section`. +4. Create or update the page title translations. +5. Update existing sections using the dedicated block tool when possible. +6. Read back the page with `get_dynamic_page_detail`. +7. If a section has auto-populated fields, trust the read-back result over the raw update payload. ## What to Expect diff --git a/apps/admin/src/components/page-builder/ArticleMediaForm.tsx b/apps/admin/src/components/page-builder/ArticleMediaForm.tsx new file mode 100644 index 0000000..ba50051 --- /dev/null +++ b/apps/admin/src/components/page-builder/ArticleMediaForm.tsx @@ -0,0 +1,182 @@ +import { Image as ImageIcon, UploadCloud } from 'lucide-react'; +import { type PageSection } from '@homaroma/types'; + +interface ArticleMediaFormProps { + editingSection: Partial; + getLocalizedValue: (payload: unknown, field: string) => string; + updateLocalizedValue: (field: string, value: string) => void; + updatePayloadValue: (field: string, value: string) => void; + setUploadTarget: (target: { type: 'main' | 'slide'; index?: number } | null) => void; + setIsMediaModalOpen: (open: boolean) => void; +} + +const POSITION_OPTIONS = [ + { value: 'left', label: 'Image left' }, + { value: 'right', label: 'Image right' }, + { value: 'top', label: 'Image top' }, +] as const; + +export default function ArticleMediaForm({ + editingSection, + getLocalizedValue, + updateLocalizedValue, + updatePayloadValue, + setUploadTarget, + setIsMediaModalOpen, +}: ArticleMediaFormProps) { + const payload = editingSection.payload || {}; + const imageUrl = typeof payload.imageUrl === 'string' ? payload.imageUrl : ''; + const imagePosition = typeof payload.imagePosition === 'string' ? payload.imagePosition : 'right'; + + return ( +
+
+ + updateLocalizedValue('heading', event.target.value)} + className="admin-input w-full" + placeholder="Section heading" + /> +
+ +
+ +