Skip to content

Adding Project based organisation for large projects - Ltk #26

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions ltk 01 -project starter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
When developing an application which is larger than a demo, its useful to have a better structure.

This series is about presenting a better project-based structure.

# Part 1:

## Pyodide (full python) or Micropython
We want to delay the decision of choosing between these two as long as possible.
To this end the index.html has both possible with Pyodide initially disabled.

## Loading animation
The very first time a user hits your page, there will be a delay.
This delay will always be longer for Pyodide than for Micropython.
The index.html has a preloading section for required css and a modal dialog.

## Terminal
When initially developing it's often useful to have the python terminal available.
The terminal takes up a bit of room but it can be resized.

## Initial user interaction
Dom manipulation is supported via pyscript.web
Next steps are to go to the ltk for all screen UI
90 changes: 90 additions & 0 deletions ltk 01 -project starter/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Newtitle</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- navbar styles preloader -->
<style>
:root { --loadbord: #00a2e8ff; --loadBG: #b3d8f4; --loadpale: #f0faff;
}
*,
*::before,
*::after {
box-sizing: border-box; }
h3 { font-weight: 400; }

#loading {
outline: 15px solid var(--loadpale); justify-content: center;
border: 3px solid var(--loadbord); border-radius: 15px;
background: transparent; }
.container {
display: flex;
align-items: center;
height: 60px;
overflow: hidden;
width: 100%;
padding: 0px 0px 8px 10px;
box-sizing: border-box; }
/* from https://whirl.netlify.app/ */
.arc:before {
-webkit-animation: spin 1.9s infinite linear;
animation: spin 1.9s infinite linear;
border-radius: 100%;
border-top: 6px solid var(--loadbord);
content: '';
display: block;
height: 50px;
width: 50px; }

