refactor(ui): Rediseño completo de UI con Nuxt UI 4
- Nuevo layout responsivo mobile-first con tabs inferiores - Sidebar colapsable en desktop con cola de impresión - Sistema de templates reutilizables con localStorage - Soporte Dark/Light mode con UColorModeButton - Composables usePrintQueue y useTemplates para estado global - Componentes modulares: CommandBuilder, QuickActions, PrintQueue, QueueItem - Navegación por tabs: Constructor | Cola | Templates
This commit is contained in:
187
app/components/constructor/CommandBuilder.vue
Normal file
187
app/components/constructor/CommandBuilder.vue
Normal file
@@ -0,0 +1,187 @@
|
||||
<script setup lang="ts">
|
||||
const queue = usePrintQueue()
|
||||
|
||||
// Estado del formulario
|
||||
const text = ref('')
|
||||
const align = ref('')
|
||||
const font = ref('')
|
||||
const width = ref<number | undefined>()
|
||||
const height = ref<number | undefined>()
|
||||
const bold = ref(false)
|
||||
const underline = ref(false)
|
||||
const reverse = ref(false)
|
||||
const smooth = ref(false)
|
||||
const color = ref('')
|
||||
const feedLines = ref<number | undefined>()
|
||||
const cut = ref('')
|
||||
|
||||
// Opciones para selects
|
||||
const alignOptions = [
|
||||
{ label: '(sin cambio)', value: '' },
|
||||
{ label: 'Izquierda', value: 'left' },
|
||||
{ label: 'Centro', value: 'center' },
|
||||
{ label: 'Derecha', value: 'right' }
|
||||
]
|
||||
|
||||
const fontOptions = [
|
||||
{ label: '(sin cambio)', value: '' },
|
||||
{ label: 'Font A', value: 'font_a' },
|
||||
{ label: 'Font B', value: 'font_b' },
|
||||
{ label: 'Font C', value: 'font_c' },
|
||||
{ label: 'Font D', value: 'font_d' },
|
||||
{ label: 'Font E', value: 'font_e' },
|
||||
{ label: 'Special A', value: 'special_a' },
|
||||
{ label: 'Special B', value: 'special_b' }
|
||||
]
|
||||
|
||||
const colorOptions = [
|
||||
{ label: '(default)', value: '' },
|
||||
{ label: 'Color 1', value: 'color_1' },
|
||||
{ label: 'Color 2', value: 'color_2' },
|
||||
{ label: 'Color 3', value: 'color_3' },
|
||||
{ label: 'Color 4', value: 'color_4' }
|
||||
]
|
||||
|
||||
const cutOptions = [
|
||||
{ label: '(no cortar)', value: '' },
|
||||
{ label: 'Sin feed', value: 'no_feed' },
|
||||
{ label: 'Con feed', value: 'feed' },
|
||||
{ label: 'Reservar', value: 'reserve' },
|
||||
{ label: 'Full sin feed', value: 'no_feed_fullcut' },
|
||||
{ label: 'Full con feed', value: 'feed_fullcut' },
|
||||
{ label: 'Full reservar', value: 'reserve_fullcut' }
|
||||
]
|
||||
|
||||
const formatSections = [
|
||||
{ label: 'Alineación y Fuente', value: 'alignment', icon: 'i-heroicons-bars-3-bottom-left' },
|
||||
{ label: 'Tamaño', value: 'size', icon: 'i-heroicons-arrows-pointing-out' },
|
||||
{ label: 'Estilo', value: 'style', icon: 'i-heroicons-paint-brush' },
|
||||
{ label: 'Acciones finales', value: 'actions', icon: 'i-heroicons-scissors' }
|
||||
]
|
||||
|
||||
function resetForm() {
|
||||
text.value = ''
|
||||
align.value = ''
|
||||
font.value = ''
|
||||
width.value = undefined
|
||||
height.value = undefined
|
||||
bold.value = false
|
||||
underline.value = false
|
||||
reverse.value = false
|
||||
smooth.value = false
|
||||
color.value = ''
|
||||
feedLines.value = undefined
|
||||
cut.value = ''
|
||||
}
|
||||
|
||||
function queueText() {
|
||||
const ops: any[] = []
|
||||
|
||||
if (align.value) ops.push({ op: 'textAlign', align: align.value })
|
||||
if (font.value) ops.push({ op: 'textFont', font: font.value })
|
||||
if (width.value || height.value) {
|
||||
ops.push({ op: 'textSize', width: width.value, height: height.value })
|
||||
}
|
||||
ops.push({
|
||||
op: 'textStyle',
|
||||
em: bold.value,
|
||||
ul: underline.value,
|
||||
reverse: reverse.value,
|
||||
...(color.value ? { color: color.value } : {})
|
||||
})
|
||||
if (text.value) ops.push({ op: 'text', value: text.value })
|
||||
if (feedLines.value != null && feedLines.value !== 0) {
|
||||
ops.push({ op: 'feedLine', line: Number(feedLines.value) })
|
||||
}
|
||||
if (cut.value) ops.push({ op: 'cut', type: cut.value })
|
||||
|
||||
queue.addOperations(ops)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UCard>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-lg font-semibold text-gray-900 dark:text-white">
|
||||
Constructor de Comandos
|
||||
</h2>
|
||||
<UButton
|
||||
icon="i-heroicons-arrow-path"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
@click="resetForm"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<!-- Textarea principal -->
|
||||
<UFormField label="Texto a imprimir" class="mb-4">
|
||||
<UTextarea
|
||||
v-model="text"
|
||||
:rows="4"
|
||||
autoresize
|
||||
placeholder="Escribe el texto a imprimir..."
|
||||
/>
|
||||
</UFormField>
|
||||
|
||||
<!-- Controles de formato con Accordion -->
|
||||
<UAccordion :items="formatSections" type="multiple">
|
||||
<template #alignment>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-3 gap-3 p-3">
|
||||
<UFormField label="Alineación">
|
||||
<USelect v-model="align" :items="alignOptions" placeholder="Seleccionar" />
|
||||
</UFormField>
|
||||
<UFormField label="Fuente">
|
||||
<USelect v-model="font" :items="fontOptions" placeholder="Seleccionar" />
|
||||
</UFormField>
|
||||
<UFormField label="Color">
|
||||
<USelect v-model="color" :items="colorOptions" placeholder="Seleccionar" />
|
||||
</UFormField>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #size>
|
||||
<div class="grid grid-cols-2 gap-3 p-3">
|
||||
<UFormField label="Ancho (1-8)">
|
||||
<UInput v-model.number="width" type="number" :min="1" :max="8" placeholder="1" />
|
||||
</UFormField>
|
||||
<UFormField label="Alto (1-8)">
|
||||
<UInput v-model.number="height" type="number" :min="1" :max="8" placeholder="1" />
|
||||
</UFormField>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #style>
|
||||
<div class="flex flex-wrap gap-4 p-3">
|
||||
<UCheckbox v-model="bold" label="Negrita" />
|
||||
<UCheckbox v-model="underline" label="Subrayado" />
|
||||
<UCheckbox v-model="reverse" label="Invertido" />
|
||||
<UCheckbox v-model="smooth" label="Suavizado" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #actions>
|
||||
<div class="grid grid-cols-2 gap-3 p-3">
|
||||
<UFormField label="Líneas de feed">
|
||||
<UInput v-model.number="feedLines" type="number" :min="0" :max="255" placeholder="0" />
|
||||
</UFormField>
|
||||
<UFormField label="Corte de papel">
|
||||
<USelect v-model="cut" :items="cutOptions" placeholder="Seleccionar" />
|
||||
</UFormField>
|
||||
</div>
|
||||
</template>
|
||||
</UAccordion>
|
||||
|
||||
<template #footer>
|
||||
<div class="flex gap-2">
|
||||
<UButton color="primary" @click="queueText">
|
||||
Agregar a cola
|
||||
</UButton>
|
||||
<UButton variant="ghost" @click="resetForm">
|
||||
Limpiar formulario
|
||||
</UButton>
|
||||
</div>
|
||||
</template>
|
||||
</UCard>
|
||||
</template>
|
||||
Reference in New Issue
Block a user