Skip to content

Commit a2209d8

Browse files
committed
add quickstart
1 parent a7c70b4 commit a2209d8

1 file changed

Lines changed: 104 additions & 0 deletions

File tree

examples/quickstart.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import uvicorn
2+
from violetear import App, StyleSheet
3+
from violetear.markup import Document, Element
4+
from violetear.color import Colors
5+
from violetear.style import Style
6+
7+
# 1. Initialize the App
8+
app = App(title="Violetear Counter")
9+
10+
# --- 1. THE STYLES (Pure Python CSS) ---
11+
style = StyleSheet(
12+
Style("body")
13+
.background(Colors.AliceBlue)
14+
.font(family="sans-serif")
15+
.flexbox(align="center", justify="center")
16+
.height("320px")
17+
.margin(top=20),
18+
Style(".counter-card")
19+
.background(Colors.White)
20+
.padding(40)
21+
.rounded(15)
22+
.shadow(blur=20, color="rgba(0,0,0,0.1)")
23+
.text(align="center"),
24+
Style(".count-display")
25+
.font(size=64, weight="bold")
26+
.color(Colors.SlateBlue)
27+
.margin(10),
28+
Style("button")
29+
.padding("10px 20px")
30+
.font(size=20, weight="bold")
31+
.margin(5)
32+
.rounded(8)
33+
.border(0)
34+
.rule("cursor", "pointer")
35+
.color(Colors.White),
36+
Style(".btn-plus").background(Colors.MediumSeaGreen),
37+
Style(".btn-minus").background(Colors.IndianRed),
38+
Style(".btn:hover").rule("opacity", "0.8"),
39+
)
40+
41+
42+
# --- 2. THE SERVER (FastAPI RPC) ---
43+
@app.server
44+
def report_count(current_count: int, action: str):
45+
"""
46+
This runs on the server.
47+
FastAPI automatically validates that current_count is an int.
48+
"""
49+
print(f"[SERVER] Count is now {current_count} (Action: {action})")
50+
return {"status": "received"}
51+
52+
53+
# --- 3. THE CLIENT (Pyodide Browser) ---
54+
@app.client
55+
async def handle_change(event):
56+
"""
57+
Runs in the browser.
58+
"""
59+
from js import document
60+
61+
# A. Get current state from DOM
62+
display_el = document.getElementById("display")
63+
current_value = int(display_el.innerText)
64+
65+
# B. Determine action
66+
action = event.target.id # "plus" or "minus"
67+
new_value = current_value + (1 if action == "plus" else -1)
68+
69+
# C. Update DOM immediately (Responsive)
70+
display_el.innerText = str(new_value)
71+
72+
# D. Sync with Server (Background)
73+
# This calls the @app.server function seamlessly!
74+
await report_count(current_count=new_value, action=action)
75+
76+
77+
# --- 4. THE UI (Server-Side Rendered) ---
78+
@app.route("/")
79+
def index():
80+
doc = Document(title="Violetear Counter")
81+
doc.style(style, href="/style.css") # Link our style
82+
83+
doc.body.add(
84+
Element("div", classes="counter-card").extend(
85+
Element("h2", text="Isomorphic Counter"),
86+
# The Count
87+
Element("div", id="display", classes="count-display", text="0"),
88+
# Controls - Both call the same Python function
89+
Element("button", id="minus", text="-", classes="btn-minus btn").on(
90+
"click", handle_change
91+
),
92+
Element("button", id="plus", text="+", classes="btn-plus btn").on(
93+
"click", handle_change
94+
),
95+
Element("p", text="Check server console for pings.").style(
96+
Style().color(Colors.Gray).margin(top=20)
97+
),
98+
)
99+
)
100+
101+
return doc
102+
103+
104+
app.run()

0 commit comments

Comments
 (0)