Embed, from the Building blocks group of the nertia component library.
npx shadcn@latest add https://ner.sh/r/block-embed.jsonThe recipe carries this block's layout and variant; the install brings the component.
{
"registries": {
"@nertia": "https://ner.sh/r/{name}.json"
}
}npx shadcn@latest add @nertia/block-embednpm create nersh@latest my-site -- --site https://nertia.ai/components/building-blocks/element-block-embed/site.json scaffolds a project from it.{
"slug": "element-block-embed",
"mode": "builder",
"status": "draft",
"skinId": "zinc",
"composition": {
"id": "element-block-embed",
"sections": [
{
"id": "block-embed",
"instanceId": "stage-block-embed"
}
]
},
"copy": {
"stage-block-embed.url": "",
"stage-block-embed.title": "A headline that says what you do",
"stage-block-embed.kind": "videoEmbed"
}
}
import type { Section } from '../types';
import { Component } from './Component';
import { schema } from './schema';
import { meta } from './meta';
import { writeCopy } from './writeCopy';
export const blockEmbed: Section = { meta, schema, Component, writeCopy };
'use client';
import type { SectionProps } from '../types';
import { Editable } from '@/components/site/EditableText';
import { compositionEditPath } from '@/lib/composition/compositionEditableCopy';
import { Embed } from '@/components/foundation';
export function Component({ copy, instanceId, builderInsert }: SectionProps) {
const edit = (slotKey: string) => compositionEditPath(instanceId, slotKey);
const url = copy.url?.trim() || '';
const title = copy.title?.trim() || undefined;
const kind = (copy.kind === 'iframeEmbed' ? 'iframeEmbed' : 'videoEmbed') as
| 'videoEmbed'
| 'iframeEmbed';
// A visitor never sees an "Add an embed URL" box; the placeholder is builder-only, and
// the empty column it leaves behind collapses through `empty:hidden` on the wrapper.
if (!url && !builderInsert) return null;
if (!url) {
return (
<div
data-section="block-embed"
className="site-type-sm rounded-[var(--radius)] border border-dashed border-[var(--border)] p-6 text-[var(--muted-foreground)]"
>
Add an embed URL
</div>
);
}
return (
<div data-section="block-embed">
<span className="sr-only">
<Editable path={edit('title')!}>{copy.title ?? ''}</Editable>
</span>
<Embed url={url} kind={kind} title={title} />
</div>
);
}
import type { SectionCopySchemaField } from '../types';
export const schema: SectionCopySchemaField[] = [
{ key: 'url', label: 'URL', type: 'videoEmbed', placeholder: 'https://' },
{ key: 'title', label: 'Title (optional)', type: 'text', placeholder: 'Embed title' },
{
key: 'kind',
label: 'Kind',
type: 'text',
placeholder: 'videoEmbed',
advanced: true,
options: [
{ value: '', label: 'Video' },
{ value: 'iframeEmbed', label: 'Iframe' },
],
},
];
import type { SectionMeta } from '../types';
export const meta: SectionMeta = {
id: 'block-embed',
displayName: 'Embed',
family: 'component',
tags: ['component', 'atom', 'embed', 'video', 'iframe'],
bucket: 'atom',
};
import type { BrandContext } from '@/lib/brandContext';
export function writeCopy(_ctx: BrandContext) {
return {
url: '',
title: '',
kind: 'videoEmbed',
};
}