import solara
import asyncio
import base64
from pathlib import Path
# — reactive quarter‐index (0…3) —
index = solara.reactive(0)
def svg_data_uri(path):
raw = Path(path).read_text(encoding="utf-8")
b64 = base64.b64encode(raw.encode("utf-8")).decode("ascii")
return f"data:image/svg+xml;base64,{b64}"
# Inline all three SVGs
BASE_URI = svg_data_uri("VERAcompass.svg")
NEEDLE_URI = svg_data_uri("VERAcompass_needle_new.svg")
PIN_URI = svg_data_uri("VERA_compass_pin.svg")
# Layout constants
SIZE = 320 # px for overall compass
PIN_SIZE = SIZE * 0.15 # 10% pin
# Pivot for CSS transform-origin in percent
PIVOT_X_PCT = 0.50
PIVOT_Y_PCT = 0.495
@solara.component
def Page():
def go_prev():
index.value = (index.value - 1) % 4
def go_next():
index.value = (index.value + 1) % 4
def do_reset():
index.value = 0
# Compute angle: 0°, 90°, 180°, 270°
angle = index.value * 90
# Build a small block of HTML + CSS that layers the three images
html = f"""
<div style="position:relative;
width:{SIZE}px;height:{SIZE}px;
margin:auto;border:1px solid #ccc;">
<!-- Base -->
<img src="{BASE_URI}"
style="position:absolute;top:0;left:0;
width:100%;height:100%;pointer-events:none;" />
<!-- Needle -->
<img src="{NEEDLE_URI}"
style="position:absolute;
top:16%;left:24%;
width:160px;
transform:translate(50%,50%);
transform:rotate({angle}deg);
pointer-events:none;" />
<!-- Pin -->
<img src="{PIN_URI}"
style="position:absolute;
width:{PIN_SIZE}px;height:{PIN_SIZE}px;
top:50%;left:50%;
transform:translate(-50%,-50%);
pointer-events:none;" />
</div>
"""
# Render it
solara.HTML(unsafe_innerHTML=html)
# Controls
with solara.Row():
solara.Button("◀ Prev", on_click=go_prev)
solara.Button("Next ▶", on_click=go_next)
solara.Button("Reset", on_click=do_reset)
# Autoplay first +90° after 1s
def startup():
async def _d():
await asyncio.sleep(1)
go_next()
asyncio.create_task(_d())
solara.use_effect(startup, [])
# Mount
app = Page