[1s] welcome everybody to another edition of [3s] the [4s] larval worldwide meetup i got uh [7s] two gifts for you like always uh in half [10s] an hour [11s] uh robin malfey will join us to talk [13s] about [14s] headless deal with ui but first i have [17s] with me [18s] uh tom witowski who is going to [22s] talk a little bit about a new project [23s] that he recently [25s] launched hey tom how are you doing hello [28s] i'm fine thank you so much for [31s] yeah also also fine and have grabbed [34s] some [34s] some beverages i hope so too i saw [38s] already [38s] some people in the chatroom that were [40s] looking forward to your talk [42s] so that's already good [45s] um so i saw you [48s] launch a uh i think i think it's a side [51s] project [52s] together with um um [58s] on just met yeah with matt stafford [1m] sorry i [1m 1s] i i saw his friendly face before you but [1m 3s] it's matt with what was his last name [1m 5s] matt stafford of course [1m 7s] uh you launched a side project with him [1m 9s] uh [1m 10s] open door without me and i guess we're [1m 13s] going to see [1m 15s] all about that in your talk right [1m 18s] yeah not all because half an hour is [1m 22s] far too less to talk about all of it but [1m 25s] i will [1m 26s] once quickly run through some [1m 30s] some important parts of it yeah cool [1m 33s] so if you're ready then the stage is [1m 36s] yours [1m 36s] i'll share your screen and then you're [1m 39s] good to go [1m 41s] so first of all for all who haven't seen [1m 45s] opener this is it and it's a [1m 49s] tool website platform however you name [1m 51s] it to [1m 52s] make it easier showcasing your [1m 55s] yeah your open source contributions so [1m 59s] there's a start page and [2m 2s] on the profile we have indexed [2m 6s] a lot of github and connected with your [2m 10s] profile [2m 10s] so you can quickly show that you're [2m 13s] doing php [2m 14s] javascript html and whatever so on [2m 17s] and in a way set is important for me to [2m 20s] set [2m 21s] recruiters and or other people since the [2m 23s] hiring process can understand [2m 25s] because we all know github is cool for [2m 28s] version control but [2m 30s] it's not so cool to showcase any [2m 33s] recruiting related resume cv [2m 37s] things so that's a quick [2m 41s] run through what open me is and now to [2m 44s] the code [2m 46s] um first of all what open me makes yeah [2m 50s] somehow special is [2m 51s] said i would say around 90 of the [2m 54s] application is made in the queue [2m 57s] so right now i'm processing around [2m 59s] nearly half a million q jobs per day [3m 2s] and this was only not even 300 [3m 6s] registered users and [3m 8s] four thousand repositories so you [3m 11s] get a feeling uh how many jobs uh run [3m 14s] through [3m 15s] the secured and yeah [3m 19s] i've learned a lot of things during this [3m 21s] to optimize my queue [3m 22s] and yeah makes this happen [3m 26s] so that your server can run so many jobs [3m 29s] and first of all this is a base job i've [3m 32s] implemented i think [3m 34s] uh most of the top part is [3m 37s] known by nearly everyone here because [3m 39s] this is what [3m 40s] laravel generates if you run artisan [3m 41s] make job [3m 43s] and yeah these are uh [3m 46s] a collection i would say of uh of the [3m 49s] documentation [3m 50s] so you won't really find these [3m 53s] properties [3m 54s] somewhere in source code you also don't [3m 56s] get all the completion for it [3m 58s] because this is all done with if [4m] property exists and so on so [4m 2s] yeah you have to collect them on your [4m 4s] own and first of all it says delete when [4m 6s] missing models [4m 8s] so it's important if you have a job set [4m 11s] is based on a model so for example if [4m 14s] you want to [4m 15s] index your [4m 18s] a user you have a reference to the user [4m 21s] model [4m 22s] and [4m 26s] quickly [4m 28s] i have i will zoom in a little bit more [4m 32s] cool i was just going to ask you that [4m 36s] thanks some people are watching on [4m 39s] mobile devices [4m 40s] and on big tv so you have to accommodate [4m 43s] for them too [4m 45s] yeah that's already uh so yeah [4m 48s] i guess that's good okay so [4m 52s] uh yeah and lower does all this model [4m 56s] resolving and serializing with the [4m 58s] serial racist model straight [4m 59s] and by default a cue job fails if the [5m 2s] model [5m 3s] is deleted between the dispatch and [5m 6s] running the queue job [5m 7s] so if you dispatch for example is a [5m 10s] job right after registration and the [5m 13s] user is super fast and the queue [5m 14s] is also slow and the user was able to [5m 17s] delete his account because your job [5m 19s] was able to run your q job would throw [5m 23s] i think it's a model not found exception [5m 26s] and it's also flagged as failed [5m 28s] which probably isn't what you want so [5m 31s] you can set this delete when missing [5m 32s] models to true [5m 34s] which just means uh ignore and delete [5m 36s] this cute job as is [5m 38s] it would never have existed if any of [5m 41s] the models doesn't exist anymore [5m 44s] next one is a timeout for most [5m 47s] use cases applications this isn't really [5m 50s] a thing [5m 51s] i think um but [5m 54s] what it does is uh by default a cute job [5m 58s] timeouts after five minutes if i'm not [6m 1s] wrong [6m 2s] so if your job takes longer than five [6m 4s] minutes for example if you import a [6m 5s] large csv file [6m 7s] and it takes 10 minutes half an hour [6m 9s] whatever [6m 10s] yeah it will time out and means that [6m 12s] your job is never able to [6m 14s] uh yeah to complete and will always fail [6m 18s] so you can increase this timeout to [6m 21s] where you said matches your requirements [6m 25s] and next one is a trice [6m 28s] this is important if you want if you [6m 30s] know that your job can fail [6m 32s] but you want to retry it because uh [6m 35s] it can fail because the third party [6m 38s] service for example isn't available and [6m 39s] you want to retry it half an hour later [6m 42s] so you can say how often do you want to [6m 44s] retry tries [6m 46s] is one two three and so on so an integer [6m 49s] and you say how many times you [6m 52s] retrace this job the next one sounds [6m 56s] a bit similar nearly the same like the [6m 59s] trice one but [7m] it's slightly different you can [7m 3s] retry a job without having it failed in [7m 7s] the first place [7m 8s] so if your job really fails with an [7m 12s] exception [7m 14s] it will retry if you say so and the max [7m 17s] exceptions will increment [7m 19s] uh but you can also retry a job without [7m 22s] having it failed [7m 22s] with explicit call to retried for [7m 25s] example [7m 26s] and so in this case this [7m 29s] is just another counter you can set so [7m 32s] you can say for example i want to [7m 33s] recreate five times [7m 35s] but after two exception i want to uh [7m 37s] don't retry anymore [7m 38s] because two exceptions means there is [7m 40s] something really wrong and [7m 42s] yeah this is just a quick helper method [7m 46s] for me [7m 46s] and yeah this one is [7m 50s] another version to retry to define how [7m 53s] many times you want to retry your job [7m 55s] by defining a date time until [7m 59s] when you want to retry it so [8m 2s] you have dispatch your job it starts to [8m 4s] run and [8m 5s] now you say okay retry it for one day [8m 8s] for example [8m 9s] and in this case it's not important if [8m 12s] it runs one time [8m 13s] 10 times or a million times whatever [8m 16s] your queue [8m 17s] is possible but [8m 21s] it just runs until this exact date time [8m 24s] moment [8m 26s] yeah and now to my next [8m 31s] more precise abstract job this is a [8m 34s] github job so it handles all the github [8m 36s] api things [8m 38s] and here you can see [8m 42s] that i have said okay you can reach [8m 43s] right three times but after one [8m 45s] exception you have to fail immediately [8m 47s] and i've also defined a timeout of one [8m 50s] minute [8m 52s] for all of you who don't know the carbon [8m 55s] interval is a [8m 56s] amazing tool to define readable [9m] uh periods of time so you can also [9m 4s] uh add an hour here for example and so [9m 8s] on so this is a super readable version [9m 11s] of [9m 12s] creating uh periods and you also get [9m 16s] i know in which units this [9m 20s] result integer is used in this case we [9m 23s] are using seconds [9m 24s] but there are also places in the lateral [9m 26s] codebase which uses [9m 28s] minutes for example or even hours or [9m 30s] whatever [9m 31s] so this is a cool way to make it [9m 34s] readable [9m 36s] and yeah [9m 39s] this is my abstract handle method so you [9m 41s] can see that i have defined some [9m 46s] standard things to do with all make it [9m 49s] up job so if it's a badge and the batch [9m 51s] is cancelled [9m 52s] i have to return if the entity [9m 55s] entity always returns this single model [9m 58s] my job is about so [9m 59s] repository user organization if this one [10m 3s] is blocked [10m 4s] i will delete the job immediately and [10m 8s] yeah the real logic i've put in this run [10m 11s] method [10m 12s] and here i have some explicit [10m 16s] exception handling and this is also [10m 18s] something important i've learned that [10m 20s] you should handle exceptions you know [10m 24s] that could happen in an explicit way in [10m 27s] your [10m 28s] in your jobs because this in first place [10m 31s] means okay you [10m 33s] know that's exception can happen and you [10m 35s] have also defined [10m 36s] a real behavior how to handle it so [10m 41s] sorry i have to close the window [10m 50s] super sorry for this interruption and [10m 55s] yeah you have to handle this exception [10m 58s] and [11m] in most cases for example this is a [11m 2s] client exception this is part of the [11m 4s] castle library [11m 5s] you don't want to really throw it to the [11m 8s] exception handler [11m 9s] but you want to define some other logic [11m 12s] for example if you get an [11m 14s] forbidden or not found exception you [11m 16s] want to do some things with your local [11m 17s] models for example [11m 19s] or if it's a rate limit exception i have [11m 22s] this method here [11m 23s] uh if this is a rate limit exceptions a [11m 27s] c3 requirements identify [11m 30s] a github rate limit response [11m 34s] i want to retry the job in [11m 38s] the amount of seconds rate limit is [11m 40s] reset [11m 41s] so this is also a way to handle it [11m 45s] yeah and only if it's an exception i [11m 47s] haven't handled [11m 49s] or i don't know about i [11m 52s] really throw the exception [11m 55s] yeah and i think it was with laurel [12m] 8. [12m 4s] lara introduced should be unique [12m 8s] interface [12m 9s] and this uses this unique id [12m 12s] for example method which defines [12m 15s] an identifier for the job set [12m 18s] can only be present in the queue [12m 22s] one time so [12m 28s] i have this raise or for a user in this [12m 31s] case it will be user [12m 33s] column 14 for example as [12m 37s] unique identifier and [12m 40s] if i would dispatch the same job with [12m 42s] the same user [12m 43s] 10 times in a row it would only add and [12m 46s] process [12m 47s] at one time so so something [12m 50s] also good to keep your q clean [12m 54s] and don't uh yeah [12m 57s] don't mess around with user and actions [12m 59s] for example so if a user [13m] is kind of malicious and clicks this [13m 3s] dispatch any job button [13m 6s] like an idiot 100 times in a row [13m 9s] it will only be in the queue for one [13m 11s] time [13m 12s] and tags is something for the horizon [13m 16s] which i really recommend to you to use [13m 19s] for [13m 19s] processing cues so yeah it is what it [13m 22s] says it takes to [13m 24s] quickly find jobs by some model for [13m 28s] example or any other label [13m 31s] back off is a method [13m 34s] that defines a strategy to [13m 38s] uh yeah to slowly increments the wait [13m 42s] time between retries [13m 44s] so the first job fails it waits one [13m 47s] minute [13m 49s] to retry the job after the second job [13m 51s] fails it will be [13m 52s] wait 5 minutes 10 minutes 15 adds on [13m 56s] and this is [14m] in first place good for you if you [14m 3s] depend on a third-party service because [14m 5s] most times uh curl exception for example [14m 9s] or a short down time only takes some [14m 12s] seconds and most times [14m 14s] and so it's quickly up again and it also [14m 17s] prevents you from having [14m 19s] a single job uh [14m 22s] blocking your whole cue because it's [14m 24s] retract retry retract really try it and [14m 26s] so on [14m 27s] uh it will be uh [14m 30s] run wait a minute so you have one minute [14m 33s] to process all [14m 34s] other jobs or at least uh part of it [14m 37s] after this it will wait five minutes so [14m 39s] you now have five minutes to process [14m 41s] other jobs and so on so you prevent [14m 44s] one blocky malicious [14m 48s] whatever job from blocking your whole [14m 50s] cue [14m 52s] and the next one is [14m 56s] this specific job [14m 59s] like some namesakes load repositories [15m 2s] it loads all contributors for one [15m 4s] repository [15m 6s] and this can be really a lot uh during [15m 9s] development i found one repository with [15m 11s] over 25 000 contributors [15m 15s] uh to comparison i think laravel [15m 18s] framework has only [15m 21s] three thousand or five thousand um [15m 25s] yeah and per page i get [15m 28s] 100 contributors so you [15m 32s] know you can calculate how many requests [15m 33s] i have to do only to get all the [15m 36s] contributors and this can really take [15m 39s] some time [15m 40s] but for me even more time was required [15m 42s] to resolve the contributors because of [15m 44s] some [15m 45s] internal logic a user can have multiple [15m 47s] email addresses i have to compare [15m 49s] uh you have css and on here so github [15m 52s] only returns to fi [15m 54s] first 500 contributors as full user [15m 56s] objects [15m 58s] all other contributors are returned as [16m] like you get by git log [16m 2s] only the name and the email address so [16m 5s] no you now have to match by email [16m 7s] address with your own database [16m 9s] and because a user can have multiple [16m 11s] email addresses i have to compare with [16m 12s] multiple strings and [16m 14s] so on and before this was done php site [16m 17s] with a [16m 18s] collection and lazy collection and going [16m 21s] through it finds first one matching and [16m 23s] so on [16m 23s] and this is really slow uh because [16m 26s] if you have a loop with 25 000 [16m 29s] iterations if you only take [16m 31s] like 10 milliseconds more [16m 35s] with 25 per iteration with 25 000 [16m 38s] iterations this is [16m 40s] now 250 000 milliseconds which is [16m 43s] 250 seconds which is around [16m 46s] two minutes already so you see how [16m 50s] very small optimizations inside the loop [16m 54s] can [16m 56s] make your job in minutes or even hours [16m 58s] faster [16m 59s] so for comparison this job before the [17m 2s] refactoring to a batch [17m 4s] which i will quickly talk in a minute [17m 7s] uh this job took around six hours and [17m 10s] failed after it because of the timeout [17m 12s] image i've mentioned before [17m 13s] and now it's finished with also [17m 17s] batch sub jobs in yeah kind of [17m 20s] 30 minutes so half an hour and [17m 24s] yeah at first it all does also request [17m 28s] to the api [17m 28s] get always 100 contributors and [17m 32s] this patches one job per contributor to [17m 35s] the same batch [17m 36s] so this job uses a github batches [17m 39s] for all of you who don't know it's one [17m 41s] way to group [17m 42s] multiple jobs in one yeah [17m 46s] batch which has a unique identifier and [17m 49s] also [17m 49s] can calculate some process so if you [17m 52s] would show [17m 53s] this in the front and somewhere you can [17m 54s] show a progress bar which will [17m 56s] slowly increment and [18m] yeah so it's a cool way to do [18m 3s] this kind of uh processing it's also a [18m 6s] cool way if you [18m 7s] have a csv import for example and [18m 11s] processing of the single lines takes [18m 13s] longer than [18m 14s] reading the whole file itself so you can [18m 17s] dispatch one job for each line [18m 19s] and you can also benefit in this case [18m 22s] from your [18m 23s] key workers because most instant app [18m 25s] instas will [18m 26s] spawn like 10 or 15 20 [18m 30s] or however your setup server is uh [18m 33s] q workers so if you dispatch hundred [18m 37s] drops at the same time with 10 key [18m 39s] workers which is in my [18m 40s] case as a production amount [18m 44s] it will process get processed 10 times [18m 46s] faster [18m 47s] so yeah and [18m 53s] since at repository contributor gets a [18m 56s] repository it has to add the contributor [18m 58s] to [18m 59s] and the contributor data and [19m 3s] here you see this [19m 6s] difference of real user objects and the [19m 9s] anonymous user objects how github names [19m 11s] it [19m 12s] and yeah [19m 17s] for all of you who want to check out the [19m 19s] real code it's [19m 20s] public on github estrodom astrotomic or [19m 23s] pandorami [19m 24s] and yeah you can check it out so [19m 27s] some other stuff i've already seen it in [19m 31s] the questions [19m 32s] is some some macros i've [19m 36s] added so [19m 39s] especially use the github one i know [19m 42s] there are a lot of packages to uh which [19m 45s] provide [19m 46s] php github api so s1 by [19m 50s] graham campbell and also a base [19m 54s] plain php one but for me the important [19m 57s] part is [19m 59s] during this authorization uh kind of [20m 2s] stuff and setting up the general client [20m 4s] and i don't need a specific method per [20m 7s] endpoint so i don't [20m 9s] have to do github method user method [20m 12s] show or whatever [20m 14s] it is i'm totally fine with [20m 18s] providing surreal paths after this api [20m 22s] github.com [20m 23s] so this macro pro generates a [20m 26s] pending request for me which is prepared [20m 30s] with [20m 30s] all the basic stuff so it sets the space [20m 33s] area l [20m 34s] it's it's uh accepted content type [20m 37s] which is here vnd github version three [20m 41s] json and it also generates a user agent [20m 44s] for me [20m 45s] it says that i want to throw real [20m 48s] exceptions if there's an error [20m 50s] i apply it to middlewares here so the [20m 52s] cache middleware will [20m 54s] handle this e-tag and [20m 57s] cache stuff so it acts [21m] similar like a browser if you do the [21m 2s] same request some [21m 3s] multiple times it will load the response [21m 6s] from [21m 7s] from redis in this case and don't do the [21m 10s] read request [21m 11s] so i will save some [21m 13s] [Music] [21m 15s] some api calls for the rate limit and [21m 18s] the second one here [21m 20s] is some special handling for [21m 23s] my local database so if [21m 28s] there's some guzzle stuff and if the [21m 30s] response is unauthorized [21m 33s] i will get the bro token [21m 36s] from the authorization header and [21m 39s] search for user which has this beer [21m 42s] token as github access token defined [21m 45s] and will anonymize this user in this [21m 50s] case so reset it to the default github [21m 52s] no reply email address and unset all the [21m 55s] profile details because this means [21m 58s] that the user has deleted the or pandami [22m 2s] application from his github profile [22m 6s] and we aren't allowed to access [22m 9s] his github data anymore so i will also [22m 13s] reset that anonymizes profile [22m 16s] yeah and it will also [22m 19s] set a random github access token from [22m 22s] the database [22m 24s] and this is only important for one case [22m 26s] and all other cases this is [22m 28s] overwritten on the later point so [22m 32s] on the user model for example i have [22m 34s] this github method [22m 36s] here and it's the user has a github [22m 40s] token [22m 40s] it will call http github and overwrite [22m 43s] the token in this case [22m 44s] and if it doesn't have one this is the [22m 47s] only case [22m 48s] it returns the default github with a [22m 51s] random access token [22m 53s] and to [22m 57s] quickly find one point [23m] we are using this [23m 6s] so this is how it looks like if i want [23m 8s] to call the github api [23m 10s] i have this github this user model calls [23m 12s] a github method to get suspending [23m 14s] request [23m 15s] and do a get request in this case to [23m 19s] use us the username and box to retrieve [23m 22s] all [23m 22s] the public organizations to use as [23m 24s] member of [23m 26s] and [23m 30s] now some stuff around the [23m 34s] yeah let's say hosting infrastructure [23m 37s] however you want to name it so [23m 41s] uh open me runs on a total of four [23m 44s] servers [23m 45s] one two web servers [23m 49s] and one database and reddit server and [23m 52s] one keyworker server so [23m 58s] if or better [24m 1s] i can spread all the load and if the [24m 4s] queue for example goes crazy which [24m 7s] happens [24m 8s] like three times a day [24m 11s] the resources for the web server aren't [24m 14s] blocked [24m 14s] and it's still working and [24m 19s] yeah this is my scheduler and in general [24m 22s] hosting [24m 22s] an application on multiple servers isn't [24m 24s] this [24m 25s] complicated so i thought it's more [24m 29s] work to do after reading some stories on [24m 32s] twitter for example and it's [24m 37s] kind of not this much you have to adjust [24m 40s] so [24m 41s] one thing i had to do is for most [24m 43s] schedules tasks [24m 44s] calling this on one server so [24m 48s] this will create a mutex versus command [24m 51s] and [24m 52s] storage and redis so also important that [24m 54s] you have one [24m 56s] redis instance for all applications and [24m 58s] not one per [24m 59s] instance and this just prevents [25m 2s] if you have three servers running the [25m 4s] scheduler uh [25m 6s] doing the same job three times which [25m 8s] will be useless [25m 10s] and yeah like you can see i have this on [25m 14s] one server [25m 15s] all the time here says one command [25m 18s] uh i also limit to the environment so i [25m 20s] have the [25m 22s] app env variable defined per server so i [25m 25s] don't use this production [25m 27s] like you can see here i use the host [25m 28s] names generated by a laravel forge [25m 31s] and since george's mune [25m 34s] in this case is a keyworker so [25m 38s] i run this command and this one also [25m 42s] only on secure server and [25m 47s] yeah here down the space here love [25m 50s] back on backup commands i run on all [25m 52s] servers so [25m 54s] i get a backup of all three application [25m 56s] servers because i [25m 58s] don't only back up the database [26m 1s] and i also add some files [26m 5s] uh from the application so some storage [26m 7s] files uh [26m 8s] env file and so on and [26m 14s] this was the most important change i had [26m 16s] to do [26m 17s] to make it work and yeah [26m 20s] some more things you have to adjust is [26m 22s] for sure [26m 24s] the database for example or primary not [26m 27s] really in the config but in your env [26m 29s] not using uh 127.001 [26m 35s] or localized whatever but the network [26m 38s] ip address of your database server [26m 43s] and i can really recommend to use [26m 45s] private networks for this so you can use [26m 47s] a ip address like [26m 50s] and zero zero five for example [26m 55s] and don't have to use the full public ip [26m 58s] and this means that you can also close [27m 1s] and [27m 2s] hide the database server from the public [27m 6s] and yeah [27m 9s] that's nearly everything i had to adjust [27m 13s] or really keep in mind [27m 18s] i had to do and [27m 21s] yeah so there's also the most also [27m 24s] special stuff i have to say about [27m 26s] appendemi and [27m 29s] are there any questions otherwise i'm [27m 32s] kind of ready and i know that i have [27m 35s] talked pretty fast because i had to [27m 38s] do also stuff in less than half an hour [27m 41s] pretty cool tom um [27m 46s] people can contribute to uh open door [27m 49s] right [27m 51s] are there any contributions you're still [27m 53s] looking for are there [27m 54s] is there any low-hanging fruits that [27m 58s] newcomers to open source maybe can can [28m] handle for you [28m 3s] [Music] [28m 4s] so i definitely have [28m 7s] not a lot but some issues [28m 13s] so uh [28m 16s] i think this one is done already but [28m 20s] yeah here for example at uh registered [28m 22s] at timestamps so not only is it created [28m 24s] an updated one but also [28m 26s] just that add timestamp to the database [28m 28s] and the user model [28m 30s] using the link header from the github [28m 33s] api responses for pagination [28m 35s] so right now [28m 37s] [Music] [28m 39s] i'm doing this where is it [28m 44s] yes this paginated uses this [28m 47s] old uh old hacky wake of [28m 51s] if the count is more or equal the amount [28m 54s] i expected [28m 55s] let's request another time and [28m 58s] yeah so there are definitely some issues [29m 1s] here [29m 3s] i also always welcome some [29m 6s] own ideas we also have discussions [29m 10s] so you can add your own ideas discuss [29m 13s] them with [29m 14s] us like you can see there are a lot of [29m 16s] ideas [29m 17s] and you can also take on one of these [29m 20s] ideas [29m 21s] and best case don't start right away but [29m 24s] at a comment like i would i would want [29m 27s] to work on this [29m 28s] uh are there any special things i have [29m 30s] to keep in mind or whatever [29m 32s] uh this prevents all of us from [29m 35s] rejecting [29m 36s] any pull requests [29m 39s] yeah what is the thing that you're [29m 42s] working on yourself now for for open [29m 45s] door [29m 46s] i have to be honest i haven't done much [29m 49s] during the last two weeks i have uh done [29m 54s] one release today or yesterday [29m 57s] here today adding some [30m 1s] missing languages and license [30m 4s] doing some filament optimization so in [30m 7s] the back office for filament for example [30m 9s] we also [30m 12s] yeah could need some help to make it [30m 15s] more usable for me [30m 19s] and yeah also a quick fix so here for [30m 22s] example [30m 23s] uh after contribution were added to [30m 27s] a user we haven't touched the user model [30m 29s] which means that [30m 30s] it wasn't re-indexed in the algolia [30m 33s] search [30m 34s] yeah and yeah this was a quick fix [30m 38s] so there's definitely a lot [30m 41s] possible to do and yeah i'm always [30m 45s] happy to retrieve any contributions [30m 51s] cool tom i it's nice to see that that [30m 53s] that you're [30m 54s] yeah using the power of laravel's [30m 56s] queuing system [30m 57s] at its full extent there so that's uh [30m 59s] yeah pretty cool to see [31m 1s] and i also like the http macros uh [31m 5s] i knew the those were there but it was [31m 7s] already on the back of my mind it was [31m 9s] good to get a refresher [31m 10s] that that existed pretty cool that you [31m 12s] leveraged that too [31m 14s] so for me as http here is now a full [31m 18s] replacement for all these [31m 20s] uh api wrapping [31m 23s] packages for example github api for [31m 26s] primary because [31m 27s] it makes it a lot easier to test [31m 30s] because you can i have to find it [31m 34s] somewhere here yeah so this is http [31m 38s] fake and in this case for example i [31m 42s] have fixture json files on the same path [31m 46s] as api here and i think you could also [31m 49s] do this in a [31m 51s] more dynamic function but at all it [31m 54s] makes it a lot easier to [31m 55s] fix the responses for testing stuff so [31m 59s] with real castle you would have to mock [32m 2s] and also things [32m 5s] yeah it's a pain this is much better for [32m 8s] sure [32m 10s] okay tom uh yeah i guess [32m 14s] uh we're watching the question by alex [32m 17s] yes uh i i have to say is that i have [32m 21s] increased [32m 25s] the database server today so i'm using [32m 27s] headset cloud [32m 29s] and now [32m 32s] the database server runs on a cpx [32m 35s] 31 so 8 gigabytes of ram and for [32m 39s] cores with amd which has some [32m 42s] i like 100 megahertz more of processing [32m 45s] power per core or something like this [32m 48s] and yeah i had to do this because uh [32m 50s] before four gigabyte ram machine [32m 53s] run out of memory so [32m 56s] red is with half a million jobs per day [32m 59s] is pretty resource hungry and [33m 3s] i had problems that my whole swap was [33m 7s] 98 filled and my ram was also [33m 11s] around 95 used which resulted in [33m 14s] a lot of redis exceptions like redis [33m 16s] wasn't able to write to disk [33m 18s] so persisting stuff and redis was just [33m 21s] not reachable for some seconds so [33m 25s] if i check my my ping ping up time here [33m 29s] you see this the last three days [33m 33s] i had a lot of these was down for [33m 36s] two minutes two minutes yeah [33m 39s] so this was a reason to upgrade as uh [33m 42s] web servers are running uh i think the [33m 45s] cpx 11 [33m 46s] so or even as a cx11 so [33m 50s] so that part of level is a super boring [33m 53s] stuff so [33m 54s] you don't need anything php a single [33m 56s] core so [33m 58s] also no need for a lot of course and [34m 1s] secure server runs of the cpx [34m 4s] 21 so three cars and four gigabytes of [34m 6s] ram [34m 8s] which is enough in my case to process [34m 10s] around 10 [34m 11s] 000 jobs per minute with 10 workers [34m 18s] yeah cool stuff man i [34m 21s] uh it's it's pretty nice to see that [34m 24s] the load is handled pretty pretty good [34m 27s] uh [34m 27s] and yeah sure you need enough memory if [34m 30s] you have [34m 31s] uh that that number of jobs uh [34m 34s] that is going through the system uh yeah [34m 37s] for me it's the first time i am working [34m 40s] on a project on [34m 41s] onsite scale so before i never had to [34m 45s] care about q [34m 46s] optimization for example because q did [34m 48s] some [34m 50s] sms or email stuff or uh [34m 53s] calculated like two integers which took [34m 56s] like [34m 57s] 10 seconds in in worst case so there was [35m 1s] nearly nothing on the queue [35m 3s] and yeah now i get some real load on the [35m 7s] application [35m 8s] and i have to do some stuff i never had [35m 12s] to do [35m 12s] before yeah i'm pretty good that [35m 14s] knowledge will come in handy for [35m 16s] like the next project that you need to [35m 18s] do where a lot of traffic is [35m 20s] uh is being handled okay tom that's uh i [35m 24s] think all that [35m 25s] that we have time for so yeah thanks [35m 28s] again for [35m 29s] for coming on uh the stream um yeah i [35m 32s] really like the project i've said that [35m 34s] uh [35m 34s] already and yeah i hope you get some uh [35m 37s] some nice contributions uh [35m 40s] uh soon and for all just create your [35m 43s] profile uh primary maintainers [35m 46s] because we can only index repositories [35m 48s] by riches that users [35m 50s] so yeah if you maintain some [35m 52s] repositories uh it takes like five [35m 54s] seconds [35m 55s] wizard append me clicks sign in button [35m 59s] here and you are done you can already [36m 1s] leave we will do [36m 2s] all the other stuff for you so everybody [36m 6s] go and do that [36m 7s] now and yeah make use of of cues [36m 11s] of tom's uh hardware setup [36m 14s] make ready sweat again [36m 18s] yeah and for all yeah you see [36m 22s] oh yeah that's that's a big number [36m 26s] and so fail jobs is primary because of [36m 27s] this radius instance [36m 29s] going crazy so normally this is down to [36m 32s] zero [36m 36s] okay cool um we're going to head for the [36m 40s] break now [36m 41s] uh thanks again for uh for doing this [36m 44s] talk [36m 44s] and yeah i'll speak to you soon bye man [36m 47s] see you oh [36m 51s] okay we are going to do a five minute [36m 54s] break [36m 55s] and after the break herben is going to [36m 58s] join us to show us some [36m 59s] headless tailwind ui stuff stick around [37m 2s] and see you [37m 3s] in five minutes [40m 48s] okay everybody welcome back i hope that [40m 51s] you [40m 51s] enjoyed that little break um [40m 55s] i think we are ready for our next talk [40m 58s] i have here with me let me bring him on [41m 2s] my fellow gang citizen robin [41m 6s] hello evan hello hello hello how are you [41m 9s] doing [41m 10s] pretty good pretty good um yeah thanks [41m 13s] for joining the [41m 14s] the stream man um i or i [41m 17s] i think at the last meetup i think [41m 20s] five minutes after it i saw you [41m 22s] streaming and i thought hey [41m 24s] i have to ask robin because yeah yep it [41m 26s] will be the perfect guest [41m 28s] that's a good idea thank you very much [41m 30s] for inviting me by the way [41m 32s] my pleasure my pleasure man so you're [41m 34s] going to talk about uh [41m 36s] headless uh ui today right which [41m 39s] you are the which you are also the [41m 41s] author of uh [41m 43s] i'm mostly mostly working on headless ui [41m 45s] um but i'm doing a lot of [41m 47s] bearing sessions behind the scenes with [41m 49s] adam and david who is also in the chat [41m 51s] and brett and a lot of other people but [41m 54s] yeah i'm [41m 55s] mostly working on that at stillwind labs [41m 56s] that's correct yeah [41m 58s] i get that yeah you're primarily working [42m] on it but it's teamwork because you get [42m 2s] like feedback from uh from everybody on [42m 4s] there [42m 5s] exactly exactly okay man uh [42m 8s] let me put on your screen and then [42m 10s] sounds good [42m 11s] are ready to go man enjoy [42m 14s] all right hello everybody so today we [42m 18s] are [42m 18s] going to look at headless ui and some [42m 20s] accessibility [42m 21s] um and i'll do some live coding and [42m 24s] we'll [42m 25s] see how we can build a nice little ui [42m 28s] and making things more accessible so for [42m 31s] starters we have headless ui [42m 33s] up here and basically headless ui is [42m 36s] a set of components that make your life [42m 38s] a bit easier [42m 39s] and make them accessible now [42m 43s] accessibility if people think about [42m 46s] accessibility [42m 47s] a lot of people think about screen [42m 48s] reader support which is very [42m 50s] important but more importantly screen [42m 52s] readers [42m 54s] and more importantly the the [42m 56s] accessibility make sure that your [42m 59s] applications are accessible are [43m 2s] usable by a lot of people so what do we [43m 5s] mean by that it's not only [43m 7s] just area management [43m 10s] area attributes so there is like a full [43m 13s] sorry for the white screen there's a [43m 16s] full um [43m 17s] working spec with like things you should [43m 19s] implement [43m 20s] and area stuff you should manage that's [43m 22s] all important but it's also important [43m 24s] that you make [43m 25s] things usable and also make things [43m 28s] keyboard navigateable and all of that [43m 31s] stuff [43m 32s] so let's imagine that [43m 35s] we have a little a fun little [43m 37s] application here that i built [43m 40s] and this application is a list of [43m 43s] invoices for example [43m 45s] now one thing that your boss will tell [43m 48s] you is [43m 48s] we need a little actions [43m 52s] menu up here so imagine [43m 55s] we go in here and we say [43m 58s] we have some actions that we put here [44m] because these are invoices and [44m 2s] we need to make sure that we can send an [44m 4s] invoice download and invoice all of that [44m 6s] good stuff [44m 7s] so let's see how we can do this with [44m 10s] headless ui so let's start by [44m 13s] importing the menu component from atlas [44m 16s] ui react [44m 18s] and this is currently a react [44m 20s] application [44m 22s] and address ui also has components for [44m 24s] vue [44m 25s] um and we are mostly focusing on those [44m 27s] two and [44m 28s] in the future we probably will look at [44m 31s] other tools like alpine and stuff [44m 33s] um but there's a lot going on already [44m 36s] but [44m 36s] for now react and view so [44m 40s] let's imagine we have a menu component [44m 43s] if i can type it would be great and the [44m 45s] menu component has a button [44m 48s] and in this button we will have three [44m 51s] dots [44m 52s] and we will have menu items [44m 55s] now these menu items will be [44m 59s] sort of actions that we want to do [45m] mainly a menu item can be a button [45m 4s] and let's say as button [45m 8s] and this button should be downloads pdf [45m 13s] now we see our three dots here and when [45m 15s] i click them you will notice that [45m 17s] something happens but it's completely [45m 19s] unstyled this is [45m 21s] basically where the name headless ui [45m 22s] comes from it's a set of [45m 24s] unstyled fully accessible components [45m 28s] now i'm also using a tailwind css [45m 31s] behind the scenes and this is [45m 35s] makes our lives a bit easier for styling [45m 37s] you should [45m 38s] check it out it's a good project so [45m 40s] let's start by [45m 41s] styling these buttons a bit um [45m 44s] so this one [45m 47s] i want to use for the button i want to [45m 50s] use like a vertical icon so [45m 52s] dots vertical icon and we can import [45m 55s] this from [45m 58s] hero icons maybe you've heard of that [46m 1s] one it's also a project [46m 2s] by the tillman labs team so that's a [46m 5s] vertical [46m 6s] icon hero icons reacts and [46m 9s] we should import it from the outline [46m 12s] okay we can't [46m 13s] we can't see anything because we are [46m 14s] missing some class names so let's add [46m 17s] h5 with five [46m 20s] and let's make this a great one [46m 24s] now we have a beautiful drop down but [46m 28s] things are still jumping around [46m 32s] one thing you should notice is that we [46m 35s] have some default styles focus styles [46m 38s] but we can replace those with [46m 39s] some relevant ui or tailwind utilities [46m 43s] so what we can do here is basically when [46m 45s] we focus [46m 46s] we use outline num this is [46m 50s] mostly not a good idea but you can use [46m 52s] it if [46m 53s] and only if you make sure that you also [46m 55s] apply alternative style so that you can [46m 57s] see something [46m 58s] so focus ring and let's say focus [47m 2s] um ring ping [47m 5s] what shall we do 500 maybe okay that [47m 8s] gives me a pink a pink thing that's [47m 10s] that's already nice and also make this [47m 13s] fully [47m 14s] rounded so now when we focus this [47m 18s] it's nicely colored let's add some [47m 20s] padding with p1 [47m 22s] and here we go so that's good so far [47m 26s] now one thing that we want to do is also [47m 28s] style [47m 29s] these things up here these items [47m 32s] um so we can do that by passing through [47m 36s] class names again [47m 37s] everything is installed by default so [47m 40s] you are [47m 41s] fully in charge of doing this thing so [47m 44s] let's make this a flex container [47m 46s] let's center this a bit um [47m 51s] let me also make sure that we use [47m 54s] flex columns in here let's make sure [47m 57s] that we are [47m 58s] using a nice nice little width um [48m 1s] of like 48 i think let's use a nice [48m 4s] background some [48m 5s] shadow some rounded corners maybe [48m 9s] lg what do we have now already [48m 13s] we have something already okay okay [48m 14s] that's that's that's good already [48m 17s] um let's add a bit of [48m 20s] margin between the button and this thing [48m 23s] okay cool and notice that this is [48m 26s] currently [48m 27s] outlined so we don't want it here so [48m 30s] what we will do is [48m 31s] focus outline [48m 35s] so currently nothing is really happening [48m 38s] but we have something working all right [48m 41s] next step let's add a few more items [48m 44s] so let's say we have some actions and [48m 47s] they can have a name [48m 49s] so this will be download pdf [48m 52s] this one will be maybe duplicate this [48m 55s] thing [48m 56s] sure maybe send the invoice and maybe [49m 1s] pay ready invoice and last but not least [49m 4s] we can say delete the invoice okay [49m 8s] so let's loop over this [49m 12s] chance map map this action to a [49m 15s] components [49m 16s] and this is our little components [49m 20s] always add your keys that's very [49m 21s] important [49m 23s] in this case we don't have anything [49m 25s] really unique [49m 26s] so we will use the name that is good [49m 29s] enough [49m 30s] mostly you want to do some some ids in [49m 31s] here and [49m 33s] and now let's echo out this action name [49m 37s] okay and now we can focus a little bit [49m 39s] more on on the styling up here [49m 42s] and where shall we start [49m 45s] let's say we want to make sure that this [49m 48s] is [49m 49s] left aligned okay now we do want to make [49m 53s] sure that we [49m 55s] have enough enough breeding room that's [49m 57s] always important in in design [49m 59s] breeding room all the things [50m 2s] there we go let's also add some [50m 5s] um rounded corners [50m 8s] and i will get to this in a second while [50m 10s] we'll do this [50m 12s] um and now that we have this [50m 15s] i think we are good to go okay [50m 19s] so the next thing i want to talk about [50m 21s] is basically how you make sure that you [50m 23s] can have like nice little [50m 24s] hover effects now [50m 28s] normally how you would implement this is [50m 30s] with hover colon [50m 32s] bg 200 [50m 35s] and you will notice that when you do [50m 37s] that you get something here it's [50m 39s] not that great but it's working [50m 42s] the issue with this is if you now use [50m 44s] your arrow knees and i have a little [50m 47s] key cluster down here that showcases my [50m 50s] um my piece that i'm i'm typing [50m 54s] you don't see anything here so this is [50m 57s] something that [50m 58s] headless ui provides for you so what we [51m 2s] will do instead [51m 3s] is um this class name can also be [51m 6s] a function and we will return [51m 11s] the last name that you want this [51m 12s] function has a back [51m 14s] and in this back you can restructure an [51m 16s] active prop [51m 18s] so what you can do with this is [51m 19s] basically when this is active [51m 22s] and we want to do something with the [51m 25s] ternary operator otherwise you want to [51m 26s] do something else [51m 28s] so what do we want to do we want to say [51m 31s] the background should be pink 600 [51m 34s] the text should be white and in other [51m 37s] scenarios the text should be [51m 40s] okay all right [51m 44s] now we have our nice hovers again [51m 47s] but now we also have [51m 50s] this enabled for your arrow keys [51m 53s] something that is bugging me a little [51m 54s] bit is a spacing in between [51m 57s] so let's give ourselves a little [52m] more breeding room here [52m 4s] this is better this is better all right [52m 7s] so [52m 8s] this is one thing that's important about [52m 9s] headless ui is that you [52m 12s] don't have to think a lot about [52m 14s] accessibility parts themselves but you [52m 16s] mostly get them for free [52m 18s] all right one thing that is bugging me [52m 20s] as well is the little [52m 21s] content that is shifting around here so [52m 23s] let's make tuples let's make sure to [52m 25s] position this [52m 26s] nicely as well so let's make this [52m 28s] relative [52m 30s] and let's make sure that our items are [52m 34s] absolutes they are to the right [52m 38s] and i think that's about it that should [52m 41s] be [52m 42s] that should be good already okay so one [52m 45s] issue that you are seeing is that our [52m 47s] other icons are peaking true that's [52m 49s] something we don't want so let's use [52m 51s] some z index there [52m 53s] and now we have our menu item [52m 57s] working nicely in this list [53m 1s] all right let's look a bit about at the [53m 5s] accessibility features that this [53m 7s] component gives you [53m 8s] um a lot of people if they want to [53m 11s] implement such an [53m 12s] um tool like this like a component like [53m 15s] this [53m 16s] they basically stop here and because you [53m 19s] can open it [53m 19s] you can close it you can hover it and [53m 21s] you can potentially click on things so [53m 23s] let's let's add a quick little on click [53m 26s] in here and [53m 28s] let's use a good old alert [53m 31s] invoking item [53m 36s] if i can spell click right [53m 39s] there we go [53m 43s] you will notice that something gets [53m 44s] executed um headless ui also provides [53m 47s] you like with a bunch of keyboard [53m 49s] accessibility features [53m 50s] um for example notice that we are using [53m 54s] our [53m 54s] mouse here and instead of doing this [53m 56s] what we can do is use our arrow key [53m 59s] our enter key that opens it and when you [54m 2s] enter again [54m 2s] it invokes the item when it's closed [54m 6s] the focus is returned to this little [54m 8s] icon down here [54m 10s] when we use the spacebar key it's doing [54m 12s] the same thing it's opening [54m 14s] and it's highlighting the first item [54m 16s] already [54m 18s] another feature we get out of the box is [54m 20s] when you press escape when you press [54m 21s] escape [54m 22s] it closes it automatically another [54m 25s] feature [54m 26s] is when you click outside of the menu [54m 29s] component [54m 30s] it closes as well so that's a lot of [54m 32s] stuff you just get for free [54m 36s] a few other things are when you press [54m 39s] page up down so then you jump to the [54m 43s] first one and the last one [54m 45s] when you press the home key or the arrow [54m 47s] key [54m 48s] at the end key so on on next this is [54m 51s] a function and then your arrow arrow [54m 53s] keys to [54m 55s] move around that's also how you can [54m 56s] navigate pages and stuff [55m] um so there's nothing here that you have [55m 2s] to think about [55m 3s] one thing that we can look at real quick [55m 6s] is what happens [55m 7s] under the hood is um when we look at [55m 10s] this [55m 11s] menu and let's see if this is visible [55m 14s] we basically put an id on here of [55m 16s] headless ui [55m 18s] we also manage area [55m 21s] stuff for you so this is important for [55m 23s] screen reader users [55m 24s] and this information will all be used in [55m 26s] your screen reader software [55m 28s] to notify you when things change [55m 32s] we also have a area controls this is [55m 35s] basically saying this little button [55m 37s] is controlling this pop over um [55m 41s] then we have a little our wrapper here [55m 44s] for our items [55m 45s] so they they have an area labeled by [55m 48s] this button so it's um [55m 52s] labeled by this thing so to improve this [55m 55s] for screen reader usage let's add a [55m 56s] little [55m 58s] span here with actions and let's give it [56m 1s] a class name of sr only this means [56m 3s] screen [56m 4s] screen reader only and basically what [56m 6s] this will do is [56m 7s] since this is controlled by this button [56m 10s] and these buttons [56m 11s] are just dots you basically want to sell [56m 13s] something [56m 14s] to screen user user so this is our [56m 16s] actions [56m 18s] we also have a role of menu and a tab [56m 21s] index for focus management [56m 23s] and each individual menu item has also [56m 26s] roll of menu item [56m 27s] a depth index of -1 because they are not [56m 30s] focusable there are [56m 31s] multiple ways that you can handle it but [56m 33s] by default they are not focusable [56m 35s] um and this is basically the relation [56m 38s] between those [56m 39s] whenever i hover over a certain thing [56m 42s] you will also notice that [56m 44s] in this div where we have the the role [56m 46s] of menu [56m 47s] we get an area active descendant and [56m 49s] that's basically telling screen reader [56m 51s] usage again [56m 52s] um which item is currently the active [56m 55s] the active one [56m 56s] so that's all the stuff you get for free [56m 58s] basically [57m] so let's let's continue a bit so [57m 3s] headless [57m 4s] doesn't do anything rendering wise for [57m 7s] you [57m 7s] so what if you want to group these [57m 9s] sections what if you want to group these [57m 11s] two together these two together [57m 13s] and then the last one let's let's try [57m 14s] and implement that [57m 16s] so one thing that we can do is [57m 20s] one of adam's favorite tricks [57m 23s] is basically using tuples or multiple [57m 26s] arrays [57m 28s] and what this allows us to do is group [57m 31s] them together [57m 31s] in these little errors currently this is [57m 33s] failing because [57m 35s] our action is now going to be a group [57m 37s] and [57m 38s] it will get an index here as well [57m 41s] because we will need it for the key [57m 43s] so what we will do here is we will loop [57m 45s] over the group [57m 46s] and we get our action back and then we [57m 49s] can [57m 50s] move this thing in here and one thing [57m 53s] that is important here is [57m 55s] let's add more breeding room always [57m 58s] add more breeding room so that's gonna [58m 1s] be here [58m 2s] and now i have to make sure that i rub [58m 4s] these in [58m 6s] at least like this okay [58m 9s] next we need a um [58m 14s] in here [58m 17s] okay group action [58m 21s] flip flop map is is not a function [58m 24s] apparently [58m 26s] is that not the case oh because i have [58m 29s] to [58m 30s] make sure that i write valid code there [58m 33s] we go [58m 34s] all right so now we have some elements [58m 36s] in between they are not looking great [58m 38s] but let's let's make it a bit nicer [58m 41s] so what we can do here is let's add some [58m 44s] breeding room [58m 44s] very important now on our menu items [58m 48s] themselves what we can do [58m 50s] is we have our flex [58m 53s] but we can make it um [58m 57s] let's see we can add a divide and divide [59m] we'll just put a line in between them [59m 1s] so divide y it's going to be gray and [59m 5s] then 100 [59m 7s] this is going to do some things already [59m 10s] and now you can get little lines here [59m 13s] good now our button [59m 17s] let's make it a full width [59m 20s] all right here we go and one thing that [59m 23s] i just noticed [59m 24s] is that we can get rid of this padding [59m 26s] because now we have a little bit of [59m 28s] light space up there [59m 29s] and we don't want it so now we have [59m 32s] some things going on here and this b [59m 37s] y can be just a p okay now we have this [59m 41s] nice thing [59m 42s] now if you are working with [59m 45s] accessibility a bit then you will know [59m 48s] that [59m 49s] adding diffs like this in between are [59m 51s] technically not allowed [59m 53s] because the hierarchy is that you have a [59m 54s] menu and then menu items nothing in [59m 57s] between can [59m 58s] be there so headless ui fixes this for [60m 1s] you [60m 2s] um what it does is [60m 5s] it will let me make sure to [60m 9s] look at this way okay so what it does is [60m 11s] it will [60m 12s] go over the dom and everything in [60m 15s] between [60m 16s] a roll of menu and roll of menu item [60m 18s] will get the roll none [60m 19s] so this is again to make the [60m 22s] accessibility [60m 23s] accessibility tree totally valid [60m 26s] so you don't really have to worry about [60m 28s] doing things [60m 30s] wrong um a lot of stuff is is happening [60m 32s] for you and that's basically what's [60m 34s] happening here [60m 35s] um again since [60m 39s] we are basically in control of rendering [60m 42s] the actual usability stuff is still [60m 45s] implemented so you can still use your [60m 46s] arrow keys up and down up and down [60m 48s] that's all working fine [60m 52s] so let's imagine that you can't [60m 53s] duplicate this pdf [60m 56s] okay you can disable the button so let's [60m 59s] add a disabled prop up here [61m 1s] make it true and one thing that the menu [61m 4s] item [61m 5s] can receive is a disabled prop think of [61m 8s] it as your normal buttons or input [61m 10s] items it's going to be disabled when [61m 13s] this is true if you don't have a [61m 15s] disabled [61m 16s] prop in javascript it's going to be [61m 18s] undefined and undefined is falsy [61m 20s] so this is just going to work [61m 23s] now one thing you will notice is when i [61m 25s] start hovering [61m 27s] we can't really hover over the [61m 28s] duplicates one [61m 30s] the styles are not great yet but we can [61m 33s] improve that later [61m 35s] another thing you can see is when we [61m 37s] start using our arrow keys [61m 39s] we will basically jump over it because [61m 41s] it's it's disabled [61m 42s] it should not be invokable [61m 45s] let's improve the styling a little bit [61m 48s] what we can do here is [61m 49s] say when this action is disabled [61m 53s] we can get this information from this [61m 55s] prop from this [61m 56s] little object when it's disabled [62m] then we want to say um let's say opacity [62m 4s] 25 maybe and let's reset our [62m 7s] cursor otherwise don't do anything [62m 10s] and now we get a little grayed out [62m 14s] disabled prop over here [62m 18s] one reason why we are basically [62m 20s] forwarding this disabled prop is that in [62m 22s] some of our components because we have [62m 24s] other components like list boxes and [62m 25s] stuff [62m 26s] um some of them can be disabled on [62m 29s] individual item [62m 30s] level but also on a group level and so [62m 33s] it's [62m 34s] it's quite nice to forward this so [62m 35s] that's just a boolean [62m 37s] um in other scenarios it could also be [62m 40s] that your disabled [62m 42s] logic up here can be a computer's [62m 45s] property like some function that you are [62m 47s] invoking and then you don't have to [62m 48s] duplicate it so basically we are [62m 49s] forwarding that [62m 51s] for you just because of this all right [62m 55s] um [62m 58s] a few other things i want to talk about [63m] is for example how we can [63m 2s] compose things together so currently we [63m 5s] have a menu components but we have a few [63m 7s] other components as well [63m 9s] so one of those is a transition [63m 11s] component [63m 13s] because currently the the [63m 16s] menu component is just popping in and [63m 19s] out [63m 19s] and that's about it so we can we can [63m 22s] improve things a little bit here [63m 24s] so let's import our transition component [63m 28s] and in headless ui it's pretty [63m 31s] easy to do this logic you basically [63m 34s] wrap your transition items [63m 38s] transition all right and [63m 41s] a transitional by default render a diff [63m 44s] but we don't want [63m 45s] if we basically want to put all the [63m 48s] props [63m 49s] onto the menu items so what we can do is [63m 52s] we provide an [63m 53s] s-prop fragment the s-prop will [63m 55s] basically [63m 56s] allow you to overwrite the underlying [64m] element that is being used [64m 2s] so let's import this fragment from react [64m 7s] and for the pipe script fans out there [64m 9s] one thing that's pretty cool about [64m 11s] the s probe is if you have like we have [64m 14s] an as [64m 14s] button here notice that the href here is [64m 18s] um being marked as incorrect this is [64m 21s] because [64m 21s] an href can be on a button but in case [64m 23s] that you are using an anchor tag then [64m 25s] it's totally fine [64m 26s] so for the type cute people you get a [64m 29s] little bit of [64m 31s] help here as well so let's make this a [64m 33s] button again [64m 36s] back your transition so what we want to [64m 38s] do is [64m 40s] we want to enter in and when we are [64m 43s] entering [64m 44s] what we want to do is we want to [64m 45s] transition with [64m 47s] an ease out and duration of 100 [64m 51s] and let's say we also want to transform [64m 54s] this is important for the next step [64m 58s] we want to start at enter from [65m 1s] and we want to enter from opacity zero [65m 4s] we want a little bit of [65m 5s] fade-in going on and we also want a [65m 8s] little bit of scale going on so [65m 10s] scale 95 and you want to enter to [65m 13s] where do we want to enter to we want to [65m 15s] enter to opposite 100 and scale 100 [65m 19s] so this should give us something already [65m 22s] this nice little effect this is only [65m 24s] going on on the [65m 25s] ender state of things not on the leaving [65m 28s] state because we didn't implement that [65m 29s] just yet but we have this [65m 31s] going on already so for the leaving [65m 35s] stuff we can do basically the same we [65m 37s] can transition we want to ease in this [65m 39s] time [65m 40s] we wanted a little bit a little bit [65m 42s] faster and [65m 44s] let's say transform again where we we [65m 47s] want to [65m 48s] live from opacity 100 [65m 51s] scale 100 we want to leave to [65m 55s] opacity 0 and scale 95 [65m 59s] all right now we should have [66m 2s] the logic built in to [66m 5s] fade in fade outs and scale a little bit [66m 10s] apart from that all the stuff is still [66m 12s] working so you can still [66m 14s] open up use your arrow keys press escape [66m 17s] there are a few [66m 18s] cool things that you don't have to think [66m 20s] about that are imported here [66m 21s] important here like when you press enter [66m 24s] to open it [66m 24s] and you quickly press escape you want to [66m 27s] cancel this transition [66m 28s] so this is basically happening for you [66m 30s] behind the scenes [66m 32s] and so again something else not to worry [66m 35s] about [66m 37s] all right what what else can we can we [66m 40s] talk about here [66m 44s] so [66m 46s] few things that i didn't talk about yet [66m 48s] is when we [66m 49s] open up this thing another thing is uh [66m 52s] focus trapping so when we start [66m 56s] tabbing around you're sort of locked [66m 58s] into this menu and this is because [67m 1s] again accessibility reasons you are you [67m 3s] have a menu you have to do an action [67m 5s] you either do the actual action or you [67m 8s] don't [67m 8s] and you press escape or click outside so [67m 10s] that's again stuff that's [67m 12s] managed for you [67m 15s] all right a few other things that are [67m 17s] maybe a bit more technical [67m 19s] but um atlas ui also provides you to [67m 23s] control [67m 24s] the the rendering of things so now we [67m 26s] have [67m 27s] this menu items it's currently being [67m 30s] being [67m 31s] mounted and unmounted in in react that [67m 35s] means it's mounting into the dom and [67m 38s] then it's removing it from the dom again [67m 40s] when it's when it's done you can control [67m 41s] that behavior by [67m 43s] by using uh unmount files and what it [67m 46s] will do in that case is basically [67m 49s] um make sure that it's started display [67m 52s] hidden [67m 53s] uh and that's something common common [67m 55s] you will see in in view applications [67m 58s] um i see a few questions in the chat [68m 2s] there is indeed outside click [68m 4s] functionality so when we have this [68m 6s] menu open we can click outside and it [68m 8s] will close for you [68m 10s] so if we zoom out a little bit [68m 14s] most of this code is basically all [68m 16s] styling related there is not a lot of [68m 18s] stuff going on to do the actual [68m 21s] um accessibility side of things we have [68m 24s] a list of actions [68m 25s] you can imagine that they are hard-coded [68m 28s] somewhere or that these are actually [68m 30s] implemented currently they just uses [68m 34s] stupid alerts but you can imagine this [68m 37s] doing real things [68m 38s] but apart from that there is nothing you [68m 39s] really have to have to think about and i [68m 41s] think this is one thing that's [68m 43s] very important for the web um it's [68m 46s] it's not so much about making sure that [68m 48s] screen readers or [68m 50s] work properly that's very important but [68m 53s] it's it's more important that everybody [68m 55s] can use [68m 55s] your application um so by providing all [68m 59s] these keyboard shortcuts [69m 1s] it's it's just something you don't have [69m 3s] to think about and it will make your [69m 4s] life a bit easier and we've seen it that [69m 6s] still went laps as well [69m 9s] so this is the most important stuff i [69m 12s] wanted to talk about [69m 14s] for this part um a few [69m 18s] small other things is we use a lot of [69m 21s] this [69m 22s] resource the the w3c working draft [69m 26s] where a lot of these components are [69m 29s] described and that we use for like [69m 32s] reference [69m 34s] um headless ui itself is also fully open [69m 37s] source [69m 38s] you can dive in and look at the packages [69m 40s] that we have currently we are focused on [69m 42s] react [69m 43s] and view um but again hopefully maybe [69m 47s] soon we will look at like more more [69m 50s] native javascript implement [69m 51s] implementation or maybe something like [69m 53s] alpine [69m 54s] and now especially that's alpine days [69m 56s] coming up [69m 59s] so there is that other stuff is [70m 3s] if you are a customer of building ui [70m 6s] then let's imagine [70m 10s] let's go to a nice example here [70m 13s] like the select menus [70m 17s] so we have nice designs here this is a [70m 19s] premium package of ours it's fully [70m 21s] accessible with it's built with [70m 23s] tailwinds and and nice designs [70m 25s] but if you can see we are we have like [70m 27s] react apps and view tabs [70m 29s] in here and those are basically all [70m 32s] implemented [70m 32s] using our open source and free headless [70m 34s] ui library [70m 36s] so if you're a customer you can benefit [70m 38s] from from this for free [70m 40s] and if people are interested [70m 44s] this small application that we [70m 47s] just built here uh will be available on [70m 50s] github [70m 50s] and i will probably have it's something [70m 53s] somewhere in the show notes or in the [70m 54s] description or wherever we can put it [70m 58s] and i think this is this is about it [71m] that i wanted to talk about [71m 1s] and yeah check out the the headless ui [71m 4s] documentation we have a lot more [71m 6s] a lot more components going on here um [71m 10s] we will add a few more in the future now [71m 12s] that we are working on e-commerce [71m 14s] packages and we will [71m 16s] update this accordingly and [71m 19s] enjoy using headless ui and if you have [71m 21s] any questions feel free to open up [71m 23s] issues [71m 23s] or jump into the discord of tillman css [71m 26s] we have an atlas ui channel there as [71m 27s] well [71m 28s] and that's it [71m 31s] that's it for me cool man very very cool [71m 35s] stuff [71m 36s] um it's it's amazing to see how easy [71m 40s] that [71m 41s] these components make it to make like a [71m 44s] quality experience [71m 45s] i still remember the pain of [71m 47s] implementing all of these things myself [71m 50s] and i don't [71m 51s] ever want to do that again and here [71m 53s] we've just done it in [71m 54s] half an hour time amazing yep that's [71m 57s] indeed the goal to [71m 58s] build the components once and never [72m] think about it ever again and just focus [72m 2s] on the stuff you are [72m 4s] you want to implement like your business [72m 6s] logic your [72m 7s] your styles your design system whatever [72m 9s] but you don't need to care about all of [72m 11s] this interaction [72m 12s] ever again that's that's sort of the [72m 13s] goal cool cool [72m 16s] uh let's maybe finish by maybe [72m 18s] mentioning one more thing [72m 20s] here you're doing streams yourself right [72m 23s] where can people uh see those streams [72m 26s] yes i am streaming on twitch um so if [72m 29s] you go to my [72m 30s] website i have a few links down here [72m 32s] maybe i don't know if you can see them [72m 33s] very well [72m 34s] let me zoom in real quick and so i'm [72m 38s] at malfoy robin on twitter i have my [72m 40s] users page that's very important because [72m 42s] i've seen a [72m 43s] few people ask for what editor i'm using [72m 46s] and and what tools i'm using for [72m 48s] for my window management um so if you go [72m 51s] to my [72m 51s] website there is a lot of links going on [72m 54s] for my github for my twitter for my [72m 55s] twitch and i stream at twitch.tv slash [72m 58s] robbie malfay and i [72m 59s] don't really have a schedule um but i [73m 2s] stream often enough and i work with [73m 5s] headless ui on the stream i work with [73m 7s] an invoicing system that i'm currently [73m 9s] building and that's where this little [73m 10s] example was [73m 12s] uh inspired by so you can [73m 15s] check me out there as well cool [73m 18s] uh yeah thanks again for for this talk [73m 21s] uh robin [73m 22s] and yeah have fun creating more [73m 24s] components [73m 25s] uh like these uh we need them so keep on [73m 28s] creating them [73m 29s] we will create we will keep creating [73m 31s] components cool [73m 33s] okay man see you around and thanks again [73m 37s] ciao okay we are at the [73m 40s] end of this meetup i hope you enjoyed it [73m 43s] uh i didn't plan uh a next one yet [73m 47s] i still have to hunt down some [73m 51s] some good speakers the aim of this [73m 53s] meetup is to give [73m 55s] new speakers a chance so if you want to [73m 58s] propose [73m 59s] a talk head over to meetup.laravel.com [74m 2s] and propose a talk there and maybe you [74m 5s] can speak at the next meetup [74m 7s] thanks again for attending and see you [74m 9s] the next time bye [74m 31s] you