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:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
.DS_Store
|
||||||
|
*.local
|
||||||
42
README.md
42
README.md
@@ -1,3 +1,41 @@
|
|||||||
# vue3-basis
|
# Vue3 Basis
|
||||||
|
|
||||||
Vue 3 Basis mit TailwindCSS, PrimeVUE, i18n und Dark/Light Mode
|
Eine moderne Vue 3 Starter-Vorlage mit allen wichtigen Features.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- ⚡ **Vite** - Blitzschneller Build
|
||||||
|
- 🎨 **TailwindCSS** - Utility-first CSS
|
||||||
|
- 🌙 **Dark/Light Mode** - Automatischer Theme-Switch
|
||||||
|
- 🌍 **i18n** - Deutsch & Englisch
|
||||||
|
- 💎 **PrimeVue 4** - UI-Komponenten
|
||||||
|
- 📦 **Pinia** - State Management
|
||||||
|
- 🛣️ **Vue Router** - SPA Navigation
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Struktur
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── components/ # Wiederverwendbare Komponenten
|
||||||
|
├── views/ # Seiten-Komponenten
|
||||||
|
├── locales/ # Sprachdateien (de, en)
|
||||||
|
├── router/ # Vue Router Konfiguration
|
||||||
|
├── stores/ # Pinia Stores
|
||||||
|
└── composables/ # Composition API Funktionen
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
Erstellt von OpenClaw 🤖
|
||||||
|
|||||||
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Vue3 Basis</title>
|
||||||
|
<link rel="icon" href="/favicon.ico">
|
||||||
|
</head>
|
||||||
|
<body class="antialiased">
|
||||||
|
<div id="app"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
27
package.json
Normal file
27
package.json
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"name": "vue3-basis",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "vite",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^3.4.0",
|
||||||
|
"vue-router": "^4.2.0",
|
||||||
|
"vue-i18n": "^9.9.0",
|
||||||
|
"pinia": "^2.1.0",
|
||||||
|
"primevue": "^4.0.0",
|
||||||
|
"@primevue/themes": "^4.0.0",
|
||||||
|
"primeicons": "^7.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@vitejs/plugin-vue": "^5.0.0",
|
||||||
|
"vite": "^5.0.0",
|
||||||
|
"tailwindcss": "^3.4.0",
|
||||||
|
"postcss": "^8.4.0",
|
||||||
|
"autoprefixer": "^10.4.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
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>
|
||||||
12
tailwind.config.js
Normal file
12
tailwind.config.js
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
export default {
|
||||||
|
content: [
|
||||||
|
"./index.html",
|
||||||
|
"./src/**/*.{vue,js,ts,jsx,tsx}",
|
||||||
|
],
|
||||||
|
darkMode: 'class',
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
11
vite.config.js
Normal file
11
vite.config.js
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [vue()],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': '/src'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user