ShellLite includes a dedicated Domain Specific Language (DSL) for building web applications. It reads like a description of a website.
A Web App in ShellLite usually consists of:
- Components/Pages: Reusable UI parts
- Routes: URLs that users visit
- Middleware: Code that runs before requests
- Server: The command to start listening
Use define page to create HTML structures using English words.
define page HomePage
h1 "Welcome to My Site"
p "Built with ShellLite."
button "Click Me"You can nest elements naturally using indentation.
define page List
ul
li "Item 1"
li "Item 2"
li "Item 3"| Element | Description |
|---|---|
h1 - h6 |
Headings |
p |
Paragraph |
div |
Division/container |
span |
Inline container |
a |
Link |
img |
Image |
ul, ol |
Lists |
li |
List item |
button |
Button |
input |
Input field |
form |
Form container |
table, tr, td |
Table elements |
define page ContactPage
h1 "Contact Us"
form action="/submit" method="post"
input name="email" placeholder="Your email"
input name="message" placeholder="Your message"
button "Send"
a href="/" "Back to Home"
img src="/logo.png" alt="Company Logo"Tell the server what to do when a user visits a URL.
when someone visits "/"
HomePage
when someone visits "/about"
define page AboutPage
h1 "About Us"
p "We are a great company."
AboutPage
when someone visits "/users"
users = db query "SELECT * FROM users"
define page UsersPage
h1 "All Users"
ul
for user in users
li user["name"]
UsersPagewhen someone submits to "/login"
username = request.form["username"]
password = request.form["password"]
# Validate credentials
if username == "admin" and password == "secret"
say "User logged in: " + username
DashboardPage
else
define page ErrorPage
h1 "Login Failed"
p "Invalid credentials"
ErrorPagewhen someone visits "/user/:id"
user_id = request.params["id"]
user = db query "SELECT * FROM users WHERE id = ?", [user_id]
define page UserProfile
h1 "User Profile"
p "ID: " + str(user_id)
UserProfileYou can run code before every request, for example, to log activity or check authentication.
before request
say "Incoming request to: " + request.path
say "Method: " + request.methodbefore request
# Check if user is logged in for protected routes
if request.path.startswith("/admin")
if not request.session.get("logged_in")
# Redirect to login
redirect "/login"You can serve static files (images, CSS, JavaScript) from a folder.
serve files from "public"
serve static from "assets"This makes all files in the public or assets folder accessible via URL.
Finally, bring it all to life.
start server on port 8080Now, open your browser to http://localhost:8080.
# Different ports
start server on port 3000
start server on port 5000
# Listen on port (alternative syntax)
listen on port 8080The request object contains information about the incoming request.
| Property | Description |
|---|---|
request.path |
URL path (e.g., "/users") |
request.method |
HTTP method (GET, POST, etc.) |
request.form |
Form data (POST requests) |
request.params |
URL parameters |
request.headers |
HTTP headers |
request.query |
Query string parameters |
when someone visits "/search"
query = request.query.get("q", "")
say "Searching for: " + query
# ... perform searchCreate interactive forms easily.
define page ContactForm
h1 "Contact Us"
form action="/contact" method="post"
div
label "Name:"
input name="name" placeholder="Your name" required="true"
div
label "Email:"
input name="email" type="email" placeholder="your@email.com"
div
label "Message:"
textarea name="message" rows="5" placeholder="Your message"
button type="submit" "Send Message"
when someone visits "/contact"
ContactForm
when someone submits to "/contact"
name = request.form["name"]
email = request.form["email"]
message = request.form["message"]
# Save to database
db exec "INSERT INTO messages (name, email, message) VALUES (?, ?, ?)", [name, email, message]
define page ThankYou
h1 "Thank You!"
p "We'll get back to you soon, " + name
ThankYouBuild REST APIs easily.
when someone visits "/api/users"
users = db query "SELECT * FROM users"
give convert users to json
when someone submits to "/api/users"
data = json.parse(request.body)
db exec "INSERT INTO users (name, email) VALUES (?, ?)", [data["name"], data["email"]]
give convert {"status": "created"} to json# Simple Todo App
tasks = a list of "Buy Milk", "Walk Dog"
define page App
h1 "My Tasks"
ul
for task in tasks
li task
form action="/add" method="post"
input name="new_task" placeholder="New task..."
button "Add Task"
define page Added
h1 "Task Added!"
p "Redirecting..."
a href="/" "Back to list"
when someone visits "/"
App
when someone submits to "/add"
new_item = request.form["new_task"]
if new_item
add new_item to tasks
Added
start server on port 5000# Simple Blog
db open "blog.db"
db exec "CREATE TABLE IF NOT EXISTS posts (id INTEGER PRIMARY KEY, title TEXT, content TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"
define page Layout title, content
html
head
title title
link rel="stylesheet" href="/style.css"
body
nav
a href="/" "Home"
a href="/new" "New Post"
main
content
define page HomePage
h1 "My Blog"
posts = db query "SELECT * FROM posts ORDER BY created_at DESC"
for post in posts
article
h2 post["title"]
p post["content"]
define page NewPost
h1 "Create New Post"
form action="/create" method="post"
input name="title" placeholder="Post title"
textarea name="content" placeholder="Write your post..."
button "Publish"
when someone visits "/"
HomePage
when someone visits "/new"
NewPost
when someone submits to "/create"
title = request.form["title"]
content = request.form["content"]
db exec "INSERT INTO posts (title, content) VALUES (?, ?)", [title, content]
redirect "/"
serve files from "public"
start server on port 3000ShellLite also supports building native desktop GUI applications with The Canvas.
# Create a simple GUI app
app "My Application" size 400, 300
column
heading "Welcome!"
row
button "Click Me" on_click show_message
button "Exit" on_click exit_app
to show_message
alert "Hello from ShellLite!"
to exit_app
exit| Element | Description |
|---|---|
app |
Define application window |
column |
Vertical layout |
row |
Horizontal layout |
button |
Clickable button |
heading |
Text heading |
input |
Text input field |
label |
Text label |