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:
13
src/App.vue
Normal file
13
src/App.vue
Normal 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
77
src/components/Navbar.vue
Normal 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
27
src/locales/de.json
Normal 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
27
src/locales/en.json
Normal 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
34
src/main.js
Normal 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
20
src/router/index.js
Normal 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
15
src/style.css
Normal 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
12
src/views/AboutView.vue
Normal 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
51
src/views/HomeView.vue
Normal 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>
|
||||
Reference in New Issue
Block a user