491 lines
18 KiB
Vue
491 lines
18 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref } from "vue";
|
|
import {
|
|
DsAlert,
|
|
DsAppShell,
|
|
DsButton,
|
|
DsButtonGroup,
|
|
DsCheckbox,
|
|
DsConfirmDialog,
|
|
DsDivider,
|
|
DsEmptyState,
|
|
DsErrorState,
|
|
DsFormActions,
|
|
DsIconButton,
|
|
DsInline,
|
|
DsInlineMessage,
|
|
DsLoadingState,
|
|
DsPageHeader,
|
|
DsPanel,
|
|
DsPasswordInput,
|
|
DsProgressBar,
|
|
DsRadioGroup,
|
|
DsSearchInput,
|
|
DsSectionHeader,
|
|
DsSelect,
|
|
DsSettingsSection,
|
|
DsSkeleton,
|
|
DsSpinner,
|
|
DsStack,
|
|
DsSwitch,
|
|
DsTabs,
|
|
DsTextarea,
|
|
DsTextInput,
|
|
type DsTabItem,
|
|
} from "@omaresquivel/design-system";
|
|
|
|
const sections: DsTabItem[] = [
|
|
{ id: "catalog", label: "Catálogo" },
|
|
{ id: "profile", label: "Perfil" },
|
|
{ id: "settings", label: "Configuración" },
|
|
{ id: "form", label: "Formulario largo" },
|
|
{ id: "states", label: "Estados de panel" },
|
|
];
|
|
const currentSection = ref("catalog");
|
|
const name = ref("Omar Esquivel");
|
|
const email = ref("omar@example.com");
|
|
const password = ref("correct horse battery staple");
|
|
const search = ref("");
|
|
const bio = ref("Diseño y desarrollo productos web mantenibles.");
|
|
const role = ref("designer");
|
|
const plan = ref("pro");
|
|
const notifications = ref(true);
|
|
const analytics = ref(false);
|
|
const terms = ref(false);
|
|
const dialogOpen = ref(false);
|
|
const confirmOpen = ref(false);
|
|
const panelState = ref<"loading" | "error" | "empty" | "success">("success");
|
|
const nameError = computed(() =>
|
|
name.value.length > 0 && name.value.length < 3
|
|
? "Escribe al menos tres caracteres."
|
|
: undefined,
|
|
);
|
|
|
|
const roleOptions = [
|
|
{ label: "Diseño", value: "designer" },
|
|
{ label: "Desarrollo", value: "developer" },
|
|
{ label: "Producto", value: "product" },
|
|
];
|
|
const planOptions = [
|
|
{
|
|
label: "Inicial",
|
|
value: "starter",
|
|
description: "Para proyectos personales.",
|
|
},
|
|
{ label: "Profesional", value: "pro", description: "Para equipos pequeños." },
|
|
{
|
|
label: "Empresa",
|
|
value: "enterprise",
|
|
description: "Controles y soporte avanzados.",
|
|
},
|
|
];
|
|
</script>
|
|
|
|
<template>
|
|
<DsAppShell>
|
|
<main class="playground-frame">
|
|
<DsPageHeader
|
|
eyebrow="Sistema de diseño"
|
|
title="Fundamentos y componentes"
|
|
description="Una fuente única de estilos sobrios, accesibles y reutilizables para productos Vue."
|
|
>
|
|
<template #actions>
|
|
<DsButton variant="secondary" @click="dialogOpen = true"
|
|
>Ver instalación</DsButton
|
|
>
|
|
</template>
|
|
</DsPageHeader>
|
|
|
|
<div class="playground-body">
|
|
<DsTabs
|
|
v-model="currentSection"
|
|
class="playground-nav"
|
|
:items="sections"
|
|
label="Secciones del catálogo"
|
|
>
|
|
<template #catalog>
|
|
<DsStack :gap="8">
|
|
<DsSectionHeader
|
|
title="Catálogo base"
|
|
description="Variantes, estados y controles que comparten el mismo lenguaje visual."
|
|
/>
|
|
|
|
<section class="playground-grid playground-grid--2">
|
|
<DsPanel>
|
|
<DsStack :gap="4">
|
|
<DsSectionHeader
|
|
title="Acciones"
|
|
description="Jerarquía explícita para cada intención."
|
|
/>
|
|
<DsButtonGroup label="Variantes de botones">
|
|
<DsButton>Guardar cambios</DsButton>
|
|
<DsButton variant="secondary">Cancelar</DsButton>
|
|
<DsButton variant="ghost">Más opciones</DsButton>
|
|
<DsButton variant="danger">Eliminar</DsButton>
|
|
</DsButtonGroup>
|
|
<DsButtonGroup label="Estados de botones">
|
|
<DsButton size="sm">Pequeño</DsButton>
|
|
<DsButton loading>Guardando</DsButton>
|
|
<DsButton disabled>Deshabilitado</DsButton>
|
|
<DsIconButton label="Añadir elemento" variant="secondary"
|
|
>+</DsIconButton
|
|
>
|
|
</DsButtonGroup>
|
|
</DsStack>
|
|
</DsPanel>
|
|
|
|
<DsPanel>
|
|
<DsStack :gap="4">
|
|
<DsSectionHeader
|
|
title="Tokens de color"
|
|
description="Valores semánticos sobrescribibles con CSS."
|
|
/>
|
|
<div class="playground-grid playground-grid--2">
|
|
<div class="playground-swatch playground-swatch--primary">
|
|
Primary
|
|
</div>
|
|
<div class="playground-swatch playground-swatch--inverse">
|
|
Surface inverse
|
|
</div>
|
|
<div class="playground-swatch playground-swatch--muted">
|
|
Surface muted
|
|
</div>
|
|
<div class="playground-swatch">Surface</div>
|
|
</div>
|
|
</DsStack>
|
|
</DsPanel>
|
|
</section>
|
|
|
|
<DsDivider />
|
|
|
|
<section class="playground-grid playground-grid--2">
|
|
<DsPanel>
|
|
<DsStack :gap="4">
|
|
<DsSectionHeader
|
|
title="Campos"
|
|
description="Label, ayuda y error comparten un contrato consistente."
|
|
/>
|
|
<DsTextInput
|
|
v-model="name"
|
|
label="Nombre completo"
|
|
required
|
|
:error="nameError"
|
|
autocomplete="name"
|
|
/>
|
|
<DsSearchInput
|
|
v-model="search"
|
|
label="Buscar proyecto"
|
|
description="Busca por nombre o identificador."
|
|
/>
|
|
<DsPasswordInput
|
|
v-model="password"
|
|
label="Contraseña"
|
|
required
|
|
autocomplete="current-password"
|
|
/>
|
|
<DsSelect
|
|
v-model="role"
|
|
label="Área principal"
|
|
:options="roleOptions"
|
|
required
|
|
/>
|
|
<DsTextarea
|
|
v-model="bio"
|
|
label="Biografía"
|
|
description="Máximo 280 caracteres."
|
|
:maxlength="280"
|
|
/>
|
|
</DsStack>
|
|
</DsPanel>
|
|
|
|
<DsPanel>
|
|
<DsStack :gap="4">
|
|
<DsSectionHeader
|
|
title="Selección"
|
|
description="Controles nativos y comportamiento predecible."
|
|
/>
|
|
<DsCheckbox
|
|
v-model="terms"
|
|
label="Acepto los términos"
|
|
description="Puedes consultar la política antes de continuar."
|
|
required
|
|
/>
|
|
<DsRadioGroup
|
|
v-model="plan"
|
|
legend="Plan"
|
|
name="catalog-plan"
|
|
:options="planOptions"
|
|
/>
|
|
<DsSwitch
|
|
v-model="notifications"
|
|
label="Notificaciones"
|
|
description="Recibe novedades importantes por correo."
|
|
/>
|
|
<DsSwitch
|
|
v-model="analytics"
|
|
label="Analítica de uso"
|
|
description="Ayúdanos a mejorar el producto."
|
|
/>
|
|
</DsStack>
|
|
</DsPanel>
|
|
</section>
|
|
|
|
<DsPanel>
|
|
<DsStack :gap="4">
|
|
<DsSectionHeader
|
|
title="Retroalimentación"
|
|
description="Mensajes visibles y anunciables solo cuando son dinámicos."
|
|
/>
|
|
<DsAlert variant="info" title="Información"
|
|
>El nuevo tema se aplicará a todos tus proyectos.</DsAlert
|
|
>
|
|
<DsAlert variant="success" title="Cambios guardados"
|
|
>Tu configuración ya está actualizada.</DsAlert
|
|
>
|
|
<DsAlert variant="warning" title="Revisa la información"
|
|
>Algunos campos todavía usan valores
|
|
predeterminados.</DsAlert
|
|
>
|
|
<DsAlert variant="error" title="No pudimos guardar"
|
|
>Comprueba tu conexión e intenta nuevamente.</DsAlert
|
|
>
|
|
<DsProgressBar :value="68" label="Configuración completada" />
|
|
<DsInline align="center"
|
|
><DsSpinner size="sm" /><DsInlineMessage
|
|
>Sincronizando preferencias…</DsInlineMessage
|
|
></DsInline
|
|
>
|
|
<DsSkeleton height="2.75rem" />
|
|
</DsStack>
|
|
</DsPanel>
|
|
</DsStack>
|
|
</template>
|
|
|
|
<template #profile>
|
|
<DsStack :gap="6">
|
|
<DsSectionHeader
|
|
title="Perfil de usuario"
|
|
description="Ejemplo completo compuesto únicamente con la API pública."
|
|
/>
|
|
<div class="playground-profile">
|
|
<DsPanel>
|
|
<DsStack align="center" :gap="4">
|
|
<div class="playground-avatar" aria-hidden="true">OE</div>
|
|
<div style="text-align: center">
|
|
<strong>Omar Esquivel</strong>
|
|
<p class="playground-meta">Administrador</p>
|
|
</div>
|
|
<DsButton variant="secondary" size="sm"
|
|
>Cambiar fotografía</DsButton
|
|
>
|
|
</DsStack>
|
|
</DsPanel>
|
|
<form @submit.prevent>
|
|
<DsPanel>
|
|
<DsStack :gap="6">
|
|
<DsSectionHeader
|
|
title="Información personal"
|
|
description="Esta información aparecerá en tu cuenta y actividad."
|
|
/>
|
|
<div class="playground-grid playground-grid--2">
|
|
<DsTextInput
|
|
v-model="name"
|
|
label="Nombre completo"
|
|
required
|
|
autocomplete="name"
|
|
/>
|
|
<DsTextInput
|
|
v-model="email"
|
|
type="email"
|
|
label="Correo electrónico"
|
|
required
|
|
autocomplete="email"
|
|
/>
|
|
</div>
|
|
<DsTextarea v-model="bio" label="Acerca de ti" />
|
|
<DsFormActions
|
|
><DsButton variant="secondary">Cancelar</DsButton
|
|
><DsButton type="submit"
|
|
>Guardar perfil</DsButton
|
|
></DsFormActions
|
|
>
|
|
</DsStack>
|
|
</DsPanel>
|
|
</form>
|
|
</div>
|
|
</DsStack>
|
|
</template>
|
|
|
|
<template #settings>
|
|
<DsStack :gap="6">
|
|
<DsSectionHeader
|
|
title="Configuración"
|
|
description="Secciones independientes que pueden guardarse por separado."
|
|
/>
|
|
<DsSettingsSection
|
|
title="Comunicaciones"
|
|
description="Elige cómo quieres recibir información."
|
|
>
|
|
<DsStack :gap="4">
|
|
<DsSwitch
|
|
v-model="notifications"
|
|
label="Actualizaciones del producto"
|
|
description="Noticias sobre funciones y mantenimiento."
|
|
/>
|
|
<DsSwitch
|
|
v-model="analytics"
|
|
label="Resumen semanal"
|
|
description="Actividad relevante en un solo correo."
|
|
/>
|
|
</DsStack>
|
|
<template #actions
|
|
><DsButton size="sm">Guardar</DsButton></template
|
|
>
|
|
</DsSettingsSection>
|
|
<DsSettingsSection
|
|
title="Zona de riesgo"
|
|
description="Estas acciones pueden afectar el acceso de todo el equipo."
|
|
>
|
|
<DsAlert variant="warning" title="Antes de continuar"
|
|
>Exporta una copia de la información que necesites
|
|
conservar.</DsAlert
|
|
>
|
|
<template #actions
|
|
><DsButton
|
|
size="sm"
|
|
variant="danger"
|
|
@click="confirmOpen = true"
|
|
>Eliminar cuenta</DsButton
|
|
></template
|
|
>
|
|
</DsSettingsSection>
|
|
</DsStack>
|
|
</template>
|
|
|
|
<template #form>
|
|
<form @submit.prevent>
|
|
<DsStack :gap="6">
|
|
<DsSectionHeader
|
|
title="Solicitud de proyecto"
|
|
description="Formulario largo dividido en secciones claras."
|
|
/>
|
|
<DsSettingsSection
|
|
title="1. Contexto"
|
|
description="Cuéntanos qué necesitas resolver."
|
|
>
|
|
<DsTextarea
|
|
label="Objetivo y contexto de negocio"
|
|
required
|
|
placeholder="Agrega la información relevante para esta sección."
|
|
/>
|
|
</DsSettingsSection>
|
|
<DsSettingsSection
|
|
title="2. Responsables"
|
|
description="Personas que participarán en las decisiones."
|
|
>
|
|
<div class="playground-grid playground-grid--2">
|
|
<DsTextInput label="Responsable" required />
|
|
<DsTextInput label="Correo" type="email" required />
|
|
</div>
|
|
</DsSettingsSection>
|
|
<DsSettingsSection
|
|
title="3. Alcance"
|
|
description="Define prioridad y tipo de entrega."
|
|
>
|
|
<DsRadioGroup
|
|
v-model="plan"
|
|
legend="Prioridad"
|
|
name="project-priority"
|
|
:options="planOptions"
|
|
/>
|
|
</DsSettingsSection>
|
|
<DsFormActions
|
|
><DsButton variant="secondary">Guardar borrador</DsButton
|
|
><DsButton type="submit"
|
|
>Enviar solicitud</DsButton
|
|
></DsFormActions
|
|
>
|
|
</DsStack>
|
|
</form>
|
|
</template>
|
|
|
|
<template #states>
|
|
<DsStack :gap="6">
|
|
<DsSectionHeader
|
|
title="Estados de panel"
|
|
description="Prueba loading, error, vacío y contenido correcto."
|
|
>
|
|
<template #actions>
|
|
<DsButtonGroup label="Seleccionar estado">
|
|
<DsButton
|
|
v-for="state in [
|
|
'loading',
|
|
'error',
|
|
'empty',
|
|
'success',
|
|
] as const"
|
|
:key="state"
|
|
size="sm"
|
|
:variant="panelState === state ? 'primary' : 'secondary'"
|
|
@click="panelState = state"
|
|
>{{ state }}</DsButton
|
|
>
|
|
</DsButtonGroup>
|
|
</template>
|
|
</DsSectionHeader>
|
|
<DsPanel>
|
|
<DsLoadingState v-if="panelState === 'loading'" />
|
|
<DsErrorState
|
|
v-else-if="panelState === 'error'"
|
|
title="No pudimos cargar los proyectos"
|
|
description="Comprueba tu conexión e intenta nuevamente."
|
|
><template #actions
|
|
><DsButton>Reintentar</DsButton></template
|
|
></DsErrorState
|
|
>
|
|
<DsEmptyState
|
|
v-else-if="panelState === 'empty'"
|
|
title="Aún no hay proyectos"
|
|
description="Crea el primero para comenzar a organizar tu trabajo."
|
|
><template #actions
|
|
><DsButton>Crear proyecto</DsButton></template
|
|
></DsEmptyState
|
|
>
|
|
<DsStack v-else :gap="4"
|
|
><DsAlert variant="success" title="Todo está al día"
|
|
>Hay 12 proyectos activos y ninguno requiere
|
|
atención.</DsAlert
|
|
><DsProgressBar :value="100" label="Sincronización"
|
|
/></DsStack>
|
|
</DsPanel>
|
|
</DsStack>
|
|
</template>
|
|
</DsTabs>
|
|
</div>
|
|
</main>
|
|
|
|
<DsConfirmDialog
|
|
v-model="confirmOpen"
|
|
title="¿Eliminar la cuenta?"
|
|
description="Esta acción no se puede deshacer."
|
|
confirm-label="Sí, eliminar"
|
|
danger
|
|
@confirm="confirmOpen = false"
|
|
>
|
|
Se eliminarán los proyectos y preferencias vinculados a esta cuenta.
|
|
</DsConfirmDialog>
|
|
|
|
<DsConfirmDialog
|
|
v-model="dialogOpen"
|
|
title="Instalación"
|
|
confirm-label="Entendido"
|
|
@confirm="dialogOpen = false"
|
|
>
|
|
<pre
|
|
class="playground-code"
|
|
><code>import { DsButton } from '@omaresquivel/design-system'
|
|
import '@omaresquivel/design-system/style.css'</code></pre>
|
|
</DsConfirmDialog>
|
|
</DsAppShell>
|
|
</template>
|