feat: Vue 3 Basis mit TailwindCSS, PrimeVue, i18n und Dark/Light Mode

- Vue 3 + Vite Setup
- TailwindCSS mit Dark Mode Support
- PrimeVue 4 mit Aura Theme
- vue-i18n (Deutsch/Englisch)
- Vue Router + Pinia
- Responsive Navbar mit Theme Toggle & Language Switcher
This commit is contained in:
2026-02-10 22:23:30 +00:00
parent 48fd98b0dc
commit 46b6a87505
16 changed files with 389 additions and 2 deletions

13
src/App.vue Normal file
View File

@@ -0,0 +1,13 @@
<script setup>
import { RouterView } from 'vue-router'
import Navbar from './components/Navbar.vue'
</script>
<template>
<div class="min-h-screen">
<Navbar />
<main class="container mx-auto px-4 py-8">
<RouterView />
</main>
</div>
</template>

77
src/components/Navbar.vue Normal file
View File

@@ -0,0 +1,77 @@
<script setup>
import { ref, onMounted } from 'vue'
import { useI18n } from 'vue-i18n'
import Button from 'primevue/button'
import Select from 'primevue/select'
const { locale, t } = useI18n()
const isDark = ref(false)
const languages = [
{ code: 'de', name: 'Deutsch' },
{ code: 'en', name: 'English' }
]
onMounted(() => {
isDark.value = document.documentElement.classList.contains('dark') ||
localStorage.getItem('theme') === 'dark' ||
(!localStorage.getItem('theme') && window.matchMedia('(prefers-color-scheme: dark)').matches)
updateTheme()
})
function toggleTheme() {
isDark.value = !isDark.value
updateTheme()
}
function updateTheme() {
if (isDark.value) {
document.documentElement.classList.add('dark')
localStorage.setItem('theme', 'dark')
} else {
document.documentElement.classList.remove('dark')
localStorage.setItem('theme', 'light')
}
}
function changeLocale(event) {
locale.value = event.value
localStorage.setItem('locale', event.value)
}
</script>
<template>
<nav class="bg-white dark:bg-gray-800 shadow-md">
<div class="container mx-auto px-4">
<div class="flex items-center justify-between h-16">
<div class="flex items-center">
<span class="text-xl font-bold text-primary-600 dark:text-primary-400">
Vue3 Basis
</span>
</div>
<div class="flex items-center gap-4">
<!-- Language Switcher -->
<Select
:modelValue="locale"
:options="languages"
optionLabel="name"
optionValue="code"
@update:modelValue="changeLocale"
class="w-32"
/>
<!-- Theme Toggle -->
<Button
:icon="isDark ? 'pi pi-sun' : 'pi pi-moon'"
severity="secondary"
text
rounded
@click="toggleTheme"
:aria-label="t('nav.toggleTheme')"
/>
</div>
</div>
</div>
</nav>
</template>

27
src/locales/de.json Normal file
View File

@@ -0,0 +1,27 @@
{
"nav": {
"toggleTheme": "Theme wechseln"
},
"home": {
"title": "Willkommen bei Vue3 Basis",
"getStarted": "Loslegen",
"features": {
"fast": {
"title": "Blitzschnell",
"desc": "Mit Vite und Vue 3 für optimale Performance gebaut."
},
"themes": {
"title": "Dark & Light Mode",
"desc": "Nahtloser Wechsel zwischen hellem und dunklem Design."
},
"i18n": {
"title": "Mehrsprachig",
"desc": "Vollständige Internationalisierung mit vue-i18n."
}
}
},
"about": {
"title": "Über uns",
"content": "Vue3 Basis ist eine moderne Starter-Vorlage mit TailwindCSS, PrimeVue und i18n."
}
}

27
src/locales/en.json Normal file
View File

@@ -0,0 +1,27 @@
{
"nav": {
"toggleTheme": "Toggle theme"
},
"home": {
"title": "Welcome to Vue3 Basis",
"getStarted": "Get Started",
"features": {
"fast": {
"title": "Lightning Fast",
"desc": "Built with Vite and Vue 3 for optimal performance."
},
"themes": {
"title": "Dark & Light Mode",
"desc": "Seamless switching between light and dark themes."
},
"i18n": {
"title": "Multilingual",
"desc": "Full internationalization support with vue-i18n."
}
}
},
"about": {
"title": "About",
"content": "Vue3 Basis is a modern starter template with TailwindCSS, PrimeVue and i18n."
}
}

34
src/main.js Normal file
View File

@@ -0,0 +1,34 @@
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { createI18n } from 'vue-i18n'
import PrimeVue from 'primevue/config'
import Aura from '@primevue/themes/aura'
import 'primeicons/primeicons.css'
import './style.css'
import App from './App.vue'
import router from './router'
import de from './locales/de.json'
import en from './locales/en.json'
const i18n = createI18n({
legacy: false,
locale: localStorage.getItem('locale') || 'de',
fallbackLocale: 'en',
messages: { de, en }
})
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(i18n)
app.use(PrimeVue, {
theme: {
preset: Aura,
options: {
darkModeSelector: '.dark'
}
}
})
app.mount('#app')

20
src/router/index.js Normal file
View File

@@ -0,0 +1,20 @@
import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: HomeView
},
{
path: '/about',
name: 'about',
component: () => import('../views/AboutView.vue')
}
]
})
export default router

15
src/style.css Normal file
View File

@@ -0,0 +1,15 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
}
body {
@apply bg-white text-gray-900 dark:bg-gray-900 dark:text-gray-100;
min-height: 100vh;
transition: background-color 0.3s, color 0.3s;
}

12
src/views/AboutView.vue Normal file
View File

@@ -0,0 +1,12 @@
<script setup>
import { useI18n } from 'vue-i18n'
const { t } = useI18n()
</script>
<template>
<div class="max-w-2xl mx-auto">
<h1 class="text-3xl font-bold mb-4">{{ t('about.title') }}</h1>
<p class="text-gray-600 dark:text-gray-400">{{ t('about.content') }}</p>
</div>
</template>

51
src/views/HomeView.vue Normal file
View File

@@ -0,0 +1,51 @@
<script setup>
import { useI18n } from 'vue-i18n'
import Card from 'primevue/card'
import Button from 'primevue/button'
const { t } = useI18n()
</script>
<template>
<div class="space-y-8">
<h1 class="text-4xl font-bold text-center">
{{ t('home.title') }}
</h1>
<div class="grid md:grid-cols-3 gap-6">
<Card>
<template #title>
<i class="pi pi-bolt text-primary-500 mr-2"></i>
{{ t('home.features.fast.title') }}
</template>
<template #content>
{{ t('home.features.fast.desc') }}
</template>
</Card>
<Card>
<template #title>
<i class="pi pi-palette text-primary-500 mr-2"></i>
{{ t('home.features.themes.title') }}
</template>
<template #content>
{{ t('home.features.themes.desc') }}
</template>
</Card>
<Card>
<template #title>
<i class="pi pi-globe text-primary-500 mr-2"></i>
{{ t('home.features.i18n.title') }}
</template>
<template #content>
{{ t('home.features.i18n.desc') }}
</template>
</Card>
</div>
<div class="text-center">
<Button :label="t('home.getStarted')" icon="pi pi-arrow-right" iconPos="right" />
</div>
</div>
</template>