4020ad62c5
- Implemented `resolveApiAssetUrl` function to normalize asset URLs based on API base. - Updated `MedialibImage` component to utilize new asset URL resolution and added support for alt text and class properties. - Enhanced image loading behavior with improved width measurement and focal point handling. - Added placeholder image handling and improved accessibility with alt text. - Introduced new test script for auditing broken links in skill documentation. - Expanded seeded test content to include medialib entries and updated related tests for pagebuilder previews. - Improved global setup and teardown logging for clarity on seeded content management.
151 lines
4.5 KiB
TypeScript
151 lines
4.5 KiB
TypeScript
import { mount, unmount, type Component, type SvelteComponent } from "svelte"
|
|
import { apiBaseOverride } from "./lib/store"
|
|
import BlockRenderer from "./blocks/BlockRenderer.svelte"
|
|
|
|
const previewCssUrl = new URL("./index.css", import.meta.url).toString()
|
|
|
|
type BlockRenderContext = {
|
|
namespace?: string
|
|
apiBase?: string
|
|
projectBase?: string
|
|
}
|
|
|
|
type BlockHandle = {
|
|
update(row: Record<string, any>, context?: BlockRenderContext): void
|
|
destroy(): void
|
|
}
|
|
|
|
type BlockDefinition = {
|
|
render(container: HTMLElement | ShadowRoot, row: Record<string, any>, context?: BlockRenderContext): BlockHandle
|
|
css?: string[]
|
|
previewStyles?: Record<string, string>
|
|
label?: string
|
|
icon?: string
|
|
color?: string
|
|
}
|
|
|
|
type BlockPresentation = {
|
|
label: string
|
|
icon: string
|
|
color: string
|
|
}
|
|
|
|
function getAdminPreviewProps(props?: { [key: string]: any }) {
|
|
return {
|
|
isAdminPreview: true,
|
|
...(props || {}),
|
|
}
|
|
}
|
|
|
|
function getRenderedElement(
|
|
component: typeof SvelteComponent,
|
|
options?: { props: { [key: string]: any }; addCss?: string[] },
|
|
nestedElements?: { tagName: string; className?: string }[]
|
|
) {
|
|
const el = document.createElement("div")
|
|
el.attachShadow({ mode: "open" })
|
|
|
|
const body = document.createElement("body")
|
|
|
|
// build nested divs with css classes
|
|
let target: HTMLElement = body
|
|
nestedElements?.forEach((e) => {
|
|
const newElement = document.createElement(e.tagName)
|
|
if (e.className) {
|
|
newElement.className = e.className
|
|
}
|
|
target.appendChild(newElement)
|
|
target = newElement
|
|
})
|
|
|
|
el.shadowRoot.appendChild(body)
|
|
|
|
options?.addCss?.forEach((css) => {
|
|
const link = document.createElement("link")
|
|
link.rel = "stylesheet"
|
|
link.href = css
|
|
link.type = "text/css"
|
|
el.shadowRoot.appendChild(link)
|
|
})
|
|
|
|
new component({
|
|
target: target,
|
|
props: getAdminPreviewProps(options?.props),
|
|
})
|
|
|
|
return el
|
|
}
|
|
|
|
function createContentBlockDefinition(presentation: BlockPresentation): BlockDefinition {
|
|
return {
|
|
css: [previewCssUrl],
|
|
label: presentation.label,
|
|
icon: presentation.icon,
|
|
color: presentation.color,
|
|
previewStyles: {
|
|
"background-color": "white",
|
|
position: "relative",
|
|
},
|
|
render(container, row, context) {
|
|
const previewApiBase = context?.projectBase || context?.apiBase
|
|
if (previewApiBase) {
|
|
apiBaseOverride.set(String(previewApiBase))
|
|
}
|
|
|
|
const target = document.createElement("div")
|
|
target.dataset.adminPreview = "true"
|
|
container.appendChild(target)
|
|
|
|
let mountedComponent = mount(BlockRenderer as Component<any>, {
|
|
target,
|
|
props: {
|
|
blocks: [row as ContentBlockEntry],
|
|
isAdminPreview: true,
|
|
},
|
|
})
|
|
|
|
return {
|
|
update(nextRow, nextContext) {
|
|
const nextPreviewApiBase = nextContext?.projectBase || nextContext?.apiBase
|
|
if (nextPreviewApiBase) {
|
|
apiBaseOverride.set(String(nextPreviewApiBase))
|
|
}
|
|
|
|
unmount(mountedComponent)
|
|
target.innerHTML = ""
|
|
mountedComponent = mount(BlockRenderer as Component<any>, {
|
|
target,
|
|
props: {
|
|
blocks: [nextRow as ContentBlockEntry],
|
|
isAdminPreview: true,
|
|
},
|
|
})
|
|
},
|
|
destroy() {
|
|
unmount(mountedComponent)
|
|
target.remove()
|
|
},
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
const blockRegistry = {
|
|
hero: createContentBlockDefinition({ label: "Hero", icon: "image", color: "#1d4ed8" }),
|
|
features: createContentBlockDefinition({ label: "Features", icon: "view_quilt", color: "#0f766e" }),
|
|
richtext: createContentBlockDefinition({ label: "Richtext", icon: "article", color: "#7c3aed" }),
|
|
accordion: createContentBlockDefinition({ label: "Accordion", icon: "expand", color: "#b45309" }),
|
|
"contact-form": createContentBlockDefinition({
|
|
label: "Contact Form",
|
|
icon: "mail",
|
|
color: "#be185d",
|
|
}),
|
|
}
|
|
|
|
export {
|
|
getAdminPreviewProps,
|
|
getRenderedElement,
|
|
blockRegistry,
|
|
// pass also required svelte components here
|
|
}
|