From a3a4dfb5dfe0a04975e7b2b1c6ce6800f55a113f Mon Sep 17 00:00:00 2001 From: Ben Pate Date: Mon, 14 Dec 2020 21:55:19 -0700 Subject: [PATCH 1/7] Create modal-custom.md This is a demo of making a custom modal dialog from scratch --- www/examples/modal-custom.md | 247 +++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 www/examples/modal-custom.md diff --git a/www/examples/modal-custom.md b/www/examples/modal-custom.md new file mode 100644 index 00000000..d686d050 --- /dev/null +++ b/www/examples/modal-custom.md @@ -0,0 +1,247 @@ +--- +layout: demo_layout.njk +--- + +## Custom Modal Dialogs + +While htmx works great with dialogs built into CSS frameworks (like [Bootstrap](../modal-bootstrap) and [UIKit](../modal-uikit)), htmx also makes it easy to build modal dialogs from scratch. Here is a quick example of one way to build them. + +Click here to see a demo of the final result: + + + +### High Level Plan + +We're going to make a button that loads remote content from the server, then displays it in a modal dialog. The modal content will be added to the end of the `` element, in a div named `#modal`. + +We'll define some nice animations in CSS, and use some Hyperscript events (or alternatively, Javascript) to remove the modals from the DOM when the user is done. This requires you to add a minimal amount of extra markup around your modal HTML. + + +### Main Page HTML + +```html + +``` + +### Modal HTML Fragment +```html + +``` + +### Custom Stylesheet +```css +/***** MODAL DIALOG ****/ +#modal { + /* Underlay covers entire screen. */ + position: fixed; + top:0px; + bottom: 0px; + left:0px; + right:0px; + background-color:rgba(0,0,0,0.5); + z-index:1000; + + /* Flexbox centers the .modal-content vertically and horizontally */ + display:flex; + flex-direction:column; + align-items:center; + + /* Animate when opening */ + animation-name: fadeIn; + animation-duration:150ms; + animation-timing-function: ease; +} + +#modal > .modal-underlay { + /* underlay takes up the entire viewport. This is only + required if you want to click to dismiss the popup */ + position: absolute; + z-index: -1; + top:0px; + bottom:0px; + left: 0px; + right: 0px; +} + +#modal > .modal-content { + /* Position visible dialog near the top of the window */ + margin-top:10vh; + + /* Sizing for visible dialog */ + width:80%; + max-width:600px; + + /* Display properties for visible dialog*/ + border:solid 1px #999; + border-radius:8px; + box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.3); + background-color:white; + padding:20px; + + /* Animate when opening */ + animation-name:zoomIn; + animation-duration:150ms; + animation-timing-function: ease; +} + +#modal.closing { + /* Animate when closing */ + animation-name: fadeOut; + animation-duration:150ms; + animation-timing-function: ease; +} + +#modal.closing > .modal-content { + /* Aniate when closing */ + animation-name: zoomOut; + animation-duration:150ms; + animation-timing-function: ease; +} + +@keyframes fadeIn { + 0% {opacity: 0;} + 100% {opacity: 1;} +} + +@keyframes fadeOut { + 0% {opacity: 1;} + 100% {opacity: 0;} +} + +@keyframes zoomIn { + 0% {transform: scale(0.9);} + 100% {transform: scale(1);} +} + +@keyframes zoomOut { + 0% {transform: scale(1);} + 100% {transform: scale(0.9);} +} +``` + + + + + + From 55cfe09e685a2beb6cd69cf4e0cc90011a55d14d Mon Sep 17 00:00:00 2001 From: Ben Pate Date: Mon, 14 Dec 2020 21:55:19 -0700 Subject: [PATCH 2/7] Create modal-custom.md This is a demo of making a custom modal dialog from scratch --- www/examples/modal-custom.md | 247 +++++++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 www/examples/modal-custom.md diff --git a/www/examples/modal-custom.md b/www/examples/modal-custom.md new file mode 100644 index 00000000..d686d050 --- /dev/null +++ b/www/examples/modal-custom.md @@ -0,0 +1,247 @@ +--- +layout: demo_layout.njk +--- + +## Custom Modal Dialogs + +While htmx works great with dialogs built into CSS frameworks (like [Bootstrap](../modal-bootstrap) and [UIKit](../modal-uikit)), htmx also makes it easy to build modal dialogs from scratch. Here is a quick example of one way to build them. + +Click here to see a demo of the final result: + + + +### High Level Plan + +We're going to make a button that loads remote content from the server, then displays it in a modal dialog. The modal content will be added to the end of the `` element, in a div named `#modal`. + +We'll define some nice animations in CSS, and use some Hyperscript events (or alternatively, Javascript) to remove the modals from the DOM when the user is done. This requires you to add a minimal amount of extra markup around your modal HTML. + + +### Main Page HTML + +```html + +``` + +### Modal HTML Fragment +```html + +``` + +### Custom Stylesheet +```css +/***** MODAL DIALOG ****/ +#modal { + /* Underlay covers entire screen. */ + position: fixed; + top:0px; + bottom: 0px; + left:0px; + right:0px; + background-color:rgba(0,0,0,0.5); + z-index:1000; + + /* Flexbox centers the .modal-content vertically and horizontally */ + display:flex; + flex-direction:column; + align-items:center; + + /* Animate when opening */ + animation-name: fadeIn; + animation-duration:150ms; + animation-timing-function: ease; +} + +#modal > .modal-underlay { + /* underlay takes up the entire viewport. This is only + required if you want to click to dismiss the popup */ + position: absolute; + z-index: -1; + top:0px; + bottom:0px; + left: 0px; + right: 0px; +} + +#modal > .modal-content { + /* Position visible dialog near the top of the window */ + margin-top:10vh; + + /* Sizing for visible dialog */ + width:80%; + max-width:600px; + + /* Display properties for visible dialog*/ + border:solid 1px #999; + border-radius:8px; + box-shadow: 0px 0px 20px 0px rgba(0,0,0,0.3); + background-color:white; + padding:20px; + + /* Animate when opening */ + animation-name:zoomIn; + animation-duration:150ms; + animation-timing-function: ease; +} + +#modal.closing { + /* Animate when closing */ + animation-name: fadeOut; + animation-duration:150ms; + animation-timing-function: ease; +} + +#modal.closing > .modal-content { + /* Aniate when closing */ + animation-name: zoomOut; + animation-duration:150ms; + animation-timing-function: ease; +} + +@keyframes fadeIn { + 0% {opacity: 0;} + 100% {opacity: 1;} +} + +@keyframes fadeOut { + 0% {opacity: 1;} + 100% {opacity: 0;} +} + +@keyframes zoomIn { + 0% {transform: scale(0.9);} + 100% {transform: scale(1);} +} + +@keyframes zoomOut { + 0% {transform: scale(1);} + 100% {transform: scale(0.9);} +} +``` + + + + + + From efcbc2c27ff901c1b48b9110822c1ef3bffad5df Mon Sep 17 00:00:00 2001 From: Ben Pate Date: Mon, 14 Dec 2020 22:01:40 -0700 Subject: [PATCH 3/7] Update examples.md Add example to the index --- www/examples.md | 1 + 1 file changed, 1 insertion(+) diff --git a/www/examples.md b/www/examples.md index d15fb923..24138a07 100644 --- a/www/examples.md +++ b/www/examples.md @@ -25,5 +25,6 @@ You can copy and paste them and then adjust them for your needs. | [Dialogs - Browser](/examples/dialogs) | Demonstrates the prompt and confirm dialogs | [Dialogs - UIKIt](/examples/modal-uikit) | Demonstrates modal dialogs using UIKit | [Dialogs - Bootstrap](/examples/modal-bootstrap) | Demonstrates modal dialogs using Bootstrap +| [Dialogs - Custom](/examples/modal-custom) | Demonstrates modal dialogs from scratch | [File Upload](/examples/file-upload) | Demonstrates how to upload a file via ajax with a progress bar From 5f71a41cbda304abe973b1ee0ccfcd96634fd54a Mon Sep 17 00:00:00 2001 From: Ben Pate Date: Mon, 14 Dec 2020 23:20:44 -0700 Subject: [PATCH 4/7] Documentation for how to implement tabs using htmx This PR demonstrates two different ways to make tabs using htmx --- www/examples.md | 2 + www/examples/tabs-hateoas.md | 119 +++++++++++++++++++++++++++++++ www/examples/tabs-hyperscript.md | 93 ++++++++++++++++++++++++ 3 files changed, 214 insertions(+) create mode 100644 www/examples/tabs-hateoas.md create mode 100644 www/examples/tabs-hyperscript.md diff --git a/www/examples.md b/www/examples.md index d15fb923..9ba15811 100644 --- a/www/examples.md +++ b/www/examples.md @@ -25,5 +25,7 @@ You can copy and paste them and then adjust them for your needs. | [Dialogs - Browser](/examples/dialogs) | Demonstrates the prompt and confirm dialogs | [Dialogs - UIKIt](/examples/modal-uikit) | Demonstrates modal dialogs using UIKit | [Dialogs - Bootstrap](/examples/modal-bootstrap) | Demonstrates modal dialogs using Bootstrap +| [Tabs (Using HATEOAS)](/examples/tabs-hateoas) | Demonstrates how to display and select tabs using HATEOAS principles +| [Tabs (Using Hyperscript)](/examples/tabs-hyperscript) | Demonstrates how to display and select tabs using Hyperscript | [File Upload](/examples/file-upload) | Demonstrates how to upload a file via ajax with a progress bar diff --git a/www/examples/tabs-hateoas.md b/www/examples/tabs-hateoas.md new file mode 100644 index 00000000..b55ade13 --- /dev/null +++ b/www/examples/tabs-hateoas.md @@ -0,0 +1,119 @@ +--- +layout: demo_layout.njk +--- + +## Tabs (Using HATEOAS) + +This example shows how easy it is to implement tabs using htmx. Following the principle of [Hypertext As The Engine Of Application State](https://en.wikipedia.org/wiki/HATEOAS), the selected tab is a part of the application state. Therefore, to display and select tabs in your application, simply include the tab markup in the returned HTML. If this does not suit your application server design, you can also use a little bit of [Javascript to select tabs instead](../tabs-javascript). + +### Example Code (Main Page) +The main page simply includes the following HTML to load the initial tab into the DOM. +```html +
+``` + +### Example Code (Each Tab) +Subsequent tab pages display all tabs and highlight the selected one accordingly. + +```html +
+ Tab 1 + Tab 2 + Tab 3 +
+ +
+ Commodo normcore truffaut VHS duis gluten-free keffiyeh iPhone taxidermy godard ramps anim pour-over. + Pitchfork vegan mollit umami quinoa aute aliquip kinfolk eiusmod live-edge cardigan ipsum locavore. + Polaroid duis occaecat narwhal small batch food truck. + PBR&B venmo shaman small batch you probably haven't heard of them hot chicken readymade. + Enim tousled cliche woke, typewriter single-origin coffee hella culpa. + Art party readymade 90's, asymmetrical hell of fingerstache ipsum. +
+``` + +{% include demo_ui.html.liquid %} + +
+ + + + + \ No newline at end of file diff --git a/www/examples/tabs-hyperscript.md b/www/examples/tabs-hyperscript.md new file mode 100644 index 00000000..1bad1a9e --- /dev/null +++ b/www/examples/tabs-hyperscript.md @@ -0,0 +1,93 @@ +--- +layout: demo_layout.njk +--- + +## Tabs (Using Hyperscript) + +This example shows how to load tab contents using htmx, and to select the "active" tab using Javascript. This reduces some duplication by offloading some of the work of re-rendering the tab HTML from your application server to your clients' browsers. + +You may also consider [a more idiomatic approach](../tabs-hateoas) that follows the principle of [Hypertext As The Engine Of Application State](https://en.wikipedia.org/wiki/HATEOAS).. + +### Example Code + +The HTML below displays a list of tabs, with added HTMX to dynamically load each tab pane from the server. A simple [hyperscript](https://hyperscript.org) event handler uses the [`take` command](https://hyperscript.org/commands/take/) to switch the selected tab when the content is swapped into the DOM. Alternatively, this could be accomplished with a slightly longer Javascript event handler. + +```html +
+ Tab 1 + Tab 2 + Tab 3 +
+ +
+``` + +{% include demo_ui.html.liquid %} + +
+ Tab 1 + Tab 2 + Tab 3 +
+ +
+ + + + + \ No newline at end of file From 591954e72d0e5553d2bea0276fc7b726151bbb7d Mon Sep 17 00:00:00 2001 From: Ben Croker <57572400+bencroker@users.noreply.github.com> Date: Fri, 18 Dec 2020 23:00:00 +0100 Subject: [PATCH 5/7] Change how getInputValues() works --- src/htmx.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/htmx.js b/src/htmx.js index b981c89c..35d83274 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1556,12 +1556,16 @@ return (function () { function getInputValues(elt, verb) { var processed = []; - var values = {}; + var values = { + form: {}, + element: {}, + includes: {}, + }; var errors = []; // for a non-GET include the closest form if (verb !== 'get') { - processInputValue(processed, values, errors, closest(elt, 'form')); + processInputValue(processed, values.form, errors, closest(elt, 'form')); } // include the element itself @@ -1572,12 +1576,14 @@ return (function () { if (includes) { var nodes = getDocument().querySelectorAll(includes); forEach(nodes, function(node) { - processInputValue(processed, values, errors, node); + processInputValue(processed, values.includes, errors, node); }); } + var mergedValues = mergeObjects(values.includes, values.form); + mergedValues = mergeObjects(mergedValues, values.element); - return {errors:errors, values:values}; + return {errors:errors, values:mergedValues}; } function appendParam(returnStr, name, realValue) { From adc5b2a5fad8be568bc80098e5e2b1b6ca8fcd6e Mon Sep 17 00:00:00 2001 From: Ben Croker <57572400+bencroker@users.noreply.github.com> Date: Fri, 18 Dec 2020 23:04:30 +0100 Subject: [PATCH 6/7] Undo previous commit, meant to submit a PR, doh! --- src/htmx.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/htmx.js b/src/htmx.js index 35d83274..b981c89c 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1556,16 +1556,12 @@ return (function () { function getInputValues(elt, verb) { var processed = []; - var values = { - form: {}, - element: {}, - includes: {}, - }; + var values = {}; var errors = []; // for a non-GET include the closest form if (verb !== 'get') { - processInputValue(processed, values.form, errors, closest(elt, 'form')); + processInputValue(processed, values, errors, closest(elt, 'form')); } // include the element itself @@ -1576,14 +1572,12 @@ return (function () { if (includes) { var nodes = getDocument().querySelectorAll(includes); forEach(nodes, function(node) { - processInputValue(processed, values.includes, errors, node); + processInputValue(processed, values, errors, node); }); } - var mergedValues = mergeObjects(values.includes, values.form); - mergedValues = mergeObjects(mergedValues, values.element); - return {errors:errors, values:mergedValues}; + return {errors:errors, values:values}; } function appendParam(returnStr, name, realValue) { From 062a70e3e9002bdcae5627e91a2f3fadc7b0551d Mon Sep 17 00:00:00 2001 From: Ben Croker <57572400+bencroker@users.noreply.github.com> Date: Mon, 21 Dec 2020 20:09:11 +0100 Subject: [PATCH 7/7] Removed unused parameter --- src/htmx.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/htmx.js b/src/htmx.js index b981c89c..0b71f2d6 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -1419,7 +1419,7 @@ return (function () { } function restoreHistory(path) { - saveHistory(currentPathForHistory); + saveHistory(); path = path || location.pathname+location.search; triggerEvent(getDocument().body, "htmx:historyRestore", {path:path}); var cached = getCachedHistory(path);