125 lines
5.1 KiB
Vue
125 lines
5.1 KiB
Vue
<script setup lang="ts">
|
|
const tabs = ['cURL', 'JavaScript', 'Python'] as const
|
|
type Tab = typeof tabs[number]
|
|
|
|
const activeTab = ref<Tab>('cURL')
|
|
|
|
const code: Record<Tab, string> = {
|
|
cURL: `# Get all EU VAT rates
|
|
curl https://vat-api.eu/api/v1/rates
|
|
|
|
# Get rates for a specific country
|
|
curl https://vat-api.eu/api/v1/rates/DE`,
|
|
JavaScript: `const response = await fetch('https://vat-api.eu/api/v1/rates/DE');
|
|
const data = await response.json();
|
|
console.log(data.standard_rate); // 19`,
|
|
Python: `import requests
|
|
|
|
response = requests.get('https://vat-api.eu/api/v1/rates/DE')
|
|
data = response.json()
|
|
print(data['standard_rate']) # 19`,
|
|
}
|
|
|
|
const highlighted: Record<Tab, string> = {
|
|
cURL: highlightBash(code.cURL),
|
|
JavaScript: highlightJS(code.JavaScript),
|
|
Python: highlightPython(code.Python),
|
|
}
|
|
|
|
function highlightBash(src: string): string {
|
|
return src
|
|
.replace(/(#.*)/g, '<span style="color:#8b949e">$1</span>')
|
|
.replace(/(curl)\s/g, '<span style="color:#ff7b72">$1</span> ')
|
|
.replace(/(https?:\/\/[^\s]+)/g, '<span style="color:#a5d6ff">$1</span>')
|
|
}
|
|
|
|
function highlightJS(src: string): string {
|
|
return src
|
|
.replace(/(\/\/\s*\d+)/g, '<span style="color:#8b949e">$1</span>')
|
|
.replace(/(const|await)\s/g, '<span style="color:#ff7b72">$1</span> ')
|
|
.replace(/(fetch|json|log)\(/g, '<span style="color:#d2a8ff">$1</span>(')
|
|
.replace(/('https?:\/\/[^']*')/g, '<span style="color:#a5d6ff">$1</span>')
|
|
.replace(/(\.standard_rate)/g, '<span style="color:#79c0ff">$1</span>')
|
|
.replace(/(console)\./g, '<span style="color:#79c0ff">$1</span>.')
|
|
.replace(/(response)\./g, '<span style="color:#79c0ff">$1</span>.')
|
|
}
|
|
|
|
function highlightPython(src: string): string {
|
|
return src
|
|
.replace(/(#\s*\d+)/g, '<span style="color:#8b949e">$1</span>')
|
|
.replace(/(import|from)\s/g, '<span style="color:#ff7b72">$1</span> ')
|
|
.replace(/(requests)/g, '<span style="color:#79c0ff">$1</span>')
|
|
.replace(/('https?:\/\/[^']*')/g, '<span style="color:#a5d6ff">$1</span>')
|
|
.replace(/(\['standard_rate'\])/g, '<span style="color:#79c0ff">$1</span>')
|
|
.replace(/(print|get)\(/g, '<span style="color:#d2a8ff">$1</span>(')
|
|
.replace(/(response)\./g, '<span style="color:#79c0ff">$1</span>.')
|
|
}
|
|
|
|
const copied = ref(false)
|
|
|
|
async function copyCode() {
|
|
await navigator.clipboard.writeText(code[activeTab.value])
|
|
copied.value = true
|
|
setTimeout(() => { copied.value = false }, 2000)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<section id="examples" class="section-padding">
|
|
<div class="section-container">
|
|
<div class="text-center mb-10 animate-on-scroll">
|
|
<h2 class="text-title md:text-display-sm text-ink">
|
|
Quick start
|
|
</h2>
|
|
<p class="mt-3 text-ink-muted max-w-lg mx-auto">
|
|
Integrate EU VAT rates into your project in seconds.
|
|
</p>
|
|
</div>
|
|
|
|
<div class="animate-on-scroll max-w-2xl mx-auto">
|
|
<div class="rounded-2xl border border-surface-border overflow-hidden shadow-card bg-white">
|
|
<!-- Tab bar -->
|
|
<div class="flex items-center justify-between border-b border-surface-border bg-surface-soft px-1.5">
|
|
<div class="flex">
|
|
<button
|
|
v-for="tab in tabs"
|
|
:key="tab"
|
|
class="px-4 py-3 text-sm font-medium transition-colors relative"
|
|
:class="activeTab === tab
|
|
? 'text-eu-blue'
|
|
: 'text-ink-muted hover:text-ink-secondary'"
|
|
@click="activeTab = tab"
|
|
>
|
|
{{ tab }}
|
|
<span
|
|
v-if="activeTab === tab"
|
|
class="absolute bottom-0 left-2 right-2 h-0.5 bg-eu-blue rounded-full"
|
|
/>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Copy button -->
|
|
<button
|
|
class="flex items-center gap-1.5 px-3 py-1.5 mr-1.5 rounded-lg text-xs font-medium text-ink-muted hover:text-ink-secondary hover:bg-surface-muted transition-colors"
|
|
@click="copyCode"
|
|
>
|
|
<svg v-if="!copied" class="w-3.5 h-3.5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="M15.666 3.888A2.25 2.25 0 0 0 13.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 0 1-.75.75H9.75a.75.75 0 0 1-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 0 1-2.25 2.25H6.75A2.25 2.25 0 0 1 4.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 0 1 1.927-.184" />
|
|
</svg>
|
|
<svg v-else class="w-3.5 h-3.5 text-green-600" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
|
<path stroke-linecap="round" stroke-linejoin="round" d="m4.5 12.75 6 6 9-13.5" />
|
|
</svg>
|
|
{{ copied ? 'Copied!' : 'Copy' }}
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Code -->
|
|
<div class="code-block p-5">
|
|
<pre class="text-[13px] leading-6" v-html="highlighted[activeTab]" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</template>
|