.hidden { display: none; }
.loadslide { width: 120px; animation: slide 11s ease-in; }
@-webkit-keyframes spin {
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
@keyframes spin {
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
@keyframes slide {
from { transform: translateX(0%); }
to { transform: translateX(300%); } }
</style>
<script type="module">
const interpreter = "mpy"; //"pyodide";
//document.body.append(interpreter) // clean all this away when finished
//
const loading = document.getElementById('loading');
if (interpreter === "pyodide") {
addEventListener('py:ready', () => loading.close());
} else {
addEventListener('mpy:ready', () => loading.close());
}
loading.showModal();
</script>

<!-- Import PyScript -->
<link rel="stylesheet" href="https://pyscript.net/releases/2024.11.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.11.1/core.js"></script>

</head>
<body>
<dialog id="loading">
<div class="container arc"></div>
<h3 style="display:inline;">Building:</h3>
<h1 style="display:inline;">Newtitle</h1>
<h3>Assembling bits and pieces...</h3>
<h3 class="loadslide">Almost there...</h3>
</dialog>

<!-- Choose interpreter: clean away unused when finished -->
<!-- pyodide
<script type="py" src="main.py" config="pyscript_py.toml" terminal></script> -->
<!-- micropython -->
<script type="mpy" src="./main.py" config="./pyscript_mpy.toml" terminal></script>
<link rel="stylesheet" href="./main.css"/>

</body>
</html>
3 changes: 3 additions & 0 deletions ltk 01 -project starter/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.css-class1 {
background: #f8f6e7;
}
34 changes: 34 additions & 0 deletions ltk 01 -project starter/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from pyscript.web import page, div, button, span, br
from pyscript import when, window, config
MICROPYTHON = config["type"] == "mpy" # if we need to know if we're running pyodide or micropython

if '__terminal__' in locals():
__terminal__.resize(60, 10)

def add_ui(toplevelpage):
toplevelpage.append(
div(
button(span("Hello! "), span("World!")),
br(),
button("Click me!", id="my-button"),
classes=["css-class1", "css-class2"],
style={"border": "2px dashed red"}
))

def my_button_click_handler(event):
print("The button has been clicked!")

if __name__ == "__main__":
print(f"Printing to Terminal: ({"mpy" if MICROPYTHON else "pyodide"})")
add_ui(page)
# UI built
when("click", "#my-button", handler=my_button_click_handler)
# explain
explanation = ["Index example:","- Specify micropython or pyodide in index.html",
" - two manual changes needed in index.html to swap",
"- Add a loading animation",
"- Include a resized Terminal for manual debugging",
"- basic pyscript.web based dom manipulation"
]
print("\n".join(explanation))

1 change: 1 addition & 0 deletions ltk 01 -project starter/pyscript_mpy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name = "Newtitle"
1 change: 1 addition & 0 deletions ltk 01 -project starter/pyscript_py.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name = "Newtitle"
18 changes: 18 additions & 0 deletions ltk 02 -project starter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
When developing an application which is larger than a demo, its useful to have a better structure.

This series is about presenting a better project-based structure.

# Part 2:
Building on ideas described in Part1.
- Pyodide (full python) or Micropython
- "Loading" animation

## Initial user interaction
We are now using the Ltk for Dom manipulation and all screen UI.
Ltk has jQuery base, so can also use that approach for Selectors and dom manipulation

## Terminal
The Ltk allows us to move the terminal into a sliding section.
This means we can minimise the terminal on-screen while still having full access.


96 changes: 96 additions & 0 deletions ltk 02 -project starter/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Newtitle</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- navbar styles preloader -->
<style>
:root { --loadbord: #00a2e8ff; --loadBG: #b3d8f4; --loadpale: #f0faff;
}
*,
*::before,
*::after {
box-sizing: border-box; }
h3 { font-weight: 400; }

#loading {
outline: 15px solid var(--loadpale); justify-content: center;
border: 3px solid var(--loadbord); border-radius: 15px;
background: transparent; }
.container {
display: flex;
align-items: center;
height: 60px;
overflow: hidden;
width: 100%;
padding: 0px 0px 8px 10px;
box-sizing: border-box; }
/* from https://whirl.netlify.app/ */
.arc:before {
-webkit-animation: spin 1.9s infinite linear;
animation: spin 1.9s infinite linear;
border-radius: 100%;
border-top: 6px solid var(--loadbord);
content: '';
display: block;
height: 50px;
width: 50px; }

.hidden { display: none; }
.loadslide { width: 120px; animation: slide 11s ease-in; }
@-webkit-keyframes spin {
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
@keyframes spin {
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg); } }
@keyframes slide {
from { transform: translateX(0%); }
to { transform: translateX(300%); } }
</style>
<script type="module">
const interpreter = "mpy"; // pyodide mpy
//document.body.append(interpreter) // clean all this away when finished
//
const loading = document.getElementById('loading');
if (interpreter === "pyodide") {
addEventListener('py:ready', () => loading.close());
} else {
addEventListener('mpy:ready', () => loading.close());
}
loading.showModal();
</script>

<!-- Import PyScript -->
<link rel="stylesheet" href="https://pyscript.net/releases/2024.11.1/core.css">
<script type="module" src="https://pyscript.net/releases/2024.11.1/core.js"></script>

<!-- Import jQuery - used in ltk/jquery.py -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-ui@1.13.2/dist/jquery-ui.min.js"></script>
<script src=" https://cdnjs.cloudflare.com/ajax/libs/leader-line/1.0.3/leader-line.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.13.2/themes/base/jquery-ui.css"/>

</head>
<body>
<dialog id="loading">
<div class="container arc"></div>
<h3 style="display:inline;">Building:</h3>
<h1 style="display:inline;">Newtitle</h1>
<h3>Assembling bits and pieces...</h3>
<h3 class="loadslide">Almost there...</h3>
</dialog>

<!-- Choose interpreter: clean away unused when finished -->
<!-- pyodide
<script type="py" src="main.py" config="pyscript_py.toml" terminal></script> -->
<!-- micropython -->
<script type="mpy" src="./main.py" config="./pyscript_mpy.toml" terminal></script>
<link rel="stylesheet" href="./main.css"/>

</body>
</html>
8 changes: 8 additions & 0 deletions ltk 02 -project starter/main.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.description {
font-size: 1.0rem;
font-style: light;
border: 2px dashed red;
}
#graphic {
border: 1px dashed #0d720d;
}
93 changes: 93 additions & 0 deletions ltk 02 -project starter/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#imports
import ltk
import svg as SVG
import random
from pyscript import config
MICROPYTHON = config["type"] == "mpy" # if we need to know if we're running pyodide or micropython

