355df8dbbe
Complete visual overhaul of all pages and components with generous spacing, bold typography, hover effects, gradient accents, and section differentiation. Hero features animated terminal mockup and gradient text. Cards use hover transforms with brand-colored shadows. CTAs use gradient backgrounds. All i18n keys, data structures, SEO meta, and composable logic preserved.
81 lines
2.1 KiB
Vue
81 lines
2.1 KiB
Vue
<script setup lang="ts">
|
|
import type { Technology } from '~~/shared/types'
|
|
import { techStack } from '~/data/techstack'
|
|
|
|
interface Props {
|
|
tech: Technology | string
|
|
showLevel?: boolean
|
|
showImage?: boolean
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
showLevel: true,
|
|
showImage: true,
|
|
})
|
|
|
|
const techMapping: Record<string, string> = {
|
|
'Three.js': 'JavaScript',
|
|
'WebGL': 'JavaScript',
|
|
'Discord.js': 'JavaScript',
|
|
'Express': 'Node.js',
|
|
'Canvas': 'JavaScript',
|
|
'Insta.js': 'JavaScript',
|
|
'Instagram API': 'JavaScript',
|
|
'Crowdin API': 'JavaScript',
|
|
'Cron': 'Node.js',
|
|
}
|
|
|
|
const techData = computed((): Technology => {
|
|
if (typeof props.tech !== 'string') {
|
|
return props.tech
|
|
}
|
|
|
|
const techName = props.tech
|
|
const allTechs = Object.values(techStack).flat()
|
|
|
|
let found = allTechs.find((t) => t.name.toLowerCase() === techName.toLowerCase())
|
|
|
|
if (!found && techMapping[techName]) {
|
|
found = allTechs.find((t) => t.name.toLowerCase() === techMapping[techName].toLowerCase())
|
|
}
|
|
|
|
return found ?? { name: techName, image: '', level: 'Intermediate' as const }
|
|
})
|
|
|
|
const levelColor = computed(() => {
|
|
switch (techData.value.level) {
|
|
case 'Advanced':
|
|
return 'success' as const
|
|
case 'Intermediate':
|
|
return 'primary' as const
|
|
case 'Beginner':
|
|
return 'neutral' as const
|
|
default:
|
|
return 'neutral' as const
|
|
}
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
class="inline-flex items-center gap-2 px-3 py-1.5 rounded-lg bg-gray-50 dark:bg-gray-800 border border-gray-200 dark:border-gray-700/50 transition-colors hover:border-brand-500/30"
|
|
itemscope
|
|
itemtype="https://schema.org/ComputerLanguage"
|
|
>
|
|
<NuxtImg
|
|
v-if="showImage && techData.image"
|
|
:src="techData.image"
|
|
:alt="`${techData.name} logo`"
|
|
width="20"
|
|
height="20"
|
|
loading="lazy"
|
|
class="shrink-0"
|
|
itemprop="image"
|
|
/>
|
|
<span class="text-sm font-medium text-gray-700 dark:text-gray-300" itemprop="name">{{ techData.name }}</span>
|
|
<UBadge v-if="showLevel" :color="levelColor" variant="subtle" size="xs">
|
|
{{ techData.level }}
|
|
</UBadge>
|
|
</div>
|
|
</template>
|