feat: integrate PrimeVue and TailwindCSS for enhanced UI components

- Added dependencies for PrimeVue, PrimeUI themes, and TailwindCSS in package.json.
- Replaced HelloWorld component with ColorDemo in App.vue to showcase color customization.
- Updated HelloWorld component to use PrimeVue Button component.
- Configured main.ts to set up PrimeVue with a custom theme and dark mode support.
- Enhanced vite.config.ts to include TailwindCSS and auto-import for PrimeVue components.
- Created ColorDemo.vue for color customization interface.
- Added main.css for global styles, including Tailwind and PrimeUI styles.
- Implemented AppConfig.vue and AppTopbar.vue for layout and theme configuration.
- Developed useLayout composable for managing color themes and dark mode toggle.
This commit is contained in:
Edgar Mendez Mendoza 2025-11-05 22:14:50 -06:00
parent d058a27882
commit dd9ae71bd6
13 changed files with 1734 additions and 129 deletions

22
components.d.ts vendored Normal file
View File

@ -0,0 +1,22 @@
/* eslint-disable */
// @ts-nocheck
// biome-ignore lint: disable
// oxlint-disable
// ------
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
AppConfig: typeof import('./src/components/Holos/AppConfig.vue')['default']
AppTopbar: typeof import('./src/components/Holos/AppTopbar.vue')['default']
Button: typeof import('primevue/button')['default']
HelloWorld: typeof import('./src/components/HelloWorld.vue')['default']
}
export interface GlobalDirectives {
StyleClass: typeof import('primevue/styleclass')['default']
}
}

View File

@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>golscontros-frontend-v1</title>
<title>Golscontrols V1</title>
</head>
<body>
<div id="app"></div>