if '__terminal__' in locals():
__terminal__.resize(60, 30)

# for SVG
solid_style = {"fill":"#AA0", "stroke":"#A00", "stroke-width":"1px"}

def create_svg_box(size=5):
overall = 100
box_size = 100 / size
highlight_svg = SVG.svg(width=overall, height=overall,
preserveAspectRatio="xMidYMid meet",
viewBox=f"0 0 {overall+2} {overall+2}")
# Transform the group to move its children
grp = SVG.g(id="highlight", transform='translate(0 0)', style=solid_style)
highlight_svg.appendChild(grp)
grp.appendChild(SVG.rect(x=0, y=0, width=box_size, height=box_size))
#
return highlight_svg

def button_click_handler(event):
print("The button has been clicked, the svg transformed")
# move the svg child
x,y = random.randrange(0, 100-20), random.randrange(0, 100-20)
ltk.find("#highlight").attr("transform", f"translate({x} {y})")

class UI_widget(object):
"""
Top level object that shows App.
"""

def __init__(self):
self.explanation = ["Ltk project example:","- Swap between micropython or pyodide in index.html",
"- Everything from starter_01 but using the Ltk for UI instead",
"- 'Ltk' used instead of direct dom manipulation",
"- Ltk has jQuery base, so can also use that approach for Selectors and dom manipulation",
"- The Terminal is in a top level slider. Try moving it out of the way",
"- SVG is included for more complex UIs"
]

def create(self):
info_paragraph = ltk.Paragraph("<br>".join(self.explanation)).attr("id","explanation").addClass("description")
return (ltk.VBox(
ltk.HorizontalSplitPane( # or VerticalSplitPane if your UI is better that way
ltk.Div(
# put your UI in here
# - can easily just remove these dummy panes when you no longer need the terminal
ltk.Div(
ltk.Button("Click me!", button_click_handler).attr("id","my-button")
),
ltk.Div().attr("id", "graphic"),
# overall description
info_paragraph
).attr("id", "mydiv").css("border", "2px solid red"),

# For the terminal
ltk.Div().attr("id", "forterm").css("border", "2px solid green"),
"Temp-split-pane"
)
))


if __name__ == "__main__":
w = UI_widget()
widget = w.create()
widget.appendTo(ltk.window.document.body)

# move terminal to sliding pane using one of these methods:
# - the usual Javascript mechanism
term = ltk.window.document.getElementsByTagName("py-terminal")[0]
term_box = ltk.window.document.getElementById("forterm")
# - OR
# Using ltk.find - jquery style selectors and python lists
term = ltk.find("py-terminal")[0]
term_box = ltk.find("#forterm")[0]
#
term_box.appendChild(term)
# - OR
# Using the jQuery interface with all Jquery chaining flexibility
ltk.jQuery("#forterm")[0].append(ltk.jQuery("py-terminal")[0])
# remind us of py/mpy
print(f"The Terminal: ({"mpy" if MICROPYTHON else "pyodide"})")
# svg insert into Div
somesvg = create_svg_box()
ltk.find("#graphic").html(somesvg.outerHTML)


12 changes: 12 additions & 0 deletions ltk 02 -project starter/pyscript_mpy.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
name = "Newtitle"

[files]
"https://raw.githubusercontent.com/pyscript/ltk/main/ltk/jquery.py" = "ltk/jquery.py"
"https://raw.githubusercontent.com/pyscript/ltk/main/ltk/widgets.py" = "ltk/widgets.py"
"https://raw.githubusercontent.com/pyscript/ltk/main/ltk/pubsub.py" = "ltk/pubsub.py"
"https://raw.githubusercontent.com/pyscript/ltk/main/ltk/__init__.py" = "ltk/__init__.py"
"https://raw.githubusercontent.com/pyscript/ltk/main/ltk/logger.py" = "ltk/logger.py"
"https://raw.githubusercontent.com/pyscript/ltk/main/ltk/ltk.js" = "ltk/ltk.js"
"https://raw.githubusercontent.com/pyscript/ltk/main/ltk/ltk.css" = "ltk/ltk.css"

"./svg.py" = ""
Loading