Skip to content
This repository has been archived by the owner on Oct 30, 2023. It is now read-only.

Commit

Permalink
Update language and examples to be clearer to the reader.
Browse files Browse the repository at this point in the history
  • Loading branch information
wmealing committed Oct 29, 2023
1 parent 432b9fe commit df4578f
Show file tree
Hide file tree
Showing 5 changed files with 379 additions and 108 deletions.
25 changes: 15 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,26 @@

## About [↟](#table-of-contents)

This project was created as a spawnfest entry, if you are a judge, you may want to look at the <a href="./spawnfest-manifest.md">spawnfest-manifest</a> which outlines about the project and its boundaries.

🚀 HTMX is not just another web development library; it's pure web development magic! Think of it as your secret potion to create dynamic, interactive, and fast web applications with minimal effort. No "React" in sight, no frameworks. We bring the "Hype" back into Hyper Text Markup Language. When you couple HTMXs magic with the unstoppable terminator mindset of BEAM supervised processes, industrial grade magic is within reach.

The Untitled Project is basically a learning tool. Its an interactive experience that demonstrates the
unstopable power of using Lisp Flavored Erlang on the backend and HTMX on the front.


Each micro lesson provides both backend and frontend code for the reader to observe and interact with while
not having to setup the full stack in a safe and controlled environment.

This project was created as a spawnfest entry, if you are a judge, you may want to look at the <a href="./spawnfest-manifest.md">spawnfest-manifest</a> which outlines about the project and its boundaries.

## Rationale [&#x219F;](#table-of-contents)


### Why HTMX ?
Matt.sh talks about <a href="https://matt.sh/htmx-is-a-erlang"> HTMX being an erlang </a>, While there is
more to erlang than self-upgrading its still very cool.

HTMX puts development of Single Page Applications (SPA, apparently web pages are apps). It appears to do
most of the common webappy stuff with markup instead of writing oodles of javascript.

🚀 HTMX is not just another web development library; it's pure web development magic! Think of it as your secret potion to create dynamic, interactive, and fast web applications with minimal effort. No "React" in sight, no frameworks. We bring the "Hype" back into Hyper Text Markup Language. When you couple HTMXs magic with the unstoppable terminator mindset of BEAM supervised processes, industrial grade magic is within reach.


HTMX simplifies the development of Single Page Applications (SPA, apparently web pages are apps). It does most of
the common webappy stuff with markup instead of writing oodles of javascript.


### Why Lisp Flavored Erlang
Expand All @@ -51,14 +52,17 @@ both into production.
Erlang is the T-800 terminator of programming languages, when its hit or crashes it just gets right back up. Lisp
Flavored Erlang provides alien technology to Erlang raising the bar once again.

This verion of TBWLE (Untitled Project) intends to demonstrate HTMX and LFE, I will continue to feed my learning
This version of TBWLE (Untitled Project) intends to demonstrate HTMX and LFE, I will continue to feed my learning
back into this project as I learn new skills.

It would be great if people could also contribute to this project to foster a learning community around LFE and HTMX.

## Submitting bugs [&#x219F;](#table-of-contents)

This project accepts bugs and features using github issues, you can lodge one <a href="https://github.com/spawnfest/UntitledProject/issues"> here </a>

Bugs and features will be fixed when I can. Pull Requests, are also it accepted will make my life a lot easier.
Bugs and features will be fixed when I can. Pull Requests, are also it accepted will make my life a lot easier. Github
actions are configured on this repostiory, when cloning this repo, please make sure that the current tests pass.

## Build [&#x219F;](#table-of-contents)

Expand All @@ -70,6 +74,7 @@ $ rebar3 lfe compile

```shell
$ rebar3 lfe repl
lfe> (untitled_project:start))
```

# Tests [&#x219F;](#table-of-contents)
Expand Down
43 changes: 26 additions & 17 deletions priv/chapter1.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@
padding-left: 1.25rem; /* 20px */
padding-right: 1.25rem; /* 20px */
}

div.reallybig {
font-size: 126px;
color: rgb(255,255,102);
}


</style>
</head>

Expand All @@ -53,16 +60,16 @@ <h1 class="text-black-600 text-5xl font-bold">
</p>

<p>
Here is the method of including the latest version at the time of writing.
The method of including the latest version at the time of writing is:
</p>

<p class="py-5">
&lt;script src=&quot;https://unpkg.com/[email protected]&quot;&gt;&lt;/script&gt;
</p>

<p>
Adding the htmx library creates actions based on the specific attributes of HTML tags,
its pretty neat.
Adding the HTMX library creates actions based on the specific attributes of HTML tags,
it's pretty neat.
</p>

<b>The simplest example.</b>
Expand All @@ -74,12 +81,12 @@ <h1 class="text-black-600 text-5xl font-bold">

<p>
In this minimal example, we will demonstrate how to use LFE/HTMX with the humble &lt;button&gt; element.

<p>

<p>
In the 'common' use scenario, button clicks trigger a javascript event.
Usually a button click triggers a javascript event.