1065
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,6 +9,14 @@
"preview": "vite preview"
},
"dependencies": {
"@primeuix/themes": "^1.2.5",
"@primevue/auto-import-resolver": "^4.4.1",
"@tailwindcss/vite": "^4.1.16",
"@vueuse/core": "^14.0.0",
"primeicons": "^7.0.0",
"primevue": "^4.4.1",
"tailwindcss-primeui": "^0.6.1",
"unplugin-vue-components": "^30.0.0",
"vue": "^3.5.22"
},
"devDependencies": {

View File

@ -1,30 +1,9 @@
<script setup lang="ts">
import ColorDemo from './ColorDemo.vue';
import HelloWorld from './components/HelloWorld.vue'
</script>
<template>
<div>
<a href="https://vite.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<a href="https://vuejs.org/" target="_blank">
<img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
</a>
</div>
<HelloWorld msg="Vite + Vue" />
<ColorDemo />
</template>
<style scoped>
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

80
src/ColorDemo.vue Normal file
View File

@ -0,0 +1,80 @@
<script setup lang="ts">
import AppTopbar from './components/Holos/AppTopbar.vue';
</script>
<template>
<div class="min-h-screen bg-surface-50 dark:bg-surface-950">
<AppTopbar />
<div class="p-6">
<div class="max-w-7xl mx-auto">
<h1 class="text-3xl font-bold text-surface-900 dark:text-surface-0 mb-4">
Personalización de Colores
</h1>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- Tarjeta de ejemplo 1 -->
<div class="bg-surface-0 dark:bg-surface-900 rounded-lg p-6 border border-surface-200 dark:border-surface-700">
<h2 class="text-xl font-semibold text-surface-900 dark:text-surface-0 mb-3">
Colores Primarios
</h2>
<p class="text-surface-600 dark:text-surface-400 mb-4">
Los colores primarios se usan para botones, enlaces y elementos destacados.
</p>
<button class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary-600 transition-colors">
Botón Primario
</button>
</div>
<!-- Tarjeta de ejemplo 2 -->
<div class="bg-surface-0 dark:bg-surface-900 rounded-lg p-6 border border-surface-200 dark:border-surface-700">
<h2 class="text-xl font-semibold text-surface-900 dark:text-surface-0 mb-3">
Colores de Superficie
</h2>
<p class="text-surface-600 dark:text-surface-400 mb-4">
Los colores de superficie definen el fondo y los tonos neutros de la aplicación.
</p>
<div class="flex gap-2">
<div class="w-8 h-8 rounded bg-surface-100 dark:bg-surface-800" title="surface-100"></div>
<div class="w-8 h-8 rounded bg-surface-200 dark:bg-surface-700" title="surface-200"></div>
<div class="w-8 h-8 rounded bg-surface-300 dark:bg-surface-600" title="surface-300"></div>
<div class="w-8 h-8 rounded bg-surface-400 dark:bg-surface-500" title="surface-400"></div>
</div>
</div>
<!-- Tarjeta de ejemplo 3 -->
<div class="bg-surface-0 dark:bg-surface-900 rounded-lg p-6 border border-surface-200 dark:border-surface-700">
<h2 class="text-xl font-semibold text-surface-900 dark:text-surface-0 mb-3">
Modo Oscuro
</h2>
<p class="text-surface-600 dark:text-surface-400 mb-4">
Usa el botón en la barra superior para cambiar entre modo claro y oscuro.
</p>
<div class="flex items-center gap-3">
<i class="pi pi-moon text-2xl text-primary"></i>
<span class="text-surface-700 dark:text-surface-300">Tema adaptable</span>
</div>
</div>
<!-- Tarjeta de ejemplo 4 -->
<div class="bg-surface-0 dark:bg-surface-900 rounded-lg p-6 border border-surface-200 dark:border-surface-700">
<h2 class="text-xl font-semibold text-surface-900 dark:text-surface-0 mb-3">
Paleta de Colores
</h2>
<p class="text-surface-600 dark:text-surface-400 mb-4">
Haz clic en el ícono de paleta en la barra superior para cambiar colores.
</p>
<div class="flex items-center gap-3">
<i class="pi pi-palette text-2xl text-primary"></i>
<span class="text-surface-700 dark:text-surface-300">16+ colores disponibles</span>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
/* Estilos adicionales si es necesario */
</style>

View File

@ -0,0 +1,33 @@
@import "tailwindcss";
@import "tailwindcss-primeui";
@import "primeicons/primeicons.css";
@custom-variant dark (&:where(.p-dark, .p-dark *));
:root {
/* Primary Colors - Emerald por defecto */
--p-primary-50: #ecfdf5;
--p-primary-100: #d1fae5;
--p-primary-200: #a7f3d0;
--p-primary-300: #6ee7b7;
--p-primary-400: #34d399;
--p-primary-500: #10b981;
--p-primary-600: #059669;
--p-primary-700: #047857;
--p-primary-800: #065f46;
--p-primary-900: #064e3b;
--p-primary-950: #022c22;
/* Surface Colors - Slate por defecto */
--p-surface-0: #ffffff;
--p-surface-50: #f8fafc;
--p-surface-100: #f1f5f9;
--p-surface-200: #e2e8f0;
--p-surface-300: #cbd5e1;
--p-surface-400: #94a3b8;
--p-surface-500: #64748b;
--p-surface-600: #475569;
--p-surface-700: #334155;
--p-surface-800: #1e293b;
--p-surface-900: #0f172a;
--p-surface-950: #020617;
}

View File

@ -1,41 +1,9 @@
<script setup lang="ts">
import { ref } from 'vue'
defineProps<{ msg: string }>()
const count = ref(0)
<script setup>
</script>
<template>
<h1>{{ msg }}</h1>
<div class="card">
<button type="button" @click="count++">count is {{ count }}</button>
<p>
Edit
<code>components/HelloWorld.vue</code> to test HMR
</p>
</div>
<p>
Check out
<a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
>create-vue</a
>, the official Vue + Vite starter
</p>
<p>
Learn more about IDE Support for Vue in the
<a
href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
target="_blank"
>Vue Docs Scaling up Guide</a
>.
</p>
<p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
</template>
<style scoped>
.read-the-docs {
color: #888;
}
</style>
<Button>
Hola mundo
<!-- Los componentes de PrimeVue se usan directamente sin importar -->
</Button>
</template>

View File

@ -0,0 +1,59 @@
<script setup lang="ts">
import { useLayout } from "../../composables/useLayout";
const { primaryColors, surfaces, primary, surface, updateColors } = useLayout();
</script>
<template>
<div
class="absolute top-16 right-0 w-64 p-4 bg-white dark:bg-surface-900 rounded-md shadow-lg border border-surface-200 dark:border-surface-700 origin-top z-50 hidden"
>
<div class="flex flex-col gap-4">
<div>
<span class="text-sm text-surface-600 dark:text-surface-400 font-semibold">Color Primario</span>
<div class="pt-2 flex gap-2 flex-wrap justify-between">
<button
v-for="pc of primaryColors"
:key="pc.name"
type="button"
:title="pc.name"
:class="[
'border-none w-5 h-5 rounded-full p-0 cursor-pointer focus:outline-none focus:ring-2 focus:ring-offset-2',
{
'ring-2 ring-offset-2 ring-surface-950 dark:ring-surface-0': primary === pc.name,
},
]"
:style="{ backgroundColor: pc.palette['500'] }"
@click="updateColors('primary', pc.name)"
/>
</div>
</div>
<div>
<span class="text-sm text-surface-600 dark:text-surface-400 font-semibold">Color de Superficie</span>
<div class="pt-2 flex gap-2 flex-wrap justify-between">
<button
v-for="s of surfaces"
:key="s.name"
type="button"
:title="s.name"
:class="[
'border border-surface-200 dark:border-surface-700 w-5 h-5 rounded-full p-0 cursor-pointer focus:outline-none focus:ring-2 focus:ring-offset-2',
{
'ring-2 ring-offset-2 ring-surface-950 dark:ring-surface-0': surface === s.name,
},
]"
:style="{ backgroundColor: s.palette['500'] }"
@click="updateColors('surface', s.name)"
/>
</div>
</div>
</div>
</div>
</template>
<style scoped>
button:focus-visible {
outline: 2px solid var(--p-primary-500);
outline-offset: 2px;
}
</style>

