feat(integration): add image variants section and standardize code snippets

This commit is contained in:
Florian Sylvain committed 2026-10-12 23:27:41 +02:00
1 parent 6f9ae6207a
commit e6746f2be7
28 files changed
+2256 -422

No files matched your search

+22 -76
View File
@@ -2,13 +2,13 @@
import { t, translate } from '@/i18n'
import { computed, onBeforeUnmount, onMounted, ref } from 'vue'
import CodeBlock from '@/components/CodeBlock.vue'
import CodeSnippet from '@/components/CodeSnippet.vue'
import CodeText from '@/components/CodeText.vue'
import DashboardShell from '@/components/DashboardShell.vue'
import EndpointCard from '@/components/EndpointCard.vue'
import IntegrationImages from '@/components/IntegrationImages.vue'
import SectionIndex from '@/components/SectionIndex.vue'
import SessionOnlyGroup from '@/components/SessionOnlyGroup.vue'
import { useCopyToClipboard } from '@/composables/useCopyToClipboard'
import {
API_GROUPS,
ERROR_ROWS,
@@ -17,29 +17,26 @@ import {
SESSION_GROUPS,
authExamples,
} from '@/data/apiCatalogue'
import { SECTION_TITLE } from '@/lib/apiReference'
const SPY_OFFSET_PX = 120
const origin = computed(() => window.location.origin)
const { copied, copy } = useCopyToClipboard()
const copyButtonLabel = computed(() => (copied.value ? t('Copied') : t('Copy')))
const copyButtonIcon = computed(() => (copied.value ? 'i-lucide-check' : 'i-lucide-copy'))
function copyBaseUrl() {
copy(origin.value)
}
const root = ref<HTMLElement | null>(null)
const activeSection = ref('auth')
const authTab = ref('curl')
const baseUrlTabs = computed(() => [{ k: 'base', label: t('Base URL'), code: origin.value }])
const errorSampleTabs = computed(() => [
{ k: 'error', label: t('Error response · text/plain'), code: ERROR_SAMPLE },
])
const sessionRouteCount = SESSION_GROUPS.reduce((total, group) => total + group.rows.length, 0)
const sections = computed(() => [
{ id: 'auth', label: t('Authentication') },
...API_GROUPS.map((group) => ({ id: group.key, label: translate(group.title) })),
{ id: 'images', label: t('Images and variants') },
{ id: 'session', label: t('Session only') },
{ id: 'errors', label: t('Errors') },
{ id: 'notes', label: t('Notes') },
@@ -48,14 +45,8 @@ const sections = computed(() => [
const authItems = computed(() => {
const examples = authExamples(origin.value)
return [
{ label: 'curl', value: 'curl', code: examples.curl, lang: 'shell', title: 'Shell' },
{
label: 'fetch',
value: 'fetch',
code: examples.fetch,
lang: 'javascript',
title: 'JavaScript',
},
{ k: 'curl', label: 'curl', code: examples.curl },
{ k: 'fetch', label: 'fetch', code: examples.fetch },
]
})
@@ -141,10 +132,12 @@ function updateActive() {
}
const limit = parent.getBoundingClientRect().top + SPY_OFFSET_PX
let current = sections.value[0]!.id
let currentTop = Number.NEGATIVE_INFINITY
for (const section of sections.value) {
const target = sectionElement(section.id)
if (target && target.getBoundingClientRect().top <= limit) {
const top = sectionElement(section.id)?.getBoundingClientRect().top
if (top !== undefined && top <= limit && top > currentTop) {
current = section.id
currentTop = top
}
}
activeSection.value = current
@@ -159,15 +152,14 @@ onMounted(() => {
onBeforeUnmount(() => scroller?.removeEventListener('scroll', updateActive))
const SECTION_TITLE = 'text-lg font-semibold text-highlighted'
const SECTION_CLASS = 'flex scroll-mt-16 flex-col gap-2.5 lg:scroll-mt-8'
const NOTE_ICON = 'mt-0.75 size-4 shrink-0 text-info'
const AUTH_CARD = 'flex flex-col gap-2.5 border border-default bg-default p-4'
const CARD_TITLE = 'text-lg leading-5.5 font-semibold text-highlighted'
const CARD_TITLE = 'text-md/6 font-semibold text-highlighted'
</script>
<template>
<DashboardShell :mobile-title="t('Integration')">
<DashboardShell compact-padding :mobile-title="t('Integration')">
<div ref="root" class="flex flex-col lg:flex-row lg:items-start lg:gap-10">
<div class="flex min-w-0 flex-1 flex-col gap-7 lg:gap-8">
<div class="flex flex-col gap-1.5">
@@ -186,7 +178,7 @@ const CARD_TITLE = 'text-lg leading-5.5 font-semibold text-highlighted'
list: 'gap-1',
}"
/>
<h1 class="text-xl font-semibold text-highlighted lg:text-2xl">
<h1 class="text-xl font-semibold text-highlighted">
{{ t('API reference') }}
</h1>
<p class="text-base text-muted">
@@ -204,24 +196,7 @@ const CARD_TITLE = 'text-lg leading-5.5 font-semibold text-highlighted'
<div class="flex flex-col gap-1.5">
<span class="font-medium text-highlighted">{{ t('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>
<CodeSnippet :tabs="baseUrlTabs" />
</div>
<section
@@ -272,27 +247,7 @@ const CARD_TITLE = 'text-lg leading-5.5 font-semibold text-highlighted'
)
"
/></span>
<UTabs
v-model="authTab"
:items="authItems"
variant="link"
color="primary"
:ui="{
root: 'gap-0 border border-default',
list: 'gap-4 border-b border-default px-3 py-0 before:hidden',
trigger:
'h-9 grow-0 px-0 text-sm font-medium data-[state=inactive]:font-medium data-[state=inactive]:text-toned',
content: 'mt-0',
}"
>
<template #content="{ item }">
<CodeBlock
:label="(item as (typeof authItems)[number]).title"
:lang="(item as (typeof authItems)[number]).lang"
:code="(item as (typeof authItems)[number]).code"
/>
</template>
</UTabs>
<CodeSnippet v-model:active="authTab" :tabs="authItems" />
<span class="text-pretty text-muted"
><CodeText
:text="
@@ -343,6 +298,8 @@ const CARD_TITLE = 'text-lg leading-5.5 font-semibold text-highlighted'
</div>
</section>
<IntegrationImages :origin="origin" />
<section data-anchor="session" aria-labelledby="h-session" :class="SECTION_CLASS">
<div class="flex flex-wrap items-baseline gap-2.5">
<h2 id="h-session" :class="SECTION_TITLE">{{ t('Session only') }}</h2>
@@ -399,18 +356,7 @@ const CARD_TITLE = 'text-lg leading-5.5 font-semibold text-highlighted'
</div>
</template>
</UTable>
<div class="min-w-0 border border-default bg-elevated">
<div
class="flex h-8 items-center border-b border-default px-3 font-mono text-xs font-medium text-muted"
>
{{ t('Error response · text/plain') }}
</div>
<pre
tabindex="0"
class="overflow-x-auto p-3 font-mono text-code whitespace-pre text-default"
>{{ ERROR_SAMPLE }}</pre
>
</div>
<CodeSnippet :tabs="errorSampleTabs" />
</section>
<section data-anchor="notes" aria-labelledby="h-notes" :class="SECTION_CLASS">