Jesús Pérez d59644b96f
feat: unified auth model, project onboarding, install pipeline, config management
The full scope across this batch: POST /sessions key→token exchange, SessionStore dual-index with revoke_by_id, CLI Bearer injection (ONTOREF_TOKEN), ontoref setup
  --gen-keys, install scripts, daemon config form roundtrip, ADR-004/005, on+re self-description update (fully-self-described), and landing page refresh.
2026-03-13 20:56:31 +00:00

383 lines
9.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Componentes Personalizados para Slidev
## ProjectionToggle - Toggle para Modo Proyector
### 📍 Ubicación
`slides/components/ProjectionToggle.vue`
### 🎯 Descripción
Botón flotante para cambiar entre modo Monitor (oscuro) y modo Proyector (más claro) durante la presentación.
### ✨ Características
1. **Toggle visual**: Botón flotante con iconos 🖥️ / 📽️
2. **Persistencia**: Guarda la preferencia en localStorage
3. **Feedback visual**: Cambia de color según el modo activo
4. **No invasivo**: Se oculta automáticamente en modo presentador y al imprimir
5. **CSS Variables**: Usa variables CSS para cambios instantáneos
### 📝 Uso
Agrégalo a tu primera slide o a todas las slides principales:
```vue
<ProjectionToggle />
```
O en markdown:
```markdown
---
# Primera Slide
---
<ProjectionToggle />
# Tu contenido aquí...
```
### 🎨 Estados Visuales
**Monitor Mode** (por defecto)
- Icono: 🖥️ Monitor
- Color: Naranja (gradiente Rust)
- Fondo: #1c1c1c (muy oscuro)
**Projection Mode**
- Icono: 📽️ Projection
- Color: Verde (#48bb78)
- Fondo: #2d3748 (dark pero más visible)
### 💡 ¿Por qué dos modos?
Los proyectores tienen menor contraste que los monitores. El modo Projection:
- Fondo más claro (#2d3748 vs #1c1c1c)
- Mayor contraste de texto
- Bordes más gruesos en componentes
- Mejor visibilidad en salas con luz ambiente
### 🔧 Cómo Funciona
1. Click en el botón
2. Agrega/quita la clase `projection-mode` al `<html>`
3. Las CSS variables cambian automáticamente:
```css
:root {
--bg-primary: #1c1c1c; /* Monitor */
}
.projection-mode {
--bg-primary: #2d3748; /* Projection */
}
```
4. Guarda la preferencia en `localStorage`
### 📖 Documentación Completa
Ver: `slides/PROJECTION_MODE.md` para guía detallada sobre:
- Todos los métodos de activación
- Comparación visual
- Personalización de colores
- Troubleshooting
### 🎯 Recomendación de Uso
Antes de tu presentación:
1. Agrega `<ProjectionToggle />` a la primera slide
2. Durante el soundcheck con el proyector, prueba ambos modos
3. El modo elegido se guardará automáticamente
---
## YearsCounter - Contador Animado de Años
### 📍 Ubicación
`slides/components/YearsCounter.vue`
### 🎯 Descripción
Componente SVG animado que muestra un contador de años pasando como hojas de calendario, desde 1 hasta el año actual.
### ✨ Características
1. **Animación de contador**: Los números pasan de 1 hasta 40 (en 2025)
2. **Efecto de hoja**: Animación de scale que simula una página de calendario volteándose
3. **Badge animado**: Fondo con gradiente verde y efecto de brillo pulsante
4. **SVG puro**: Más ligero y eficiente que componentes complejos
5. **Totalmente personalizable**: Props para ajustar año inicial y velocidad
### 📝 Uso
En cualquier slide de Slidev:
```vue
<YearsCounter :startYear="1985" :speed="80" />
```
### 🎛️ Props
| Prop | Tipo | Default | Descripción |
|------|------|---------|-------------|
| `startYear` | Number | 1985 | Año desde el que se cuenta |
| `speed` | Number | 80 | Velocidad en milisegundos por año (menor = más rápido) |
| `delay` | Number | 3000 | Delay en ms antes de iniciar la animación (después de que la slide sea visible) |
### 🔧 Ejemplos de Configuración
#### Más Rápido (50ms por año)
```vue
<YearsCounter :startYear="1985" :speed="50" />
```
#### Más Lento (150ms por año)
```vue
<YearsCounter :startYear="1985" :speed="150" />
```
#### Desde otro año (ej: experiencia con Rust)
```vue
<YearsCounter :startYear="2019" :speed="100" />
```
#### Con delay personalizado (iniciar 5 segundos después)
```vue
<YearsCounter :startYear="1985" :speed="80" :delay="5000" />
```
#### Sin delay (iniciar inmediatamente cuando sea visible)
```vue
<YearsCounter :startYear="1985" :speed="80" :delay="0" />
```
### 🎨 Personalización del Estilo
El componente usa estas características visuales:
1. **Badge Verde**:
- Gradiente: `rgba(72,187,120,0.2)` → `rgba(72,187,120,0.4)`
- Borde: `#48bb78` (verde Rust accent)
- Bordes redondeados: `15px`
2. **Número**:
- Color: `#4ade80` (verde brillante)
- Tamaño: `48px`
- Fondo oscuro con opacidad
3. **Animaciones**:
- **Pulso del badge**: 3 segundos, brillo entre 0.3 y 0.6 opacidad
- **Flip del número**: 0.3 segundos, scale de `1,1` → `1,0.3` → `1,1`
### 🖼️ Estructura del SVG
```svg
<svg width="300" height="120">
<!-- Badge con gradiente y animación -->
<rect with gradient + glow filter + pulse animation />
<!-- Emoji -->
<text>💻</text>
<!-- Contenedor del número -->
<g>
<rect (fondo oscuro) />
<text (número con animación de flip) />
</g>
<!-- Texto descriptivo -->
<text>años como desarrollador</text>
</svg>
```
### 🔄 Cómo Funciona la Animación
#### Detección de Visibilidad (Nuevo)
1. **IntersectionObserver**: Monitorea cuando la slide es visible (30% threshold)
2. **Activación única**: Solo se inicia la primera vez que aparece
3. **Delay configurable**: Espera 3 segundos (por defecto) antes de iniciar
4. **Compatible**: Funciona tanto en Slidev como en navegación normal
#### Secuencia de la Animación
1. **Slide visible**: IntersectionObserver detecta que el componente es visible
2. **Delay**: Espera el tiempo configurado (por defecto 3000ms)
3. **Inicio**: Comienza el contador desde 1
4. **Incremento**: Cada `speed` milisegundos, incrementa el contador
5. **Efecto flip**: Cada cambio de número aplica una animación de scale en el eje Y
6. **Fin**: Cuando alcanza el año objetivo (2025-1985=40), detiene el intervalo
**Ejemplo de timing completo**:
- Llegas a la slide 2 → espera 3 segundos → cuenta de 1 a 40 en 3.2 segundos = **6.2 segundos total**
### 💻 Código JavaScript
```javascript
const counterElement = ref(null) // Referencia al elemento DOM
const displayYear = ref(1)
const hasStarted = ref(false) // Prevenir múltiples inicios
const targetYear = new Date().getFullYear() - props.startYear // 2025 - 1985 = 40
const startAnimation = () => {
if (hasStarted.value) return // Solo iniciar una vez
hasStarted.value = true
// Esperar el delay configurado antes de iniciar
setTimeout(() => {
let year = 1
const interval = setInterval(() => {
if (year <= targetYear) {
displayYear.value = year
year++
} else {
clearInterval(interval)
}
}, props.speed)
}, props.delay)
}
onMounted(async () => {
await nextTick()
// Observar cuando el componente es visible
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && !hasStarted.value) {
startAnimation()
observer.disconnect() // Dejar de observar después de iniciar
}
})
},
{ threshold: 0.3 } // 30% visible
)
observer.observe(counterElement.value)
})
```
### 🎬 Resultado
Cuando navegas a la slide:
1. **Espera 3 segundos** (delay configurable)
2. **Inicia en 1**
3. **Va incrementando** cada 80ms
4. **Animación de flip** en cada cambio
5. **Termina en 40** (años desde 1985 hasta 2025)
**Duración total**:
- Delay: 3 segundos
- Animación: 40 años × 80ms = 3.2 segundos
- **Total: 6.2 segundos**
### ✨ Comportamiento Inteligente
- ✅ **Solo se inicia cuando la slide es visible** (no al cargar la presentación)
- ✅ **Delay de 3 segundos** para dar tiempo al usuario a leer el título
- ✅ **Se inicia solo una vez** (aunque vuelvas a la slide, no se reinicia)
- ✅ **Compatible con navegación** hacia adelante y atrás en Slidev
### 📱 Responsive
El SVG se adapta automáticamente al contenedor y mantiene su aspecto.
### 🔄 Actualización Automática
El cálculo `new Date().getFullYear() - props.startYear` se hace al montar el componente, por lo que:
- En **2025**: muestra de 1 a 40
- En **2026**: mostrará de 1 a 41
- Y así sucesivamente
### 🎯 Implementación en el Slide
**Slide 2** - Introducción Personal:
```markdown
---
layout: intro
---
# Jesús Pérez Lorenzo
<div class="flex items-center gap-11 mt-8">
<div class="leading-8 opacity-80">
<YearsCounter :startYear="1985" :speed="80" />
<span class="orange">Rust</span> Developer & Cloud Architect<br>
...
</div>
</div>
```
### 🛠️ Modificar la Animación
Para cambiar el tipo de animación, edita la sección `<animateTransform>` en el componente:
```xml
<!-- Flip horizontal en lugar de vertical -->
<animateTransform
attributeName="transform"
type="scale"
values="1,1; 0.3,1; 1,1"
dur="0.3s"/>
<!-- Rotación -->
<animateTransform
attributeName="transform"
type="rotate"
values="0 120 75; 360 120 75"
dur="0.5s"/>
```
### 🎨 Cambiar Colores
Para cambiar el esquema de colores, modifica:
```xml
<!-- Verde → Naranja Rust -->
<stop offset="0%" style="stop-color:rgba(247,76,0,0.2)" />
<stop offset="100%" style="stop-color:rgba(247,76,0,0.4)" />
<!-- Color del número -->
<text fill="#ff6b4a">
<!-- Color del borde -->
<rect stroke="#f74c00" />
```
## 🚀 Crear Otros Contadores
Puedes reutilizar el componente para otras métricas:
```vue
<!-- Años con Rust -->
<YearsCounter :startYear="2019" :speed="100" />
<!-- Años en Cloud -->
<YearsCounter :startYear="2013" :speed="100" />
```
## 📦 Archivos del Componente
```
slides/
├── components/
│ ├── YearsCounter.vue ← El componente
│ └── README.md ← Esta documentación
└── slides.md ← Uso del componente
```
## 🔍 Troubleshooting
### El componente no se muestra
- Asegúrate de que el archivo esté en `slides/components/`
- Slidev detecta automáticamente componentes en esta carpeta
### La animación es muy rápida/lenta
- Ajusta el prop `:speed` (en milisegundos)
- Valores recomendados: 50-150ms
### El número no llega al año correcto
- Verifica que `startYear` sea correcto
- El cálculo es: `new Date().getFullYear() - startYear`