View File

@ -0,0 +1,80 @@
<script setup lang="ts">
import { useLayout } from "../../composables/useLayout";
import AppConfig from "./AppConfig.vue";
const { isDarkMode, toggleDarkMode } = useLayout();
</script>
<template>
<div class="bg-surface-0 dark:bg-surface-900 border-b border-surface-200 dark:border-surface-700 px-6 py-4">
<div class="flex items-center justify-between">
<div class="flex items-center gap-3">
<span class="text-xl font-semibold text-surface-900 dark:text-surface-0">
Mi Aplicación
</span>
</div>
<div class="flex items-center gap-2">
<!-- Botón de modo oscuro -->
<button
type="button"
class="w-10 h-10 flex items-center justify-center rounded-full hover:bg-surface-100 dark:hover:bg-surface-800 transition-all text-surface-900 dark:text-surface-0 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 dark:focus-visible:ring-offset-surface-950"
@click="toggleDarkMode"
:title="isDarkMode ? 'Modo claro' : 'Modo oscuro'"
>
<i :class="['pi', isDarkMode ? 'pi-sun' : 'pi-moon']" />
</button>
<!-- Botón de configuración de colores -->
<div class="relative">
<button
v-styleclass="{
selector: '@next',
enterFromClass: 'hidden',
enterActiveClass: 'animate-scalein',
leaveToClass: 'hidden',
leaveActiveClass: 'animate-fadeout',
hideOnOutsideClick: true,
}"
type="button"
class="w-10 h-10 flex items-center justify-center rounded-full hover:bg-surface-100 dark:hover:bg-surface-800 transition-all text-surface-900 dark:text-surface-0 focus-visible:outline-hidden focus-visible:ring-1 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 dark:focus-visible:ring-offset-surface-950"
title="Configurar colores"
>
<i class="pi pi-palette" />
</button>
<AppConfig />
</div>
</div>
</div>
</div>
</template>
<style scoped>
.animate-scalein {
animation: scalein 0.15s ease-in;
}
.animate-fadeout {
animation: fadeout 0.15s ease-out;
}
@keyframes scalein {
from {
opacity: 0;
transform: scale(0.9);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes fadeout {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
</style>

View File

@ -0,0 +1,400 @@
import { updatePrimaryPalette, updateSurfacePalette } from "@primeuix/themes";
import { computed, ref } from "vue";
const appState = ref({
primary: "emerald",
surface: "slate",
darkMode: false
});
const primaryColors = ref([
{
name: "emerald",
palette: {
50: "#ecfdf5",
100: "#d1fae5",
200: "#a7f3d0",
300: "#6ee7b7",
400: "#34d399",
500: "#10b981",
600: "#059669",
700: "#047857",
800: "#065f46",
900: "#064e3b",
950: "#022c22"
}
},
{
name: "green",
palette: {
50: "#f0fdf4",
100: "#dcfce7",
200: "#bbf7d0",
300: "#86efac",
400: "#4ade80",
500: "#22c55e",
600: "#16a34a",
700: "#15803d",
800: "#166534",
900: "#14532d",
950: "#052e16"
}
},
{
name: "lime",
palette: {
50: "#f7fee7",
100: "#ecfccb",
200: "#d9f99d",
300: "#bef264",
400: "#a3e635",
500: "#84cc16",
600: "#65a30d",
700: "#4d7c0f",
800: "#3f6212",
900: "#365314",
950: "#1a2e05"
}
},
{
name: "orange",
palette: {
50: "#fff7ed",
100: "#ffedd5",
200: "#fed7aa",
300: "#fdba74",
400: "#fb923c",
500: "#f97316",
600: "#ea580c",
700: "#c2410c",
800: "#9a3412",
900: "#7c2d12",
950: "#431407"
}
},
{
name: "amber",
palette: {
50: "#fffbeb",
100: "#fef3c7",
200: "#fde68a",
300: "#fcd34d",
400: "#fbbf24",
500: "#f59e0b",
600: "#d97706",
700: "#b45309",
800: "#92400e",
900: "#78350f",
950: "#451a03"
}
},
{
name: "yellow",
palette: {
50: "#fefce8",
100: "#fef9c3",
200: "#fef08a",
300: "#fde047",
400: "#facc15",
500: "#eab308",
600: "#ca8a04",
700: "#a16207",
800: "#854d0e",
900: "#713f12",
950: "#422006"
}
},
{
name: "teal",
palette: {
50: "#f0fdfa",
100: "#ccfbf1",
200: "#99f6e4",
300: "#5eead4",
400: "#2dd4bf",
500: "#14b8a6",
600: "#0d9488",
700: "#0f766e",
800: "#115e59",
900: "#134e4a",
950: "#042f2e"
}
},
{
name: "cyan",
palette: {
50: "#ecfeff",
100: "#cffafe",
200: "#a5f3fc",
300: "#67e8f9",
400: "#22d3ee",
500: "#06b6d4",
600: "#0891b2",
700: "#0e7490",
800: "#155e75",
900: "#164e63",
950: "#083344"
}
},
{
name: "sky",
palette: {
50: "#f0f9ff",
100: "#e0f2fe",
200: "#bae6fd",
300: "#7dd3fc",
400: "#38bdf8",
500: "#0ea5e9",
600: "#0284c7",
700: "#0369a1",
800: "#075985",
900: "#0c4a6e",
950: "#082f49"
}
},
{
name: "blue",
palette: {
50: "#eff6ff",
100: "#dbeafe",
200: "#bfdbfe",
300: "#93c5fd",
400: "#60a5fa",
500: "#3b82f6",
600: "#2563eb",
700: "#1d4ed8",
800: "#1e40af",
900: "#1e3a8a",
950: "#172554"
}
},
{
name: "indigo",
palette: {
50: "#eef2ff",
100: "#e0e7ff",
200: "#c7d2fe",
300: "#a5b4fc",
400: "#818cf8",
500: "#6366f1",
600: "#4f46e5",
700: "#4338ca",
800: "#3730a3",
900: "#312e81",
950: "#1e1b4b"
}
},
{
name: "violet",
palette: {
50: "#f5f3ff",
100: "#ede9fe",
200: "#ddd6fe",
300: "#c4b5fd",
400: "#a78bfa",
500: "#8b5cf6",
600: "#7c3aed",
700: "#6d28d9",
800: "#5b21b6",
900: "#4c1d95",
950: "#2e1065"
}
},
{
name: "purple",
palette: {
50: "#faf5ff",
100: "#f3e8ff",
200: "#e9d5ff",
300: "#d8b4fe",
400: "#c084fc",
500: "#a855f7",
600: "#9333ea",
700: "#7e22ce",
800: "#6b21a8",
900: "#581c87",
950: "#3b0764"
}
},
{
name: "fuchsia",
palette: {
50: "#fdf4ff",
100: "#fae8ff",
200: "#f5d0fe",
300: "#f0abfc",
400: "#e879f9",
500: "#d946ef",
600: "#c026d3",
700: "#a21caf",
800: "#86198f",
900: "#701a75",
950: "#4a044e"
}
},
{
name: "pink",
palette: {
50: "#fdf2f8",
100: "#fce7f3",
200: "#fbcfe8",
300: "#f9a8d4",
400: "#f472b6",
500: "#ec4899",
600: "#db2777",
700: "#be185d",
800: "#9d174d",
900: "#831843",
950: "#500724"
}
},
{
name: "rose",
palette: {
50: "#fff1f2",
100: "#ffe4e6",
200: "#fecdd3",
300: "#fda4af",
400: "#fb7185",
500: "#f43f5e",
600: "#e11d48",
700: "#be123c",
800: "#9f1239",
900: "#881337",
950: "#4c0519"
}
}
]);
const surfaces = ref([
{
name: "slate",
palette: {
0: "#ffffff",
50: "#f8fafc",
100: "#f1f5f9",
200: "#e2e8f0",
300: "#cbd5e1",
400: "#94a3b8",
500: "#64748b",
600: "#475569",
700: "#334155",
800: "#1e293b",
900: "#0f172a",
950: "#020617"
}
},
{
name: "gray",
palette: {
0: "#ffffff",
50: "#f9fafb",
100: "#f3f4f6",
200: "#e5e7eb",
300: "#d1d5db",
400: "#9ca3af",
500: "#6b7280",
600: "#4b5563",
700: "#374151",
800: "#1f2937",
900: "#111827",
950: "#030712"
}
},
{
name: "zinc",
palette: {
0: "#ffffff",
50: "#fafafa",
100: "#f4f4f5",
200: "#e4e4e7",
300: "#d4d4d8",
400: "#a1a1aa",
500: "#71717a",
600: "#52525b",
700: "#3f3f46",
800: "#27272a",
900: "#18181b",
950: "#09090b"
}
},
{
name: "neutral",
palette: {
0: "#ffffff",
50: "#fafafa",
100: "#f5f5f5",
200: "#e5e5e5",
300: "#d4d4d4",
400: "#a3a3a3",
500: "#737373",
600: "#525252",
700: "#404040",
800: "#262626",
900: "#171717",
950: "#0a0a0a"
}
},
{
name: "stone",
palette: {
0: "#ffffff",
50: "#fafaf9",
100: "#f5f5f4",
200: "#e7e5e4",
300: "#d6d3d1",
400: "#a8a29e",
500: "#78716c",
600: "#57534e",
700: "#44403c",
800: "#292524",
900: "#1c1917",
950: "#0c0a09"
}
}
]);
export function useLayout() {
function setPrimary(value: string) {
appState.value.primary = value;
}
function setSurface(value: string) {
appState.value.surface = value;
}
function toggleDarkMode() {
appState.value.darkMode = !appState.value.darkMode;
document.documentElement.classList.toggle("p-dark");
}
function updateColors(type: "primary" | "surface", colorName: string) {
if (type === "primary") {
setPrimary(colorName);
const color = primaryColors.value.find((c) => c.name === colorName);
if (color) {
updatePrimaryPalette(color.palette);
}
} else if (type === "surface") {
setSurface(colorName);
const surfaceColor = surfaces.value.find((s) => s.name === colorName);
if (surfaceColor) {
updateSurfacePalette(surfaceColor.palette);
}
}
}
const primary = computed(() => appState.value.primary);
const surface = computed(() => appState.value.surface);
const isDarkMode = computed(() => appState.value.darkMode);
return {
primaryColors,
surfaces,
primary,
surface,
isDarkMode,
toggleDarkMode,
updateColors
};
}

View File

@ -1,5 +1,22 @@
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import "./assets/styles/main.css";
createApp(App).mount('#app')
import Aura from "@primeuix/themes/aura";
import PrimeVue from "primevue/config";
import StyleClass from "primevue/styleclass";
import { createApp } from "vue";
import App from "./App.vue";
const app = createApp(App);
app.use(PrimeVue, {
theme: {
preset: Aura,
options: {
darkModeSelector: ".p-dark",
},
},
});
app.directive("styleclass", StyleClass);
app.mount("#app");

View File

@ -1,7 +1,17 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import tailwindcss from "@tailwindcss/vite";
import Components from 'unplugin-vue-components/vite';
import { PrimeVueResolver } from '@primevue/auto-import-resolver';
// https://vite.dev/config/
export default defineConfig({
plugins: [vue()],
})
plugins: [
vue(),
tailwindcss(),
Components({
resolvers: [
PrimeVueResolver()
]
})
]
});