- Tiempo de aparición ahora es aleatorio entre 45s y 3 minutos
- Cada aparición genera nuevo umbral para la siguiente
- Mantiene el efecto sorpresa
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Título: x+28 para dejar espacio al semáforo (antes x+10)
- Semáforo: "Viendo ■" alineado a la derecha (antes ■ izquierda, texto derecha)
- Botones: visual_adjust +2px para compensar baseline TTF
- contrastTextColor como fallback para títulos sin base_color
Layout final: "[N] Título Estado ■"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix legibilidad títulos:
- title_color: 85% soft_white + 15% tinte del base_color
- Antes: base.lightenHsl(90) → azul claro sobre azul oscuro (ilegible)
- Ahora: blanco con tinte sutil → máximo contraste + identidad visual
Fix centrado vertical botones:
- Añadido char_height al Context (default 14px para TTF)
- button.zig: usa char_height en vez de char_width
- Offset visual -1px para compensar efecto 3D del bisel
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add bevel: bool option to TabsConfig (default false)
- Active tabs: raised effect (light top/left, dark bottom/right)
- Inactive tabs: subtle inset for depth contrast
- Respects tab_bg color for bevel calculations
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Z-Design V2: Allow panels to specify custom focus ring color.
- TextInputConfig.focus_border_color: overrides theme.primary
- SelectConfig.focus_border_color: same pattern
- Uses Command.focusRingColor() instead of focusRing()
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- button.zig: Usar ctx.measureText() y ctx.char_width para centrado
- label.zig: Mismo fix para centrado de labels
- animation.zig: Actualizar test ColorTransition para duration 500ms
Z-Design V2: El centrado ahora funciona correctamente con TTF fonts.
Antes usaba 8px hardcodeado, ahora usa métricas dinámicas del contexto.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Z-Design V2: Chips de filtro con corner_radius: 4 (igual que botones)
en lugar de 11 (pill-like).
Esto hace que chips y botones tengan el mismo lenguaje visual.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Z-Design V2: Scrollbars más anchos para mejor usabilidad.
- list.zig: 8→14px
- grid.zig: 8→14px
- advanced_table/drawing.zig: 12→14px
- virtual_advanced_table/drawing.zig: 12→14px
- virtual_scroll.zig: 12→14px (default config)
- table/render.zig: 12→14px
El bisel interno Laravel ya estaba implementado en drawBeveledRect.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Añade rectángulo de fondo con row_normal color ANTES de dibujar
las filas. Esto asegura que:
- Tablas vacías muestren color de fondo correcto (no negro)
- Áreas debajo de las últimas filas no queden sin pintar
VirtualAdvancedTable ya tenía este comportamiento.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Acabado Espectacular mejora #5:
- Bisel invertido cuando pressed (oscuro arriba = "hundido")
- Texto desplazado +1px abajo/derecha cuando pressed
- Aplicado a buttonRect y buttonStatefulRect
- Botones se sienten "físicos" al pulsarlos
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Añadir config.minimal: bool para activar estilo sin fondos
- Añadir config.indicator_height para altura personalizable del underline
- En modo minimal: no dibujar fondos de tabs
- Texto inactivo usa text_secondary, activo usa primary
- Hover en minimal ilumina el texto
- Mantener retrocompatibilidad (minimal=false por defecto)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Añadir línea highlight (lighten 15) en borde superior interno
- Añadir línea shadow (darken 15) en borde inferior interno
- Aplicar a buttonRect y buttonStatefulRect
- Deshabilitar bisel en botones disabled
- Solo aplicar si botón tiene al menos 4px de alto/ancho
- Actualizar test para reflejar 2 comandos extra
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Añadidos campos opcionales a TextInputConfig:
- bg_color: color de fondo (override del theme)
- placeholder_color: color del placeholder
Los paneles ahora pueden pasar sus colores derivados Z-Design
a los widgets hijos para coherencia visual.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Cambio de Style.Theme.dark (hardcoded) a Style.currentTheme().*
en 5 archivos / 7 ocurrencias:
- text_input.zig (línea 282)
- button.zig (líneas 75, 163)
- list.zig (líneas 124, 131)
- checkbox.zig (línea 61)
- select.zig (línea 102)
Ahora todos los widgets usan el ThemeManager global, permitiendo
cambio de tema en runtime.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Propuesta Gemini: Unificación funcional entre tablas.
1. Modo inserción centralizado en NavigationState (table_core)
- is_insertion_mode, last_inserted_id
- enterInsertionMode(), exitInsertionMode(), isInInsertionMode()
2. Auto-edit en Ctrl+N (AdvancedTable)
- Tras insertar fila, inicia edición inmediatamente en col 0
3. Auto-insert en Tab (Modo Pro)
- En modo inserción, Tab al final de fila inserta nueva fila
- Permite meter 50+ líneas sin soltar teclado
4. Fix ghost row clonada
- Comparar row_id AND row_index en rendering
- Evita que fila insertada y ghost row compartan buffer
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Bug 1: text_input bytes corruptos al editar celda con texto pre-seleccionado
- Causa: slice getTextInput() se corrompía tras deleteSelection
- Fix: Copiar a buffer local antes de modificar edit_buffer
Bug 2: Editor permanecía visible al hacer clic en otra fila
- Causa: Falta commit implícito al abandonar fila
- Fix: handleMouseClick detecta clic en fila diferente → commitEdit()
Diagnóstico: Gemini | Implementación: Claude
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Extraer AdvancedTableResult a result.zig (73 LOC)
- Extraer funciones de map shifting a state_helpers.zig (141 LOC con tests)
- Reducir state.zig de 1235 LOC a 1123 LOC
- Añadir swapMapEntries para operaciones de move row
- Mantener re-exports para compatibilidad
- Remove injected_row_idx, injected_committed from VirtualAdvancedTableState
- Remove is_injected, injection_index from RowEditBuffer and RowCommitInfo
- Remove startInjectedEdit() method
- Simplify PagedDataSource (no injection offset)
- Simplify drawRowsWithDataSource (no injection handling)
- Add is_insertion_mode, insertion_session_active to State
- Add enterInsertionMode(), exitInsertionMode(), isInInsertionMode() methods
- Ctrl+N now emits insert_row_requested for Panel to handle
Part of Modo Inserción Cronológico implementation.
- PagedDataSource ahora se crea en ctx.frameAllocator()
- Memoria estable durante todo el frame de rendering
- Eliminado cached_paged_datasource del state (punteros auto-ref peligrosos)
- Fix secundario para estabilidad (no era causa del crash Ctrl+N)
Bug: Tab within injected row was triggering immediate row commit.
This happened because RowIdGetter.getRowId() returned the REAL row ID
for the injected row index, instead of NEW_ROW_ID.
Fix:
- RowIdGetter now takes injected_idx parameter
- Returns NEW_ROW_ID for injected row
- Adjusts indices for rows after injection (row-1)
- num_rows calculation now accounts for injection (+1)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When an injected row has been committed (injected_committed=true)
and scrolling moves it out of the visible area:
- Sets needs_reload=true in result
- Clears injection state
This triggers the panel to refetch data from DB, where the
new row will appear in its proper sorted position.
RowCommitInfo now includes:
- is_injected: bool (was this an injected row)
- injection_index: ?usize (where it was injected)
buildCommitInfo() copies these from RowEditBuffer.
VirtualAdvancedTable sets result.injection_committed and
result.injection_row_idx when committing an injected row,
for both Tab navigation and selection change commits.
This allows the panel to know when to INSERT vs UPDATE and
handle the special case of locally injected rows.
- Ctrl+N creates injected row below current selection
- Uses startInjection() to initialize injection state
- Automatically starts editing first column
- Updates selection to show injected row as selected
- Adjusts visible row count when injection is active
No longer emits insert_row_requested - injection is handled
internally by the widget.
When an injected row exists (Ctrl+N between lines):
- getRowCount(): adds 1 to total count
- getCellValueInto(): returns edit buffer values for injected row,
shifts indices for rows after injection
- getRowId(): returns injected_row_id for injected row,
shifts indices for rows after injection
This enables transparent rendering of injected rows without
modifying the drawing code.
State fields:
- injected_row_idx: visual index of injected row
- injected_row_id: ID after commit (NEW_ROW_ID until saved)
- injected_committed: true when saved to DB
Result fields:
- injection_committed: panel should INSERT
- injection_row_idx: where it was injected
- needs_reload: table should refetch from DB
Helper methods:
- hasInjection(), startInjection(), clearInjection()
- markInjectionCommitted(), isInjectionVisible()
- Insert at selected_row + 1 instead of at selected_row
- Use startInjectedEdit() for proper injection tracking
- Row appears below cursor, more intuitive UX
- Add is_injected: bool to distinguish injected rows
- Add injection_index: ?usize for insertion position
- Add startInjectedEdit() method for Ctrl+N between lines
- Update startEdit/clear to reset new fields
- Add row_edit_buffer to AdvancedTableState
- Connect edit_buffer to rendering via drawRowsWithDataSource
- Use DRY planTabNavigation for Tab navigation + auto-commit
- Add Excel-style result fields: row_committed, row_changes, etc.
- Both widgets now share identical commit-on-row-change behavior
- Add planTabNavigation() in table_core.zig: central function for Tab navigation with auto-commit
- Uses row_id comparison (not indices) to detect row changes - robust for virtual tables
- Returns TabAction enum: move, move_with_commit, exit, exit_with_commit
- Integrates in virtual_advanced_table.zig with RowIdGetter wrapper
- Removes obsolete tab_out commit logic
- Fix: Tab at end of ghost row now commits before wrap
🤖 Generated with Claude Code
- Añade table_tips[] con 8 tips de atajos
- Añade tip_index a VirtualAdvancedTableState
- Rota tip cada 600 frames (~10s @ 60fps)
- result.current_tip contiene tip a mostrar
- Solo muestra tips con focus y sin edición activa
- Añade selection_start/selection_end a CellEditState
- F2/Space selecciona todo el texto al entrar en edición
- Typing con selección reemplaza texto seleccionado
- Backspace/Delete borra selección si existe
- Flechas/Home/End limpian selección
- Dibuja highlight azul en ambas tablas (Advanced + Virtual)
- Añadido deleted_row_id: i64 a VirtualAdvancedTableResult
- handleKeyboard setea el ID de la fila seleccionada
- El panel puede usar esto para eliminar de BD