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