Videos
-
Apparently I’m more than happy to discuss work in progress, yet when it comes to talking about something I’ve finished, I freeze up. 🤷 ↩︎
That’s it! I’m never going to use a framework that uses Webpack or installs more than 5 Node dev dependencies. Why? Because every time I check it out to work on it, all these dependencies break, and I’m left to spend hours updating them.
Never again! 😡
I wonder if we could convince Ben to order another run of Stratechery mugs shaped like the one he drinks from. I really like my Stratechery mug — it's one I often use — yet the mug he describes here is intriguing.
In other building-small-things-for-myself news, I spent a bit of time this morning on the image processor for Blogging Tools. The big new change was adding support for working with multiple source images, instead of just one. This made way for a new “Phone Shot” processor, which arranges multiple screenshots of phone apps in a row, while also downscaling them and proving some quick crops and distribution options.
This should reduce the vertical size of mobile app screenshots I post here, something that’s been bothering me a little.
Agree with @manton here. I used to be quite religious about Test Driven Development, but I'm less so nowadays. For the simple stuff, it works great; but for anything larger, you know little about how your going to build something until after you build it. Only then should you lock it in with tests.
Listening to this part of HV got me wondering if the secret to punctual trains is just a whole lot of them. You’re less likely to do something to delay a train — like hold the doors open — if you know the next one’s only a few minutes away, and will arrive on time. One builds on the other.
Just to add one point of anecdata to Ben’s experience: I’ve never been happy with the performance of the mobile radio of Pixel phones. You can be in the middle of the CBD and still experience weird dropouts while using mobile data. It’s quite frustrating.
While on my walk, I stopped briefly to clear a stone from my shoe and this purple swamphen (or pūkeko for our Kiwi friends) came up quite close to me. Not sure why. Looking for food maybe?
My recent exploration of Fyne has got me looking at building a level editor again. Have started work on the viewport, with camera movement using the WASD keys, and a basic mouse tracker for painting cells. Feels pretty good so far, although the cell mouse tracker might need some refinement.
Spending some time with the birds. Archie’s on heat, which is why she’s making those chirping noises. Ivy’s happily keeping to herself off to the side.
Day Trip to Bundanoon
Decided to go on a day trip to Bundanoon today. It’s been five years since I last visited and I remember liking the town enough that I thought it’d be worth visiting again. It’s not close, around 1 hour and 40 minutes from Canberra, but it not far either and I thought it would be a nice way to spend the day. Naturally, others agreed, which I guess explains why it was busier than I expected, what with the long weekend and all. Fortunately, it wasn’t too crowded, and I still had a wonderful time.
The goal was to go on a bush-walk first. I chose to do the Erith Coal Mine track, for no particular reason other than it sounded interesting. This circuit track was meant to take you to a waterfall by an old coal mine. However, the track leading to the actual mine was closed, thanks to the recent rain. In fact, if I could describe the bush-walks in one word, it would be “wet”. The ground was soaked, as were the paths, and although conditions were lovely, the paths were still very slippery.
After completing that circuit in probably 45 minutes, my appetite for bush-walking was still unsatisfied, so I tried the Fairy Bower Falls walk next. This was not as steep as the first one, but it turned to be a much harder track due to how wet and slippery everything was.
I stopped short of the end of this one too, as it seems the path was washed away. But I did manage to get a glimpse of the waterfall, so I’m considering that a win.
After that, I returned to the town for lunch and some train spotting. The train line to Goulburn runs through Bundanoon, and the last time I was there, there was probably a freight train every hour or so. So I was hoping to get a good view of a lot of freight traffic. Maybe shoot a video of a train passing through the station I could share here.
I had lunch outside and walked around the town a little, always within sight of the railway line, hoping for at least one train to pass through. But luck wasn’t on my side, and it wasn’t until I was on my way home that I saw what I think was a grain train passing through Wingello. I pulled over to take a video, and while I miss the locomotive, I got a reasonable enough recording of the wagons.
Being a little more hopeful, I stopped at Tallong, the next town along the road. I bought a coffee and went to the station to drink it and hopefully see a train pass through. Sadly, it was not to be. So I decided to head back home.
So the train spotting was a bust, and the bush-walks were difficult, but all in all it was quite a nice day. I look forward to my next visit to Bundanoon. Lets hope the trains are running a little more frequently then.
Attempting to give head scratches while recording video is more difficult than it looks. 🦜
🎥 I’ve released a video tutorial on how to use and configure the Sidebar For Tiny Theme. This walks through the process of creating and using a custom Micro.blog theme to configure the sidebar with custom HTML. Hope others find it useful.
Picnic train, now boarding. 🚂
Photo Bucket Update: More On Galleries
Spent a bit more time working on Photo Bucket this last week1, particularly around galleries. They’re progressing quite well. I’m made some strides in getting two big parts of the UI working now: adding and removing images to galleries, and re-ordering gallery items via drag and drop.
I’ll talk about re-ordering first. This was when I had to bite the bullet and start coding up some JavaScript. Usually I’d turn to Stimulus for this but I wanted to give HTML web components a try. And so far, they’ve been working quite well.
The gallery page is generated server-side into the following HTML:
<main>
<pb-draggable-imageset href="/_admin/galleries/1/items" class="image-grid">
<pb-draggable-image position="0" item-id="7">
<a href="/_admin/photos/3">
<img src="/_admin/img/web/3">
</a>
</pb-draggable-image>
<pb-draggable-image position="1" item-id="4">
<a href="/_admin/photos/4">
<img src="/_admin/img/web/4">
</a>
</pb-draggable-image>
<pb-draggable-image position="2" item-id="8">
<a href="/_admin/photos/1">
<img src="/_admin/img/web/1">
</a>
</pb-draggable-image>
</pb-draggable-imageset>
</main>
Each <pb-draggable-image>
node is a direct child of an <pb-draggable-imageset>
. The idea is that the user can rearrange any of the <pb-draggable-image>
elements within a single <pb-draggable-imageset>
amongst themselves. Once the user has moved an image onto to another one, the image will signal its new position by firing a custom event. The containing <pb-draggable-imageset>
element is listening to this event and will respond by actually repositioning the child element and sending a JSON message to the backend to perform the move in the database.
A lot of this was based on the MDN documentation for drag and drop and it follows the examples quite closely. I did find a few interesting things though. My first attempt at this was to put it onto the <pb-draggable-image>
element, but I wasn’t able to get any drop events when I did. Moving the draggable
attribute onto the <a>
element seemed to work. I not quite sure why this is. Surely I can’t think of any reason as to why it wouldn’t work. It may had something else, such as how I was initialising the HTTP components.
Speaking of HTML components, there was a time where the custom component’s connectedCallback
method was being called before the child <a>
elements were present in the DOM. This was because I had the <script>
tag in the the HTML head and configured to be evaluated during parsing. Moving it to the end of the body and loading it as a module fixed that issue. Also I found that moving elements around using element.before and element.after would actually call connectedCallback
and disconnectedCallback
each time, meaning that any event listeners registered within connectedCallback
would need to be de-registered, otherwise events would be handled multiple times. This book-keeping was slightly annoying, but it worked.
Finally, there was moving the items with the database. I’m not sure how best to handle this, but I have that method that seems to work. What I’m doing is tracking the position of each “gallery item” using a position
field. This field would be 1 for the first item, 2 for the next, and so on for each item in the gallery. The result of fetching items would just order using this field, so as long as they’re distinct, they don’t need to be a sequence incrementing by 1, but I wanted to keep this as much as possible.
The actual move involves two update queries. The first one will update the positions of all the items that are to shift left or right by one to “fill the gap”. The way it does this is that when an item is moved from position X to position Y, the value of position
between X and Y would be changed by +1 if X > Y, or by –1 if Y > X. This is effectively the same as setting position X to X + 1, and so on, but done using one UPDATE
statement. The second query just sets the position of item X to Y.
So that’s moving gallery items. I’m not sure how confident I am with this approach, but I’ve been testing this, both manually and by writing unit tests. It’s not quite perfect yet: I’m still finding bugs (I found some while coming up with these screencasts). Hopefully, I’ll be able to get to the bottom of them soon.
The second bit of work was to actually add and remove images in the gallery themselves. This, for the moment, is done using a “gallery picker” which is available in the image details. Clicking “Gallery” while viewing an image will show the list of galleries in the system, with toggles on the left. The galleries an image already belongs to is enabled, and the user can choose the galleries they want the image to be in by switching the toggles on and off. These translate to inserts
and remove
statements behind the scenes.
The toggles are essentially just HTML and CSS, and a bulk of the code was taken from this example, with some tweaks. They look good, but I think I may need to make them slightly smaller for mouse and keyboard.
I do see some downside with this interaction. First, it reverses the traditional idea of adding images to a gallery: instead of doing that, your selecting galleries for an image. I’m not sure if this would be confusing for others (it is modelled on how Google Photos works). Plus, there’s no real way to add images in bulk. Might be that I’ll need to add a way to select images from the “Photos” section and have a dialog like this to add or remove them all from a gallery. I think this would go far in solving both of these issues.
So that’s where things are. Not sure what I’ll work on next, but it may actually be import and export, and the only reason for this is that I screwed up the base model and will need to make some breaking changes to the DB schema. And I want to have a version of export that’s compatible with the original schema that I can deploy to the one and only production instance of Photo Bucket so that I can port the images and captions over to the new schema. More on this in the future, I’m sure.
Photo Bucket Galleries and Using the HTML Popover API
Spent a bit more on Photo Bucket this evening. Tonight I started working on galleries, which’ll work more or less like albums.
At the moment you can create a gallery and add a photo to it. Most of the work so far has been backend so the UI is pretty rough. Eventually you’ll be able to do things like rearrange photos within galleries, but for the moment they’ll just be added to the end.
I did need to add some modals to the UI, such as the New Gallery model that’s shown for the gallery name. This gave me the opportunity to try out the new popover API. And yeah, it does exactly what it says on the tin: add the popover
attribute to an element and it becomes a working popover (at least in the latest version of Vivaldi). Must say it’s impressive that this is now possible with HTML alone.
The initial version of the modals used a <div>
for the popover target. And while that worked, there were some small annoyances. First was that the form within the popover didn’t get focus when the popover was displayed. It would be nice to click “New” and start typing out the gallery name. But this is a small thing that’s easily solvable with JavaScript, so it’s no big deal.
The second, slightly larger one, was that dismissing the popover by clicking outside of it will not eat the input. If you were to click a sidebar link while the New Gallery model is opened, you’ll end up on that newly selected page. I’m not a fan of this. Dismissing the popover feels like its own user gesture, and I fear the user accidentally activating things when all they’re trying to do is dismiss the popover (it’s not in place now, but I am planning to dim the background when the Create Gallery modal is visible).
Fortunately, there’s a simple solution to this. It turns out that replacing the <div>
element with a <dialog>
element would solves both problems. It works seamlessly with the new popover attributes, yet showing the dialog will give focus to the form, and will eat the click when the user dismisses it.
Perfect. Looks like I’ve delayed the need for JavaScript a little longer (it will come eventually; it always will).
Working on one of the admin sections of the project I was alluding to yesterday. Here’s a screencast of how it’s looking so far.
The styling and layout is not quite final. I’m focusing more on functionality, and getting layout and whitespace looking good always takes time. But compared to how it looked before I started working on it this morning, I think it’s a good start.
In the end it took significantly more time to write about it then to actually do it, but the dot product approach seems to work.
🎥 Elm Connections #7: Deploying
In which I round out the series by deploying Clonections to Netlify.
🎥 Elm Connections #6: Fetching And JSON Decoding Puzzles
In which I use Elm’s HTTP client and JSON decoder to fetch puzzles from an external resource.
🎥 Elm Connections #5: Option Shuffling
In which I use Elm’s random number generator to shuffle the options.