9db0591f28d9895677bd0875fb51e570be7d830f
9 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9db0591f28 |
feat(tahuantinsuyu): "Guardar como…" en módulo Retorno planetario (F4)
Cierra la fase B con el botón pedido por el usuario: tener una
carta natal abierta, activar el módulo Retorno planetario con
edad N + cuerpo (ej. Sol, 34 años), y al click guardar la carta
resultante con sufijo automático `rs-34` en el mismo contacto.
Infraestructura nueva (extensible a otros overlays):
- `Control::Action { key, label }` en tahuantinsuyu-modules —
un botón sin estado que el panel pinta como pill clickeable.
- `PanelEvent::Action { module_id, key }` que el panel emite
al click y el shell despacha.
- `render_action` en tahuantinsuyu-panel: pill con bg_button
+ hover + border. Wrap en Div plano para tipo coherente.
Backend (eternal-bridge):
- Nueva función pública `compute_planetary_return_chart(chart,
body, target_age_years, shift_days) -> (StoredBirthData,
instant_label)` en `tahuantinsuyu-engine`. Reusa el cómputo
ya existente del overlay: `next_return` + parser ISO-8601
para extraer year/mm/dd/hh:mm:ss del instant del retorno.
Hereda lat/lon/alt/TZ del natal — convención clásica del
Solar return en la ciudad de nacimiento.
Flujo en el shell:
- Handler `on_panel_action` despacha por `(module_id, key)`. Hoy
solo `planetary_return.save_as_free` está cableado; otros
módulos overlay (progression, solar_arc, primary_directions,
transit) son extensión natural — TODO.
- `save_planetary_return_as_free`:
1) lee config (body, age, shift_days) del module_configs
2) llama `compute_planetary_return_chart`
3) construye un `Chart` clonando el natal con birth_data
nuevo + label `{contacto} rs-34 · 2024-08-12 14:23 UTC`
(sufijo según cuerpo: `rs` para Sol, `lunar` para Luna,
nombre directo para los demás)
4) inserta como FreeChart con id `free-{N}` y la
selecciona para que el usuario la vea
- El usuario después puede usar el menú contextual de la
free chart para "Guardar como…" → modal F3 → persiste
bajo el contacto que elija (típicamente el del natal).
UX completa:
1. Tener natal abierta
2. Panel: módulo "Retorno planetario" → Activar + elegir
cuerpo + slider edad
3. Click "💾 Guardar retorno como carta libre"
4. La nueva carta aparece en "Cartas libres" seleccionada
5. Click derecho → "Guardar como…" → elegir contacto +
confirmar nombre
10 tests verdes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
e09207b152 |
feat(tahuantinsuyu): UX pass — splitter, light wheel, scroll, zoom/pan, dock lateral
Seis fixes derivados de testing real, ordenados por costo:
- Splitter (yahweh-widget-splitter): `flex-basis: 0` por item para que
el ratio flex-grow se respete sin importar el min-content de los
hijos. Sin esto, al cambiar el canvas de Empty→Wheel (WHEEL_SIZE
fijo de 580px) la suma de basis excedía el contenedor y flexbox
abandonaba el ratio 1:4, aplastando el tree a 0px (síntoma
reportado: "el tree desaparece al seleccionar carta"). También se
amplió la hit-zone del divider de 4px a 12px manteniendo una franja
visual de 4px centrada — la zona de pointer-capture y cursor es
ahora mucho más generosa, el visual sigue fino.
- Light mode wheel (tahuantinsuyu-canvas + tahuantinsuyu-theme): el
gradient del fondo del wheel pasa de alphas 0.06/0.03 (invisibles
contra fondo claro) a 0.18/0.10 cuando el theme es light. Cusps y
aspectos secundarios del light palette bajan luminancia y suben
alpha para no lavarse contra blanco.
- Panel scroll (tahuantinsuyu-panel): body del control panel agrega
`flex_grow + min_h(0) + overflow_y_scroll` para que cuando los
controles no caben aparezca scroll vertical en lugar de cortarse.
- Canvas zoom + pan (tahuantinsuyu-canvas): nuevo estado
view_scale / view_pan_x / view_pan_y. Ctrl+wheel zoomea
multiplicativo (clamp 0.5..3.0); wheel solo paneja. MMB drag para
pan libre. Hotkey `0` resetea zoom+pan. Hit-tests del jog-dial y
hover derivan ahora el `r_outer` del width actual del canvas, así
se autoescalan con el zoom.
- Panel dock lateral (shell.rs): nuevo `PanelDock { Bottom, Right,
Left }` configurable desde 3 botones en el header (◧ ▭ ◨). Bottom
mantiene el layout histórico (tree+canvas / panel); las variantes
laterales colapsan los splitters anidados en uno solo horizontal
de 3 columnas. El dock se persiste en `layout.panel_dock` y cada
layout guarda sus flex en una key distinta para no pisarse.
`load_split_flex_n` / `save_split_flex` generalizados a N hijos.
Tests: 6 pasan (incluye nuevo roundtrip de PanelDock y N-flex).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
2192c29d4f |
chore(tahuantinsuyu): fase 28 — limpieza de warnings y dead_code
- Reemplaza `Context<Self>` por `Context<'_, Self>` (y la misma fórmula para `Context<TahuantinsuyuTree>`) en tree/panel/canvas: 60 warnings de "hidden lifetime parameters are deprecated" → 0. - Borra `TREE_WIDTH` y `PANEL_HEIGHT` (constantes muertas) y el campo `main_split` del shell (vive como child de outer_split, no necesita retención aparte). - Quita `yahweh-bus` de tahuantinsuyu — el `bus: Entity<AppBus>` estaba con `#[allow(dead_code)]` sin cablear. Cuando lo necesitemos para coordinación cross-app lo reagregamos. - Suprime imports `Module` (panel), `AppContext` (canvas) y prefija el `cx` no usado en `on_jog_down`. - Marca `BrahmanStatus::Offline.reason` y `Shell.tree` con `#[allow(dead_code)]` documentando por qué se retienen (logs y subscripciones). Workspace ahora compila limpio salvo un warning conocido de `eternal-validation` (variable `sin_i` sin usar — fuera de brahman). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
d3649bfd1a |
feat(tahuantinsuyu): fase 20 — accordion + lunar shift + CompositeModule + 90 ciudades
Cuatro features que cierran el set inicial de funcionalidades de
fase 1:
## D — Acordeón colapsable en el panel
Cuando hay 8 módulos en el panel se llenaba de cards. Ahora cada card
es expandible/colapsable por click en el header. Defaults:
- Natal siempre expanded
- Módulos con toggle "enabled" = true → expanded
- Resto → collapsed
El usuario puede forzar cualquiera vía override (collapse_overrides
HashMap). Chevron ▾/▸ a la izquierda del header. Hover sobre el
header lo resalta para invitar al click.
## B — Lunar return shift (navegación mensual)
PipelineRequest::PlanetaryReturn gana campo `shift_days: i64` (range
±180). El bridge lo suma a after_seconds del search anchor antes de
next_return. Para Solar return típicamente 0 (mantiene comportamiento).
Para Moon return, mover el slider ±28 días salta al retorno lunar
anterior o siguiente, permitiendo navegar mes a mes la lunación que
le toca al sujeto cumplido N años. PlanetaryReturnModule.controls()
agrega un slider "Shift días (lunar nav)". El badge del overlay
muestra "Moon return 38a +14d" cuando shift_days != 0. Helper
`planetary_return_request(body, age)` para callers que no necesitan
shift (zero default).
## C — CompositeModule
Carta compuesta (midpoint Davison) entre la natal del sujeto y otra
carta partner. Cada placement compuesto es el angular midpoint entre
los dos correspondientes. Engine: `PipelineRequest::Composite {
partner_chart: Box<Chart> }` + build_composite_overlay que llama
`eternal_astrology::composite()`. Renderiza placements en
`radii.composite = r * 0.32` (entre solar_arc 0.40 y aspects 0.24,
re-balanced). Módulo `composite::CompositeModule` con toggle +
ChartPicker (mismo patrón que synastry).
Shell: resolve_composite_partner reusa el fallback al primer hermano
del contacto, igual que synastry.
## A — 90 ciudades expandidas + dropdown scrollable
CITY_PRESETS pasa de 25 a 90 ciudades cubriendo:
- Latinoamérica (35): todas las capitales + grandes ciudades de AR/
VE/CO/PE/CL/EC/UY/PY/BO/MX/CU/PR/CR/PA/SV/GT/HN/NI/DO/BR
- España (5) + Europa (20): Madrid/Barcelona/Sevilla/Valencia/Bilbao
+ London/Paris/Berlin/München/Roma/Milano/Amsterdam/Bruxelles/Wien/
Zürich/Lisboa/Dublin/Stockholm/Oslo/København/Helsinki/Warszawa/
Praha/Budapest/Athina/İstanbul/Moskva
- USA + Canadá (12): NY/LA/Chicago/Miami/Houston/SF/Seattle/Boston/
DC + Toronto/Montreal/Vancouver
- Asia (16): Tokyo/Beijing/Shanghai/HK/Singapore/Seoul/Bangkok/
Jakarta/Manila/Mumbai/Delhi/Bangalore/Karachi/Tehran/Dubai/Tel Aviv
- África (6): Cairo/Lagos/Nairobi/Johannesburg/Cape Town/Casablanca
- Oceanía (3): Sydney/Melbourne/Auckland
El popup del dropdown ahora es scrollable (h=360px, overflow_y_scroll)
con id estable para no perder scroll position entre re-renders.
cargo check verde, 8 tests engine + 1 test modules (8 módulos
aplicables a ChartKind::Natal) verdes.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
6d572c81ca |
feat(tahuantinsuyu): fase 14 — Return abstracto + Control::Select interactivo
El módulo SolarReturn se generaliza a PlanetaryReturn parametrizable
por cuerpo (Sun/Moon/Mercury/Venus/Mars/Jupiter/Saturn/Uranus/Neptune/
Pluto). Validado contra `Control::Select`, ahora interactivo como
tercer tipo de control draggable (después de Toggle/Slider/ChartPicker).
Refactor estructural: el dropdown del ChartPicker pasa a ser
infraestructura compartida — chart_picker_value/chart_picker_open
desaparecen, reemplazados por string_state/dropdown_open que sirven
a CUALQUIER control basado en string (picker + select).
render_chart_picker y render_select ahora son thin wrappers sobre
render_dropdown(options, include_auto).
- engine:
- PipelineRequest::SolarReturn → PipelineRequest::PlanetaryReturn
{ body: String, target_age_years }. Body como string agnóstico
(sun/moon/jupiter/...) que el bridge mapea a eternal_sky::Body
vía map_body — el mismo helper que ya usa StoredChartConfig.
- build_solar_return_overlay → build_planetary_return_overlay con
parameter `body: Body`. next_return acepta cualquier body, así que
Moon return (mensual) y Saturn return (29 años) funcionan igual.
Mensajes de error incluyen body.name() para diagnóstico.
- modules:
- SolarReturnModule → PlanetaryReturnModule (mod planetary_return).
id "planetary_return". Controles: toggle "enabled" + Select "body"
con 10 opciones de cuerpo (Sol → Plutón) + Slider edad. label
"Retornos planetarios".
- panel:
- Refactor: chart_picker_value/chart_picker_open → string_state/
dropdown_open (compartido entre ChartPicker y Select).
- set_string(module_id, key, value, cx) — API unificada. set_chart_picker
queda como alias retrocompatible.
- render_dropdown(options, include_auto, …) — helper común. picker
pasa include_auto=true (muestra "(automático)" + separador);
select pasa include_auto=false (las options son la única opción).
- render_select implementado — el botón muestra la option's label
(no value); click abre dropdown; click en opción emite ControlChanged
con Value::String(option.value).
- shell:
- OUTER_RING_MODULES const: "solar_return" → "planetary_return".
- build_requests para planetary_return: lee body string del
module_configs (default "sun"), arma PipelineRequest::PlanetaryReturn.
- apply_selection inicializa target_age + body=sun default para
planetary_return.
- sync_panel_from_configs strings → set_string (era set_chart_picker).
Probarlo: en el panel del módulo "Retornos planetarios", click en el
dropdown "Cuerpo" abre el popup; click en "Saturno" + slider en 29
años + toggle "Activar" = ves la carta del primer retorno de Saturno
(cuando recién terminaba la primera vuelta) en el outer ring con
cross aspects al natal.
NOTE: La persistencia con id "solar_return" de fase 13 queda huérfana
en la DB de los users que ya hayan probado. No es destructivo —
simplemente esas rows quedan sin módulo que las lea. Pre-1.0.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
d9e21fbedc |
feat(tahuantinsuyu): fase 12 — Control::ChartPicker para Synastry
Cualquier carta del DB se puede elegir como partner de sinastría
(no solo hermanas del contacto actual). El módulo SynastryModule
declara un Control::ChartPicker; el panel renderea un dropdown que
abre un popup con todas las cartas; el shell inyecta las opciones y
resuelve el partner desde la selección persistida.
- modules: nueva variante Control::ChartPicker { key, label } sin
default — las opciones las inyecta el host. SynastryModule.controls()
agrega un picker con key="partner_chart_id".
- store: list_all_charts() — query sin filtros, ordenada por label
case-insensitive. Pensada para selectores cross-contact.
- panel:
- ChartOption struct público (id + label).
- chart_options Vec + chart_picker_value HashMap + chart_picker_open
Option (solo uno abierto a la vez).
- APIs públicas set_chart_options / set_chart_picker para sync.
- set_active_kind inicializa picker_value a None ("automático").
- render_chart_picker: botón "▾ label" en bg_button; al click toggle
un popup absolute con (automático) + separador + cada chart_option
clickable. select_picker emite ControlChanged con Value::String(id)
o Value::Null.
- shell:
- new() llama refresh_chart_options al final para popular el panel
desde el boot.
- refresh_chart_options() builds Vec<ChartOption> desde
list_all_charts (label + birth_brief "YYYY-MM-DD · Lugar"). Lo
llamamos también desde TreeEvent::HierarchyChanged para que el
dropdown refleje altas/bajas.
- resolve_synastry_partner reemplaza find_synastry_partner: 1) lee
module_configs["synastry"]["partner_chart_id"] y resuelve el chart;
2) fallback al automático (primera hermana). El fallback significa
que el módulo sigue funcionando sin elegir manualmente.
- sync_panel_from_configs ahora maneja Value::String / Value::Null
→ set_chart_picker, así el picker se restaura al cargar una carta.
Persistencia: el partner_chart_id va al config_json (fase 11), así
que cada carta recuerda con quién hizo sinastría la última vez.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
e0c5c02b8e |
feat(tahuantinsuyu): fase 8 — slider interactivo + slider de edad en progression
Los `Control::Slider` del panel ya no son display-only — son arrastrables con el mismo patrón del splitter (canvas absoluto sobre el track + window mouse handlers en cada frame). El `ProgressionModule` ahora expone un slider de `target_age_years` (0..120) que el shell inicializa con la edad actual del sujeto al cargar la carta. - panel: SliderDrag struct + slider_state HashMap + slider_drag Option + métodos start/continue/end_slider_drag + apply_slider_position que calcula fraction desde la posición del mouse relativa al track y emite ControlChanged con el valor float. set_slider(module, key, val) para sincronización externa. set_active_kind ahora inicializa también los sliders desde sus defaults. render_slider pinta track + portion filled + thumb circular + canvas overlay con handlers de drag. Los Slider tienen un valor visible "X.X (min...max)" en el header. - modules: ProgressionModule agrega Control::Slider target_age_years con range 0..120, step 0.25, default 30 (placeholder — el shell lo reescribe con la edad real al cargar la carta). - shell: apply_selection(Chart) ahora calcula current_age, lo inserta en module_configs["progression"]["target_age_years"], y empuja al panel via set_slider. build_requests ya leía target_age_years desde el map (de fase 7), así que ahora el slider lo controla. Mecánica: si activás "Progresión secundaria", el slider arranca en la edad actual del sujeto. Arrastralo a la izquierda y la rueda recompone la carta progresada para esa edad simbólica — vas viendo cómo el sujeto "evoluciona" o "involuciona" a través de su línea temporal interna, con los planetas progresados moviéndose por el anillo interno y los cross aspects con la natal reorganizándose en tiempo real. Same pattern aplica de aquí en más para cualquier slider futuro (harmonic en NatalModule, target_year en SolarArc, orb_multiplier, …). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
360797132e |
feat(tahuantinsuyu): fase 4 — jog-dial perimetral, hotkeys y panel interactivo
Time scrubbing por drag en el aro exterior del wheel: rota visualmente mientras dura el drag, al soltar traduce el delta angular a minutos (1° = 4 min sideral, CW = forward) y emite CanvasEvent::TimeOffsetChanged. La Shell recomputa con engine::compute_at_offset y el ascendant rotado queda en la nueva posición. Snap visual a 0° tras commit. - engine: nueva variante compute_at_offset(chart, minutes) que suma segundos al UTC base via add_seconds + Instant::from_utc y corre la pipeline normal. compute() es ahora wrapper con offset=0. - canvas: estado nuevo layer_visibility + drag_jog. Mouse handlers registrados desde el paint callback (mismo patrón que splitter/tiled). Hotkeys D/H/X/P toggle SignDial/Houses/Aspects/Bodies, R resetea offset. FocusHandle + click-to-focus para recibir teclas. Indicador ⏱ ±Xd HH:MM en el footer con color highlight cuando el offset != 0. paint_wheel + glyph overlays respetan layer_visibility (skip capas ocultas). - modules: NatalModule.controls() ahora expone show_sign_dial / show_houses / show_aspects / show_bodies con hotkeys [D/H/X/P], más el slider de armónico. - panel: ControlPanel mantiene toggle_state cache (module_id, key) → bool, inicializa desde defaults al cambiar de ChartKind. Click invierte el toggle visualmente y emite ControlChanged. Nuevo set_toggle(module, key, value) para que la Shell mantenga sync cuando el canvas se autotogglea por hotkey. - shell: nuevo current_chart + current_offset_minutes. render_current() delega a compute_at_offset. Suscripción a CanvasEvent traduce TimeOffsetChanged → re-render, LayerVisibilityChanged → panel sync. Suscripción a PanelEvent::ControlChanged traduce show_* keys a set_layer_visible sobre el canvas. Todos los tests verdes. La fase 5 sumará módulos extra (transit, progression, synastry, uranian) + extracción de eternal de lo que falte. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
c48638fe87 |
feat(tahuantinsuyu): scaffolding del estudio astrológico (10 crates + ventana 3-panes)
Módulo nuevo `modules/tahuantinsuyu/` con 9 crates reusables + app `apps/tahuantinsuyu` ejecutable que abre la ventana del explorador y coordina los widgets: - tahuantinsuyu-card: Card Brahman + spawn_sidecar (flows chart-request/chart-result). - tahuantinsuyu-model: tipos agnósticos (Group/Contact/Chart, StoredBirthData, StoredChartConfig, ChartKind, TreeSelection). - tahuantinsuyu-store: persistencia SQLite (rusqlite) con migración v1, CRUD por entidad y descenso recursivo `charts_under_group`. - tahuantinsuyu-engine: bridge agnóstico al canvas vía `RenderModel` (Layer/Glyph/Geometry). Feature `eternal-bridge` (off por default) reservada para enchufar eternal-astrology desde ~/eternal. - tahuantinsuyu-modules: registry de módulos pluggables (Module trait + Control schema) con `NatalModule` placeholder. - tahuantinsuyu-theme: AstroPalette (elementos / modos / planetas / aspectos) con variantes dark + light sobre yahweh-theme. - tahuantinsuyu-canvas: widget GPUI con CanvasState (Empty / Wheel / Thumbnails). Render placeholder hasta cablear la rueda real. - tahuantinsuyu-tree: explorador izquierdo sobre yahweh-widget-tree, prefijos g:/c:/h: para Group/Contact/Chart. - tahuantinsuyu-panel: control panel inferior que lee Controls de los módulos del registry y los pinta. - apps/tahuantinsuyu: binario `tahuantinsuyu` (launch_app-style) con Shell coordinador (tree↔canvas↔panel), DB en $XDG_DATA_HOME. Workspace Cargo.toml actualizado con los 10 miembros. `cargo check` verde, tests unitarios verdes (model/store/engine/modules/theme/card). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |