feat: integration screen

This commit is contained in:
fsylvain committed 2026-09-27 18:04:43 +02:00
1 parent a9a208b80a
commit ad55137883
13 files changed
+786 -6

No files matched your search

+114 -2
View File
@@ -1,9 +1,121 @@
<script setup lang="ts">
import { computed } from 'vue'
import DashboardShell from '@/components/DashboardShell.vue'
import EndpointCard from '@/components/EndpointCard.vue'
import { useCopyToClipboard } from '@/composables/useCopyToClipboard'
const origin = computed(() => window.location.origin)
const { copied, copy } = useCopyToClipboard()
const copyButtonLabel = computed(() => (copied.value ? 'Copied' : 'Copy'))
const copyButtonIcon = computed(() => (copied.value ? 'i-lucide-check' : 'i-lucide-copy'))
function copyBaseUrl() {
copy(origin.value)
}
const sampleArticle = {
id: 12,
title: 'How we price a bathroom renovation',
body: '<p>Every bathroom is different, but the way we price them isn’t.</p>',
images: [
{
id: 1,
path: '/static/uploadedImages/2f6a1c0e-2b8b-4c3d-9c1e-1a2b3c4d5e6f.png',
article_id: 12,
created_at: '2026-03-12T09:14:00Z',
updated_at: '2026-03-12T09:14:00Z',
},
],
is_online: true,
created_at: '2026-03-12T09:14:00Z',
updated_at: '2026-09-10T07:00:00Z',
}
const sampleArticleList = [sampleArticle]
const endpoints = computed(() => [
{
method: 'GET' as const,
path: '/v1/article/',
description: 'Lists every online article.',
examples: {
fetch: `const res = await fetch('${origin.value}/v1/article/')\nconst articles = await res.json()`,
curl: `curl ${origin.value}/v1/article/`,
response: JSON.stringify(sampleArticleList, null, 2),
},
},
{
method: 'GET' as const,
path: '/v1/article/{id}',
description: 'Returns one online article. Drafts and unknown ids both return 404.',
examples: {
fetch: `const res = await fetch('${origin.value}/v1/article/12')\nif (res.status === 404) return notFound()\nconst article = await res.json()`,
curl: `curl ${origin.value}/v1/article/12`,
response: JSON.stringify(sampleArticle, null, 2),
},
},
])
const notes = [
'Anonymous callers only ever get online articles. Drafts stay private until you publish them.',
'Images in body use paths like /static/uploadedImages/<uuid>.png. Prefix them with the base URL before rendering.',
"Browsers can only call the API from origins listed in the server's CORS setting. Ask whoever runs the server to add your site's address.",
]
</script>
<template>
<DashboardShell>
<p>Integration placeholder.</p>
<DashboardShell mobile-title="Integration">
<div class="flex max-w-199 flex-col gap-6">
<div class="flex flex-col gap-1">
<h1 class="text-xl font-semibold text-highlighted">Connect your website</h1>
<p class="text-muted">A guide for the developer who builds your public site.</p>
</div>
<p class="text-base text-pretty text-toned">
RenewCMS is headless: it stores and publishes your articles but doesn't show them to
visitors. Your website fetches published articles from the two addresses below and
displays them in its own design.
</p>
<div class="flex flex-col gap-1.5">
<span class="font-medium text-highlighted">Base URL</span>
<div class="flex border border-accented bg-default">
<span
class="h-10 min-w-0 flex-1 truncate px-3 font-mono text-sm leading-10 text-default"
>{{ origin }}</span
>
<UButton
:icon="copyButtonIcon"
color="neutral"
variant="ghost"
aria-live="polite"
class="h-10 gap-1.5 rounded-none border-l border-accented px-3 font-medium"
:class="copied ? 'text-success' : 'text-highlighted'"
:ui="{ leadingIcon: 'size-3.5' }"
@click="copyBaseUrl"
>
{{ copyButtonLabel }}
</UButton>
</div>
</div>
<EndpointCard
v-for="endpoint in endpoints"
:key="endpoint.path"
:method="endpoint.method"
:path="endpoint.path"
:description="endpoint.description"
:examples="endpoint.examples"
/>
<div class="flex flex-col gap-2.5">
<div v-for="note in notes" :key="note" class="flex gap-2.5">
<UIcon name="i-lucide-info" class="mt-0.75 size-4 shrink-0 text-info" />
<span class="text-base text-pretty text-toned">{{ note }}</span>
</div>
</div>
</div>
</DashboardShell>
</template>