HTMX reduces this complexity to elements on any html element. Check this out:
HTMX specifies behavior by adding attributes on any HTML element. Check this out:
</p>

<br>
Expand Down Expand Up @@ -115,9 +122,7 @@ <h1 class="text-black-600 text-5xl font-bold">
<b>The "Back end"</b>

<p class="py-5">
Of course this needs some server-side backend code to work correctly, You'd need to
run a simple web server that suits your needs. If you check out the code for this project, you will
see that it is using "barista" with "lanes", a neat little HTTP server and routing utility.
This needs some server-side backend code to work correctly, I use <a href="https://github.com/lfe-http/barista">Barista</a> (as a web server) with <a href="https://github.com/lfe-http/lanes">lanes</a> (a routing library) to get started.
<p>

<p>
Expand All @@ -127,14 +132,14 @@ <h1 class="text-black-600 text-5xl font-bold">
</p>

<p>
The main guts of Barista's work is done via a a <a href="https://github.com/lfe-http/barista/tree/main#creating-custom-modules-"> Custom module </a>. We're going to create a custom module that hands routing off to "lanes"
to make things just that little bit easier to understand.
Barista's is an LFE wrapper around erlangs built-in HTTP server, the Barista server implements serving requests the same way as the built in server, by using a <a href="https://github.com/lfe-http/barista/tree/main#creating-custom-modules-"> custom module </a>. We're going to create a custom module using lanes' "defroutes" macro to make the routes easier to understand.
</p>

<p>
In the example below, we're going to put all the functions below into a single function and
uses the "defroutes" macro supplied by the lanes library. We're going to start here by defining a
single route that the app will use when the button is clicked on.
In the example below, we're going to put all the routes into a single function and
use the "defroutes" macro supplied by the lanes library. Start by defining a
single route that the app will use when the button is clicked on. Additional routes
can be added later.
</p>

<br>
Expand All @@ -148,9 +153,13 @@ <h1 class="text-black-600 text-5xl font-bold">

<p>
In our example, we want to handle the HTTP POST verb, and return a HTML fragment.<br>
The "method" is an erlang atom 'GET 'POST etc.<br>
The "path" pattern is a binary list #"chapter1-clicked". <br>
Lanes creates some additional functionality, that we will get into later.
<ul>
<li>The "method" is an erlang atom 'GET 'POST etc, - 'POST in this example</li>
<li>The "path" pattern is a binary list - #"chapter1-clicked"</li>
<li>Return the resulting of the <a href="https://github.com/lfe-http/barista/blob/main/src/barista-response.lfe">barista-response</a> funtion</li>
</ul>
Lanes creates some additional functionality in the path string, that will be demonstrated later.</li>
</ul>
</p>

<p>
Expand Down
227 changes: 227 additions & 0 deletions priv/chapter2.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
<!DOCTYPE html>
<html>
<script src="https://unpkg.com/[email protected]"></script>
<style>
html {
max-width: 80ch;
padding: 3em 1em;
margin: auto;
line-height: 1.75;
font-size: 1.25em;
background-color: rgb( 0 70 67);
color: rgb(171 209 198);
font-family: system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
line-height: 1.5;
}

button {
background-color: #f9bc60;
color: #001e1d;
border-radius: 44px;
width: 10rem;
height: 4rem;
font-size: 1rem; /* 16px */
padding: 20px;
}

a {
color: #FFFFFF;
}

p {
padding-left: 1.25rem; /* 20px */
padding-right: 1.25rem; /* 20px */
padding-top: 1.25rem;
}

div {
padding-left: 1.25rem; /* 20px */
padding-right: 1.25rem; /* 20px */
padding-top: 1.25rem; /* 20px */
}

pre {
background-color: #BDB76B;
color: #001e1d;
}

/* Do this because otherwise i can't see the highlighting */
pre::selection {
/* Change highlight background color to black */
background: #000;
/* Change highlight text color to red */
color: #ff0000;
}

</style>

<body>
<h1>
A "Click to edit" Example.
</h1>

<b>Setting up your HTML - Click to Edit Example</b>

<p>
We're going to increase the voltage, amp up the functionality with the 'click to edit pattern'.
This provides a way to offer inline editing of all or part of a record without a full page refresh.
This fits in beautifully with the htmx mindset.
</p>

<p>
We borrow the example from the HTMX site (with permission! thank you <a href="https://x.com/htmx_org?">@htmx.org</a>)
</p>

<p>
<b> The presentation and input layer (AKA HTML)</b>
</p>

<pre>

&lt;div hx-target=&quot;this&quot; hx-swap=&quot;outerHTML&quot;&gt;
&lt;div&gt;&lt;label&gt;First Name&lt;/label&gt;: Joe&lt;/div&gt;
&lt;div&gt;&lt;label&gt;Last Name&lt;/label&gt;: Armstrong&lt;/div&gt;
&lt;div&gt;&lt;label&gt;Email&lt;/label&gt;: [email protected]&lt;/div&gt;
&lt;button hx-get=&quot;/contact/1/edit&quot; class=&quot;btn btn-primary&quot;&gt;
Click To Edit
&lt;/button&gt;
&lt;/div&gt;

