Skip to content

Commit 01ec02b

Browse files
committed
restructure after seeing new react docs
1 parent 21a94c0 commit 01ec02b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+455
-406
lines changed

docs/main.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ async def forward_to_index(request):
3030
def make_component():
3131
mount, component = multiview()
3232

33-
examples_dir = HERE / "source" / "examples"
33+
examples_dir = HERE / "source" / "_examples"
3434
sys.path.insert(0, str(examples_dir))
3535

3636
original_run = idom.run
+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import asyncio
2+
import enum
3+
import random
4+
import time
5+
6+
import idom
7+
8+
9+
class GameState(enum.Enum):
10+
lost = 1
11+
won = 2
12+
play = 3
13+
14+
15+
@idom.component
16+
def GameView():
17+
game_state, set_game_state = idom.hooks.use_state(GameState.play)
18+
19+
if game_state == GameState.play:
20+
return GameLoop(grid_size=6, block_scale=50, set_game_state=set_game_state)
21+
22+
start_button = idom.html.button(
23+
{"onClick": lambda event: set_game_state(GameState.play)},
24+
"Start",
25+
)
26+
27+
if game_state == GameState.won:
28+
menu = idom.html.div(idom.html.h3("You won!"), start_button)
29+
else:
30+
menu = idom.html.div(idom.html.h3("You lost"), start_button)
31+
32+
menu_style = idom.html.style(
33+
"""
34+
.snake-game-menu h3 {
35+
margin-top: 0px !important;
36+
}
37+
"""
38+
)
39+
40+
return idom.html.div({"className": "snake-game-menu"}, menu_style, menu)
41+
42+
43+
class Direction(enum.Enum):
44+
ArrowUp = (0, -1)
45+
ArrowLeft = (-1, 0)
46+
ArrowDown = (0, 1)
47+
ArrowRight = (1, 0)
48+
49+
50+
@idom.component
51+
def GameLoop(grid_size, block_scale, set_game_state):
52+
# we `use_ref` here to capture the latest direction press without any delay
53+
direction = idom.hooks.use_ref(Direction.ArrowRight.value)
54+
# capture the last direction of travel that was rendered
55+
last_direction = direction.current
56+
57+
snake, set_snake = idom.hooks.use_state([(grid_size // 2 - 1, grid_size // 2 - 1)])
58+
food, set_food = use_snake_food(grid_size, snake)
59+
60+
grid = create_grid(grid_size, block_scale)
61+
62+
@idom.event(prevent_default=True)
63+
def on_direction_change(event):
64+
if hasattr(Direction, event["key"]):
65+
maybe_new_direction = Direction[event["key"]].value
66+
direction_vector_sum = tuple(
67+
map(sum, zip(last_direction, maybe_new_direction))
68+
)
69+
if direction_vector_sum != (0, 0):
70+
direction.current = maybe_new_direction
71+
72+
grid_wrapper = idom.html.div({"onKeyDown": on_direction_change}, grid)
73+
74+
assign_grid_block_color(grid, food, "blue")
75+
76+
for location in snake:
77+
assign_grid_block_color(grid, location, "white")
78+
79+
new_game_state = None
80+
if snake[-1] in snake[:-1]:
81+
assign_grid_block_color(grid, snake[-1], "red")
82+
new_game_state = GameState.lost
83+
elif len(snake) == grid_size ** 2:
84+
assign_grid_block_color(grid, snake[-1], "yellow")
85+
new_game_state = GameState.won
86+
87+
interval = use_interval(0.5)
88+
89+
@idom.hooks.use_effect
90+
async def animate():
91+
if new_game_state is not None:
92+
await asyncio.sleep(1)
93+
set_game_state(new_game_state)
94+
return
95+
96+
await interval
97+
98+
new_snake_head = (
99+
# grid wraps due to mod op here
100+
(snake[-1][0] + direction.current[0]) % grid_size,
101+
(snake[-1][1] + direction.current[1]) % grid_size,
102+
)
103+
104+
if snake[-1] == food:
105+
set_food()
106+
new_snake = snake + [new_snake_head]
107+
else:
108+
new_snake = snake[1:] + [new_snake_head]
109+
110+
set_snake(new_snake)
111+
112+
return grid_wrapper
113+
114+
115+
def use_snake_food(grid_size, current_snake):
116+
grid_points = {(x, y) for x in range(grid_size) for y in range(grid_size)}
117+
points_not_in_snake = grid_points.difference(current_snake)
118+
119+
food, _set_food = idom.hooks.use_state(current_snake[-1])
120+
121+
def set_food():
122+
_set_food(random.choice(list(points_not_in_snake)))
123+
124+
return food, set_food
125+
126+
127+
def use_interval(rate):
128+
usage_time = idom.hooks.use_ref(time.time())
129+
130+
async def interval() -> None:
131+
await asyncio.sleep(rate - (time.time() - usage_time.current))
132+
usage_time.current = time.time()
133+
134+
return asyncio.ensure_future(interval())
135+
136+
137+
def create_grid(grid_size, block_scale):
138+
return idom.html.div(
139+
{
140+
"style": {
141+
"height": f"{block_scale * grid_size}px",
142+
"width": f"{block_scale * grid_size}px",
143+
"cursor": "pointer",
144+
"display": "grid",
145+
"grid-gap": 0,
146+
"grid-template-columns": f"repeat({grid_size}, {block_scale}px)",
147+
"grid-template-rows": f"repeat({grid_size}, {block_scale}px)",
148+
},
149+
"tabIndex": -1,
150+
},
151+
[
152+
idom.html.div(
153+
{"style": {"height": f"{block_scale}px"}},
154+
[create_grid_block("black", block_scale) for i in range(grid_size)],
155+
)
156+
for i in range(grid_size)
157+
],
158+
)
159+
160+
161+
def create_grid_block(color, block_scale):
162+
return idom.html.div(
163+
{
164+
"style": {
165+
"height": f"{block_scale}px",
166+
"width": f"{block_scale}px",
167+
"backgroundColor": color,
168+
"outline": "1px solid grey",
169+
}
170+
}
171+
)
172+
173+
174+
def assign_grid_block_color(grid, point, color):
175+
x, y = point
176+
block = grid["children"][x]["children"][y]
177+
block["attributes"]["style"]["backgroundColor"] = color
178+
179+
180+
idom.run(GameView)
File renamed without changes.

docs/source/_exts/autogen_api_docs.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
HERE = Path(__file__).parent
1010
PACKAGE_SRC = HERE.parent.parent.parent / "src"
1111

12-
AUTOGEN_DIR = HERE.parent / "autogen"
12+
AUTOGEN_DIR = HERE.parent / "_autogen"
1313
AUTOGEN_DIR.mkdir(exist_ok=True)
1414

1515
PUBLIC_API_REFERENCE_FILE = AUTOGEN_DIR / "user-apis.rst"

docs/source/_exts/build_custom_js.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66

77
SOURCE_DIR = Path(__file__).parent.parent
8-
CUSTOM_JS_DIR = SOURCE_DIR / "custom_js"
8+
CUSTOM_JS_DIR = SOURCE_DIR / "_custom_js"
99

1010

1111
def setup(app: Sphinx) -> None:

docs/source/_exts/widget_example.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99

1010
here = Path(__file__).parent
11-
examples = here.parent / "examples"
11+
examples = here.parent / "_examples"
1212

1313

1414
class WidgetExample(SphinxDirective):
@@ -124,7 +124,7 @@ def _interactive_widget(name, with_activate_button):
124124

125125

126126
_literal_include_template = """
127-
.. literalinclude:: /examples/{name}.{ext}
127+
.. literalinclude:: /_examples/{name}.{ext}
128128
:language: {language}
129129
{linenos}
130130
"""

0 commit comments

Comments
 (0)