feat: init
This commit is contained in:
124
app/components/CodeExamples.vue
Normal file
124
app/components/CodeExamples.vue
Normal file
@@ -0,0 +1,124 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user