</pre>

<p>
When the button is clicked it will make a "GET" request, to /contact/1/edit which returns
a HTML fragment, and replaces this "div" tag with the fetched content. The current CSS styling is
applied directly. There is no <a href="https://en.wikipedia.org/wiki/Flash_of_unstyled_content">flash of unstyled content</a> and the button disappears with the content in its place.
</p>

<p>
Here is the fragment of HTML returned on the 'click' event:
</p>

<pre>
&lt;form hx-put=&quot;/contact/1&quot; hx-target=&quot;this&quot; hx-swap=&quot;outerHTML&quot;&gt;
&lt;div&gt;
&lt;label&gt;First Name&lt;/label&gt;
&lt;input type=&quot;text&quot; name=&quot;firstName&quot; value=&quot;Joe&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;form-group&quot;&gt;
&lt;label&gt;Last Name&lt;/label&gt;
&lt;input type=&quot;text&quot; name=&quot;lastName&quot; value=&quot;Armstrong&quot;&gt;
&lt;/div&gt;
&lt;div class=&quot;form-group&quot;&gt;
&lt;label&gt;Email Address&lt;/label&gt;
&lt;input type=&quot;email&quot; name=&quot;email&quot; value=&quot;[email protected]&quot;&gt;
&lt;/div&gt;
&lt;button class=&quot;btn&quot;&gt;Submit&lt;/button&gt;
&lt;button class=&quot;btn&quot; hx-get=&quot;/contact/1&quot;&gt;Cancel&lt;/button&gt;
&lt;/form&gt;
</pre>

<p>
This new fragment replaces the previous &lt;div&gt; with what looks to be a normal
HTML form, with some minor differences. This form tag has an additional 'hx-put' attribute,
one of those verbs that were previously off-limits to normal HTML. By using the PUT verb,
the request can map nicely to the backend handler to "UPDATE" the resource (in this case, a contact).
</p>

<p>
As a reminder, The verbs map to specific functionality. Using these conventions makes it easier
to understand the authors intent.
</p>

<ul>
<li>GET verb is used to fetch a resource for viewing</li>
<li>POST verb is used to create a resource</li>
<li>PUT verb is used to update a resource</li>
<li>DELETE verb is used to delete a resource</li>
</ul>

<p>
There are other verbs, you can learn about them on your own time and decide when best to use them.
</p>

<p>
Because we are editing an existing contact, we use the HTTP PUT verb to update the existing
contact. Mozilla's <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PUT">thoughts</a>
on the method suggest we shouldn't be using it for from elements, let them try and stop us !
</p>

<b> Interactive Example </b>

<div hx-target="this" hx-swap="outerHTML">
<div><label>First Name</label>: Joe</div>
<div><label>Last Name</label>: Armstrong</div>
<div><label>Email</label>: [email protected]</div>

<button hx-get="/chapter2/contact/1/edit">
Click To Edit
</button>
</div>

<b>When the "Click to Edit" button is used: </b>
<ul>
<li> The pre-filled html fragment is fetched from the server, and rendered by the browser. The state is provided by the server.</li>
<li> The new form has textfields for entry, and allows the end user to modify the form data. </li>
</ul>

<b>When the submit button is clicked: </b>
<ul>
<li> A "PUT" to the webserver, including all the data from the elements in the &lt;form&gt; tag.</li>
<li> The server validates the data, and can send back validation information in html, or return the new state of the object.</li>
</ul>

<p>
Here is the lanes route handler for both features:
</p>

<pre>
(defroutes

;; previous routes above here...

('GET #"/chapter2/contact/:id/edit"
(progn
(barista-response:ok (erlang:binary_to_list (template:load "chapter2-edit.html")))))

('PUT #"/chapter2/contact/:id"
(progn
(validate id (barista-request:get-data req))
(barista-response:ok (erlang:binary_to_list (template:load "chapter2-update.html")))))
</pre>

<b> The 'GET verb: </b>
<p>
In the interest of simplicity, this has been simplified to load a pre-filled HTML form.
Usually this would be loaded from a database, and the database information applied to the
an empty form. In the interest of brevity, this has been left as an exercise for the reader.
</p>

<b> The 'PUT verb </b>
<p>
This is matched when the client makes a "PUT" request. Instead of directly returning the page,
the validate function will check the request data to ensure that the content can be updated.
</p>

<p>
This example validation function will always deny being able to update Joe's information,
however in normal deployment this would be written to a database once validated.
</p>

<b> Creating validate function </b>

<p>
Form validation is NOT a solved problem, Calling the <a href="https://github.com/erlangbureau/liver">liver</a> library looks to be one of the easier options. In our example, we're going to do a check which will always fail, and then redirect to a validation error.
</p>


<pre>
(defun validate (id map)

if (string:equals (get-map map 'firstname) "joe")
"You cant edit joe, sorry.."
)
</pre>

</body>
</html>
Loading

0 comments on commit df4578f

Please sign in to comment.