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.
9.8 KiB
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
- Toggle visual: Botón flotante con iconos 🖥️ / 📽️
- Persistencia: Guarda la preferencia en localStorage
- Feedback visual: Cambia de color según el modo activo
- No invasivo: Se oculta automáticamente en modo presentador y al imprimir
- CSS Variables: Usa variables CSS para cambios instantáneos
📝 Uso
Agrégalo a tu primera slide o a todas las slides principales:
<ProjectionToggle />
O en 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
- Click en el botón
- Agrega/quita la clase
projection-modeal<html> - Las CSS variables cambian automáticamente:
:root { --bg-primary: #1c1c1c; /* Monitor */ } .projection-mode { --bg-primary: #2d3748; /* Projection */ } - 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:
- Agrega
<ProjectionToggle />a la primera slide - Durante el soundcheck con el proyector, prueba ambos modos
- 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
- Animación de contador: Los números pasan de 1 hasta 40 (en 2025)
- Efecto de hoja: Animación de scale que simula una página de calendario volteándose
- Badge animado: Fondo con gradiente verde y efecto de brillo pulsante
- SVG puro: Más ligero y eficiente que componentes complejos
- Totalmente personalizable: Props para ajustar año inicial y velocidad
📝 Uso
En cualquier slide de Slidev:
<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)
<YearsCounter :startYear="1985" :speed="50" />
Más Lento (150ms por año)
<YearsCounter :startYear="1985" :speed="150" />
Desde otro año (ej: experiencia con Rust)
<YearsCounter :startYear="2019" :speed="100" />
Con delay personalizado (iniciar 5 segundos después)
<YearsCounter :startYear="1985" :speed="80" :delay="5000" />
Sin delay (iniciar inmediatamente cuando sea visible)
<YearsCounter :startYear="1985" :speed="80" :delay="0" />
🎨 Personalización del Estilo
El componente usa estas características visuales:
-
Badge Verde:
- Gradiente:
rgba(72,187,120,0.2)→rgba(72,187,120,0.4) - Borde:
#48bb78(verde Rust accent) - Bordes redondeados:
15px
- Gradiente:
-
Número:
- Color:
#4ade80(verde brillante) - Tamaño:
48px - Fondo oscuro con opacidad
- Color:
-
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 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)
- IntersectionObserver: Monitorea cuando la slide es visible (30% threshold)
- Activación única: Solo se inicia la primera vez que aparece
- Delay configurable: Espera 3 segundos (por defecto) antes de iniciar
- Compatible: Funciona tanto en Slidev como en navegación normal
Secuencia de la Animación
- Slide visible: IntersectionObserver detecta que el componente es visible
- Delay: Espera el tiempo configurado (por defecto 3000ms)
- Inicio: Comienza el contador desde 1
- Incremento: Cada
speedmilisegundos, incrementa el contador - Efecto flip: Cada cambio de número aplica una animación de scale en el eje Y
- 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
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:
- Espera 3 segundos (delay configurable)
- Inicia en 1
- Va incrementando cada 80ms
- Animación de flip en cada cambio
- 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:
---
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:
<!-- 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:
<!-- 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:
<!-- 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
startYearsea correcto - El cálculo es:
new Date().getFullYear() - startYear