Building app (Bun, HTMX, SQLite, ElysiaJS, and TailwindCSS) start to finish with Gemini AI help

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome to the channel today we're going to build a full application in a single video uh so we are going to use BN htx Elia GS and tailin CSS uh we also will use a bit of AI to support our JavaScript code uh to write some functions and generate test data um the final result as you can see uh that's what we aiming aiming today uh for uh it will be a simple habit Track application and all of this will be fully functional so you will be able to create new habit uh update it uh Delete if we need it and also these individual days we'll be able to mark them as completed uh all of that will will work without any client side JavaScript so we'll rely on HDMX to do IX requests for us so as you see that's the plan for today uh and as there is a lot of stuff to do let's not waste any time and let's jump into it first of all let's generate our application uh we are going to use bun uh so make sure that you have it installed if not follow instructions on official website uh but to create an app we can run B create um Elia GS as a template and let's call it just habit tracker it will install everything for us and now we can go inside and and uh open it in the editor all right so now we are inside our application let's do some changes and let's add some dependencies and we can start build uh our application so first of all let's rename this to be uh jsx um refactory name uh I'm going to put all the code inside u a single file so we probably won't need typescript support for this um okay and uh we need to add now HTML support so if we go uh to the docs for the Elia GS there is a plugin that we need uh to use let's add it here while it's installing we can copy uh this example so yeah let's put it under our root uh Handler so it will be here return want to return this and we want to use uh this use HTML and we want to add this import right so the next thing I guess is to update some jsx config yes we need this these three uh properties and you go to um TS config right and then we can scroll to the end and edit right here as the last thing like this and the final thing is to update our script uh to run in Dev mode so it was TSX and we want jsx now all right um Okay cool so now I guess we can start we can try B runev and if we go to our browser we can now open our local host and we see our hello world so we will start from here so this is our to-do list so we have done this uh we added this support and now let's add our root page uh component I created a Sim s simple snippet here for the uh root Handler let's just use this um and we can add it right here so this will be our um let's call it root Handler and we'll put it instead of this thing so it will be root Handler not a fun just a function okay so what we have here is we need to reformat this bit so where I added two uh dependencies with CDN uh so one one is for Tailwind CSS and also I included uh this additional plugin for forms support and the second one is for HDMX uh all these links you you can find on official uh websites um and yeah it's just for Simplicity we're going to use CDN links today uh but there are other options to add um to add dependencies if you want to go to production all right so let's remove this for now and let's add a simple H1 tag saying hi now it should be already reloaded and we should see it yeah like this and we see now that we have no Styles because Tailwind by default removes everything okay so the next thing is to add our root uh page uh and let's grab this component all right so we created our habits page and let's now use this page inside our main Handler habits page and we reload this and we see now our uh beautiful header here right so what we have so far we have our root Handler we have our dependencies and we have our habits page and um it just for now has this H1 um header okay and now we we're ready to build the rest of the UI so what we want to do is want uh to add um add uh button to create new habit habit and then we want to add a uh list of habits right so before we we jump into building UI I think it will be uh useful to generate some data so we from the beginning we link our application with some data in the database uh to do that we want to add a escolite support and we need this snippet uh from official docs so we can just put it right here so we will use um uh escalate in memory for Simplicity uh we don't need this uh but we are going to use this library to support simple migrations so let me uh create a new tab here and we can add this as a dependency uh so we have B isite migrations and what we want is we want to create this file in in the migrations folder so let's create a new uh folder migrations and new file add okay and after that we just want to run this inside our main file and we want to import um this two functions okay so now on on on the start um it will run and apply our migrations that we put here and we actually going to use these files to seed some test data as well let's jump into uh AI support and we can ask to um create esite uh table uh ddl uh to describe habits uh columns um ID title description and uh color uh all non null and create 10 uh inserts let's see it will if it will help us okay so let's start with this let's copy this thing put it here um I guess we can just use a primary key um in escolite so we have table habits right let's reformat that cool so what we can do next is uh we can create a simple uh function to get all habits um let's say con uh list uh all habits and it will take the database um just database I think for now and we will do uh return DB dot query and we want to put something like select all from Habits uh order by uh ID and we want all now inside our um habits page we can do something like um const habits and we do get uh select how I called it um list all habits list all habits and we pass DB and I think we can try just put it here so we want Json stringify habits just to see if it works uh properly let's jump here yep all right so now we have the list of things um in and we connected our UI with uh with database cool so now we want to create a new component uh let's say it will be habit uh component it will accept uh input will be a habit object and we will return um div it will have um let's say it will be another div here and it will have um H1 uh it will be uh Habit dot uh title and then we want to put something like P habit. description and yeah we want to style that uh so we want class um so something like um border one um rounded M there and when we get habits here now we want to uh loop through through habits so it will be uh habits map and now we have our habit and we want to return m want to return our component so it will be habit component and we want to put habit habit here let's see how that looks okay so now we have the list we can probably remove this already and we can style our uh Habit component so I always forget what are class names so let's take uh let's take a look what we have for the Border uh so border this is BD okay so border just border one pixel um border and gray something like that I think yeah all right uh we always want to add uh some spacing between them so margin button let's say five um and some padding inside okay uh so this we want I believe something like uh font bold yep and this will be um text small and we also probably want to make it a bit uh gray so let's say we want uh text Gray 700 and that's too much okay that will work for now okay so now we want here uh to add [Music] um add history of uh the habit and here we want to add add buttons to delete and edit let's start with uh with the buttons so we want div and we want it to be uh Flex with a gap Gap one let's say uh here we want a button uh let's call it edit and we want the other one with delete right okay so let's make it smaller text Sam okay uh let's add [Music] some padding uh margin let's say five and also we can probably add some sep operator between spam like this yeah that looks good to me um so we also can do something like uh edit will have the class hover um text uh Sky 700 let's say yeah and uh um same for for the delete but it will be kind of red yeah looks good to me okay and now as we we have this delete button already uh we can introduce some uh HDMX uh features and we can delete these items so to do that uh let's start with here uh we want to say that we want HX uh Delete and want um habits slash and we want to put um habit. ID here and we also can use uh htx confirm and let's say we ask uh you sure now let's open the inspector Network tab we can reload this and we can R uh click here we now have this prompt uh and now we have this request to delete it's 404 because we haven't implemented the uh Handler let's scroll into our app here and we want to start building things here so it will be a delete um path will be habits um ID it will now we can destructure params uh to get ID from perms and we want to return I think for for delete we can just return an empty body and if the status is 200 it will uh mean for HTML ma that the item was successfully deleted so yeah um here we we need a function to delete uh Habit by ID let's create it it will be const delete habit by ID want again to get database and we want the ID um and re uh we just want to do um uh DB uh dot query and the query will be uh delete from Habits uh where ID equals oops uh equals ID and we want to run that and in params we want to put our ID equals uh ID from PRS and yeah that's it so here uh let's log that um console.log uh deleting habit by ID and want uh param do ID and we want to call our function delete habit by ID database proms do ID okay so before before that will work correctly uh we want to add a Target so HX Target here will be um habit and here will be uh habit. ID and this target will mean uh on the successful response from htx request which element in your dorm to replace with the result and also HX uh swap we want it to be outer HTML so it will replace the entire node not just like the internals uh internal U nodes of that element so and now we want to to create uh our to mark this div which represents a single habit with a correct ID so it will be um habit ID if we done everything correctly I think now we have uh delete working properly let's see delete okay yes we have uh successful response and yeah I think the deletes uh deletes are working now which is cool now we can move uh to create new habit so for that we want a uh to implement a button to to create new habit right so let's create new component I think so it will be const add habit button component so want to return just this single button I think um we just want to style it so let's say we want uh full size button uh let's call it um add habit and we can now um Rand do it here before the list of of components yeah um needs a bit of styling so let's say we want uh rounded MD uh background gray something like that so hor uh Bigg PG gray um this and punning five yeah could be better but uh for Simplicity let's keep it like that uh maybe just font bold and a bit of uh spacing after button 10 maybe that's too much uh five okay should work should work for now so the idea is that when you click on this button uh it will disappear and it will return a form here that we can use as um to create a new habit right and when we click in the form to save or to cancel it will close the form it will render the button again and we'll do that with HTML X as well so now we want to add a new um a new component um to create to create uh our uh habits I think I I got this form right here just to save a bit of time because it it's cons time consuming to uh properly um uh style all these uh things but what we have here is we have our label for the input and we have uh two inputs basically one is the title input for the title and the second one is description text area um and in our create habit component uh we will use uh those two components and it will be it will be a form right um annoyingly that I need to reformat that all the time but yeah almost there and we have two buttons at the at the end uh to cancel and save almost there right so we have our form here what will have an if I reformat Corde yeah that's much better uh and let's add this fakeer library to to um generate some test data I have the PRT somewhere yeah let's do this so yeah we have our import Faker from uh Faker GS and we have our create component let's just use it uh below our button for now see how that looks okay okay so now we have this uh form so what we want to do is we want to add hm HTM x uh logic here so when we do HX uh get when we click on this uh button it will um create open a execute a Ajax call to get the form so it will be habits uh uh like create or something or form and we want to replace um HX Target we want to replace uh this component with the result and again we do HX swap outter HTML I think this is default to in a HTML but I'm usually using outer HTML in all the places so and there's an option to overwrite that as a default um later so we we can ignore we can remove all this and keep it as a default okay so now we want a new Handler for this uh habits form let's create it right here so want to get um habits form happy yeah um and we just want to return our create habit component right here return let's see if that works so now if we click here we have our uh form and the simple thing to do as well is to and to cancel it so let's say we want something like um cancel and now we want to render uh add habits component uh Habit button and we want to use this path and we want to now go to our cancel button right here and we want to on HX get on this request we want to replace our form and for that we need an ID here a new habit form now we want to replace this thing we want to use the ref with the result of the request so it will be HX swap again out HTML let's see if that works so we click here we click here we have the button back all right so now we can remove our um create habit component right here and looks much better so we open and close that now we want to implement save right so let's start with uh the back end so what we want to do is um now we want a post request to just habits here we will get body and um we want a new function to insert uh a habit so let's grab this thing will DB and habit right here um we want to uh name it uh insert habit uh the query will be insert into habits um then we want title color um title description color and values we want same but we want to add an doll sign before and also we want to return uh return the result and we do get uh in get we want to pass our title description and color and it will be habit. title um then description habit dot description and finally the color habit. color this is broken now yeah removed okay we have our insert habit now we want to use that in our uh app so here we want to call will be const habit we want to insert habit uh it will get DB and then it will be uh title uh body. title um and also description body dot description and let's say we want color here uh we just hard code something for now and then we'll create a function to generate a random color for us um so let's say uh purple so now we have this habit and when we successfully finish uh the post request um we want to return um a fragment actually and the first element in the fragment will be our add button component to render the button again but also we want to add a habit component and it will receive the Habit that we just created right yeah uh let's Also let's also log that uh so it will be creating habit cool um now we go to our form create habit component um we want to add HX post to the form itself uh just habits and uh HX swap it will be this um outer HTML HX uh Target will be this so we'll Target this form and we'll replace it with the result of of this call okay uh probably some mistake was made somewhere but uh let's see if that works so we call Save I'm not sure that works like test test save yeah and we have it right here you see so our form is now replaced by this element and this element and it's just added to the page so now we have U this add habit working the other thing is to implement edit right but yeah it will be almost the same so now we we uh basically can just grab this component to create habit and we call it um edit habit component so the ID uh we can just use something like habit uh and habit. ID uh now we will have uh Habit as an input for title we want habit do title for description we want habit. description by default um so here uh on HX get that will mean that we want to close the addit form so we want just to return um Habits by ID so let's do it like this uh Habit do ID HX Target will be this thing back tis and yeah so that that will will uh will cancel it uh how we Implement um we add we need to add bunch of of uh Roots here so one will be just to get uh get habit by ID get habits ID so here we have uh PRS and this will return habit comp uh Habit component and we want habit here so it will be const habit uh get we don't have get by ID unfortunately yet so we we need to add a new query um Bo boom yeah so we can use this um let's call it get habit by ID so we have ID B and ID so we have now where ID equals ID and we want get to return a single thing and we want our ID to be equal ID that's it let's jump to our app get habit by ID DB ps. ID and now we want to use this habit here um what we want to do also so is we do um sledit now edit uh to open the edit form it will be uh edit uh headit component and we basically getting it by ID and passing it inside this form let's see uh yeah we we haven't added this to uh to the cancel button so uh edit habit component no uh just habit component right and there is a button to open edit yeah it will be HX get um and we want to use habit. ID right here and the target will be um basically this wait a sec what's some missing oh yeah okay so like this let's reload yeah so now we have we have this form and it's opening um let's create something like test test oops test test save we now have this we click edit and we have this test and test so this is all working properly um and I think the final thing is to create this uh save uh Handler so it will be um let's jump to app we want same but it will be put so now we will have uh params to get ID and we'll have body as well right here and we want to call an update function so let's do something like this uh we will call it update habit we want want to change this to be update habits set um title equals title and uh description equals description uh where ID equals ID we don't want color here but we want to add our ID parameter habit dot ID and also as usual we want to return returning the result cool um now let's go to our application again where is our put yeah right here so we want to um update habit and yeah we want to build an object here so it will be ID equals prom. ID uh title equals body do title as it comes from the form body and description equals body uh description and again uh when we successfully update it we want to render our habit component and return it cool um let's see if if that works so want to add it here let's say test and test and save it yeah and it works but for some reason we have our button twice so we made a mistake somewhere uh test one test one save interesting I think it's calling the wrong uh end point for some reason Let's see we have our edit habits component oh yeah so it's post here still so we we need to update here to be put and this will now become habits um habit. ID like this um we do edit test test save interesting so the tiny uh problem was actually in this uh SQL query so for update it's not and you just add a comma here um really easy to make a mistake but now everything is working we can remove our logs and if we reload this thing we do edit and we do something one two three save and we have everything back correctly so yeah we have our uh kind of crowd application for the Habit entity itself uh now we want to add this days history um let's go to our habit component and we can um we can create a new component saying that it's a habit a history item something like that um and we want to return uh a div maybe a span like yeah let's do a def for now see let's see if that works so we want to have a class something like um five and hate five so they are like squares one them rounded and we want them inside a div with flex so the class will be flex and GAP one and here we want our habit uh history item multiple of those um yeah we want we want it to be uh P purple something like this for now yeah we have this our nice elements let's go to Ai and we will ask to uh create uh JavaScript function to generate a sequence of dates starting from today and going back 90 days let's say n days and for each um element calculate completed flag that could be uh that will be Boolean that should be 30% true uh false 30% true let's see if that works come on all right yeah so we create dates in the history and then we randomly add Flags yeah looks good um let's just grab this put it somewhere here here uh let's just do a div and we want Json uh generate how it's called habit data yeah okay data 90 days yeah okay so we have this list and we can use that to um to map over and create our habits history item let's say we want uh Habit history we now want this generate habit data right here 90 dat looks good um we want to map here now map um habit history and we want to map history like just day and we want to return return our habit history item let's remove this yeah so we want uh Flex um I don't remember actually it's like flax W um no r nope wait a sec Flex wrap yep nice want to pass here our habit habit and we want to pass here our um habit history probably yeah D now if we go here we want to rest structure that it will be habit and habit history and here we will need a uh this function for class names let's just add it and why we need that is uh we want to do something like uh class names we want now this to be as our base class but also we want to add an optional class let's say we want want um we want background purple if uh Habit history habit history um completed purple and if not we want a default background um gray if not completed let's see oh yeah so we we need to remove this from here right yeah okay so now we have this random random dates um that's good the other thing we want is we want to get this um want to get this from from The Habit itself so we want to do something like um so we can also add a title right first of all so title will be um just habit history date now on H we have this date and we also need to reverse that but yeah we can we can do that later um I always forget the syntax but I think it's something like you put it brackets and then you do this right and here we can now do something like this uh it will be habit dot color yeah but um we need to add cor colors here so let's say we have Sky we have purple green um orange T um red pink green what else we have I have some list some somewhere um yeah let's do [Music] emerald and what else here we need to reload reload this yeah okay so this is this is nice the last thing to build is when you click on the element here it will toggle toggle it to different state so you can Mark and unmark your your dates let's create a new entity in in our database so I should have it somewhere here yeah table history let's set it right here so we have our habit ID and date and if we if we have um if we um insert a value in this table it will mean that this date is completed if we delete this element it will be removed right could be improved but it should be fine for now so um what we want to do is we want to add we want to add an HX HX HX post and what we want is [Music] um habit like want habits um then ID habit do ID and we can just for now say like toggle so it will use database state to understand if if if we need to remove it or if we need to insert it right so uh HX uh Target will be this and HX swap again will be Al HTML now we want to grab this thing and go to Our Roots let's put it somewhere at the end so it will be post oops this and we want params here uh we want to return uh Habit history item so we will need to get our uh Habit first get habit by ID DB promps do ID and uh what else so we'll return this thing oops it will receive habit and habit history habit so here we want to do something like uh check if um habit history element is in DB uh deleted else insert inserted it's pretty stupid logic so it could be improved uh significantly but yeah for now should work right and also we want probably we want um date here as well so it will be um date and this will be ID so we want const uh Habit history so now we want to get habit history get habit history it will have ID and date so I want to select from Habits history where ID um where habit habit ID equals ID and uh date equals date here we want to pass um date date and also we want to have a same function but for insert where we have it yeah so so it will be insert habit history same ID and date insert into habits history uh Habit ID and date and values will be habit um say ID and date don't need color and we'll get the same input like this yep um moving to our app we now want to get habit history uh DB params do ID params do date and then if um habit history is null we want to insert habit history and uh we want to do in DB basically same PRS else we want and again we need an extra function delete habit history delete from Habits history where habit ID equals ID and date equals date okay so now we do this delete here delete habits history DB again same same input and let's just create a simple object uh it will be habits history result updated end of the video and code gets a bit ugly but yeah we can we can refact to that if we need so habit history will be now uh date date uh PRS date and the completed flag will be um habits history so if it was null here we we insert it so now it means that it's completed so a bit annoying but yeah it probably will work let's update yeah and we we now want to add this to be um habit history history item want this to have uh Habit history. date and also umore pointer let's check our Network okay undefined date is undefined so when we return the function from the HTML snippet from the [Music] um from right here we don't have date there date okay typle right so we just made a typo here it should be completed right now if we go here reload this thing we can do this and it's all working yep I think that leads us to the end of the video um I think it was uh pretty useful uh I hope you learned something if you enjoyed the video don't forget to like subscribe uh leave comments and also there are multiple ways to support the channel and all the links are in the description thanks a lot for watching see you next video bye-bye
Info
Channel: Andrey Fadeev
Views: 1,928
Rating: undefined out of 5
Keywords: #clojure #bun #htmx #software
Id: zOOd9Dde_vM
Channel Id: undefined
Length: 67min 28sec (4048 seconds)
Published: Sat Feb 17 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.