<template>
<div v-for="id in page?.blocks_layout?.items" :key="id"
:data-block-uid="editing ? id : undefined">
<a :href="page.blocks[id].link"
:data-edit-link="editing ? 'link' : undefined">
<img :src="page.blocks[id].image"
:data-edit-media="editing ? 'image' : undefined" />
<h3 :data-edit-text="editing ? 'title' : undefined">
{{ page.blocks[id].title }}
</h3>
<p :data-edit-text="editing ? 'description' : undefined">
{{ page.blocks[id].description }}
</p>
</a>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { initBridge } from 'hydra-js'
const page = ref(null)
const editing = ref(false)
onMounted(async () => {
if (window.name.startsWith('hydra')) {
editing.value = true
initBridge({
blocks: {
card: { blockSchema: { properties: {
image: { widget: 'image' },
title: { type: 'string' },
description: { type: 'string' },
link: { widget: 'url' },
}}}
},
onEditChange: (data) => { page.value = data }
})
} else {
const res = await fetch(`/++api++${useRoute().path}`)
page.value = await res.json()
}
})
</script>
'use client'
import { useState, useEffect } from 'react'
import { initBridge } from 'hydra-js'
export default function Page({ params }) {
const [page, setPage] = useState(null)
const [editing, setEditing] = useState(false)
useEffect(() => {
if (window.name.startsWith('hydra')) {
setEditing(true)
initBridge({
blocks: {
card: { blockSchema: { properties: {
image: { widget: 'image' },
title: { type: 'string' },
description: { type: 'string' },
link: { widget: 'url' },
}}}
},
onEditChange: setPage
})
} else {
fetch(`/++api++/${params.slug?.join('/') || ''}`)
.then(r => r.json()).then(setPage)
}
}, [])
if (!page) return <div>Loading...</div>
return page.blocks_layout?.items?.map(id => {
const block = page.blocks[id]
return (
<div key={id} data-block-uid={editing ? id : undefined}>
{/* data-edit-link: click to edit link URL in sidebar */}
<a href={block.link}
data-edit-link={editing ? 'link' : undefined}>
{/* data-edit-media: click to pick/upload image in sidebar */}
<img src={block.image}
data-edit-media={editing ? 'image' : undefined} />
{/* data-edit-text: edit text directly in the preview */}
<h3 data-edit-text={editing ? 'title' : undefined}>
{block.title}
</h3>
<p data-edit-text={editing ? 'description' : undefined}>
{block.description}
</p>
</a>
</div>
)
})
}
<script>
import { onMount } from 'svelte'
import { initBridge } from 'hydra-js'
let page = $state(null)
let editing = $state(false)
onMount(async () => {
if (window.name.startsWith('hydra')) {
editing = true
initBridge({
blocks: {
card: { blockSchema: { properties: {
image: { widget: 'image' },
title: { type: 'string' },
description: { type: 'string' },
link: { widget: 'url' },
}}}
},
onEditChange: (data) => { page = data }
})
} else {
const res = await fetch(`/++api++${window.location.pathname}`)
page = await res.json()
}
})
</script>
{#if page}
{#each page.blocks_layout?.items ?? [] as id}
<div data-block-uid={editing ? id : undefined}>
<a href={page.blocks[id].link}
data-edit-link={editing ? 'link' : undefined}>
<img src={page.blocks[id].image}
data-edit-media={editing ? 'image' : undefined} />
<h3 data-edit-text={editing ? 'title' : undefined}>
{page.blocks[id].title}
</h3>
<p data-edit-text={editing ? 'description' : undefined}>
{page.blocks[id].description}
</p>
</a>
</div>
{/each}
{/if}
<div id="content"></div>
<script type="module">
import { initBridge } from 'hydra-js'
let editing = false
// Only init bridge when loaded inside the editor
if (window.name.startsWith('hydra')) {
editing = true
initBridge({
// Register custom block types with their field schemas
blocks: {
card: { blockSchema: { properties: {
image: { widget: 'image' },
title: { type: 'string' },
description: { type: 'string' },
link: { widget: 'url' },
}}}
},
// Receive live updates as editor changes content
onEditChange: renderPage
})
} else {
const res = await fetch(`/++api++${location.pathname}`)
renderPage(await res.json())
}
function renderPage(page) {
const el = document.getElementById('content')
el.innerHTML = page.blocks_layout.items.map(id => {
const b = page.blocks[id]
return `
<div ${editing ? `data-block-uid="${id}"` : ''}>
<a href="${b.link}"
${editing ? 'data-edit-link="link"' : ''}>
<img src="${b.image}"
${editing ? 'data-edit-media="image"' : ''} />
<h3 ${editing ? 'data-edit-text="title"' : ''}>
${b.title}
</h3>
<p ${editing ? 'data-edit-text="description"' : ''}>
${b.description}
</p>
</a>
</div>`
}).join('')
}
</script>