Articles in the year 2023

Five Useful Apple Shortcuts For Obsidian

3 months ago Sat, Aug 26, 2023

Obsidian is a note-taking powerhouse. Unfortunately, no app can offer every feature. One thing missing from Obsidian for iOS is the ability to add widgets to the home screen. In this article I'll show you how to get that functionality back with Apple Shortcuts.

#Prerequisites

Before I continue, there is some functionality that you may need or want to add to your Obsidian setup via community plugins in order to use these shortcuts.

#1. Advanced URI

Advanced URI by Vinzent is required to add additional URL Schemes to Obsidian. These additional URL schemes will allow you to trigger functionality in Obsidian through links that can be called from outside the app. The documentation lists the following examples:

Here is an example URL scheme:

obsidian://advanced-uri?vault=<your-vault>&workspace=main

#2. Obsidian Homepage

Obsidian Homepage by mirnovov allows you assign a note, canvas or workspace as a "home page". It allows you to configure when and how this homepage note is opened. This plugin isn't really necessary to use the Home shortcut, but it's a good plugin that deserves a mention in this context.

#3. Quick Add

Quick Add by Christian Bager Bach Houmann adds functionality to Obsidian to enable you quickly create notes with a specified template. It is a very powerful plugin that enables you take additional actions such as capturing information and running macros when adding notes. This plugin is required for the Quick Add shortcut.

#4. Obsidian Hotkeys for Templates

Obsidian Hotkeys for Templates, also by Vinzent adds a command to list all your templates. You can then assign a hotkey to bring up this list. This is useful when you want to call a command to insert a template from an Apple Shortcut using Advanced URI.

#Shortcuts

In this section I'll describe five shortcuts that will allow you to control Obsidian from Apple shortcuts on iPhone, iPad and Mac. Feel free to download and modify them to suit your needs.

#1. Home

Download Shortcut

This shortcut will open your Obsidian home note. When you import it into the shortcuts app it will ask you two setup questions:

  1. What is the name of your Vault?
  2. What is the name of your home note?

In reality, you can simply duplicate and rename this shortcut to make it open any note in your Obsidian vault. Don't forget to modify or remove the import question that asks for the name of your home note.

#2. Today (Daily Note)

Download Shortcut

This shortcut will open today's daily note. Additionally, if you have Obsidian Hotkeys for Templates installed, it will also insert the template for your daily note.

When you import this shortcut it will ask you two setup questions:

  1. What is the name of your vault?
  2. What is the path to your Daily Notes? (e.g. Journal/)

#3. Quick Open

Download Shortcut

This shortcut will open Obsidian and then call the command to open the Quick Open palette. You can start typing immediately to quickly open the note you are looking for.

When you import this shortcut it will ask you one setup question:

  1. What is the name of your vault?

#4. Open Note for Date

Download Shortcut

This shortcut lets you open a daily note for any date by letting you choose from a date picker as well as offering shortcuts for Yesterday, Today and Tomorrow.

When you import this shortcut it will ask you two setup questions:

  1. What is the name of your vault?
  2. What is the format date you have chosen for your daily notes?

#5. Quick Add

Download Shortcut

This shortcut will open Obsidian and call the Quick Add command. This will list all of the quick add commands you have configured in the plugin settings.

When you import this shortcut it will ask you one setup question:

  1. What is the name of your vault?

#Customisation

Remember, you are free to copy and modify all of these shortcuts to fit into your Obsidian workflow. It's easy to change the icon, colour and title of each shortcut in the Shortcuts app.

You can also modify the shortcuts to use other urls exposed by the Advanced URI plugin. Get it touch with me on Twitter/X if you have any questions.

#Quick Tips

  • All text entered during import will be URL Encoded so you can just enter the names as they appear in Obsidian.
  • These shortcuts will work on both iOS and MacOS.
  • You can search for these shortcuts in Spotlight or Raycast.
  • You can pin shortcuts to the menu bar on Mac OS.
  • You can modify the shortcuts to accept input and then use them as Quick Actions on iOS.
  • You can add shortcut widgets that will trigger these shortcuts.
  • You can ask Siri to trigger these shortcuts.
  • You can even make new shortcuts to call existing shortcuts.

#Credit

Finally, I'd like to mention the Obsidian community forum, where you can find a thread called iOS Shortcuts - Share your ideas!. My shortcuts are modified versions inspired by shortcuts I found on this forum. Unfortunately, its been some time since I made these shortcuts so I can't credit people individually as I normally do.

Make sure to check the thread out if you are looking for inspiration or ready-made shortcuts that I don't cover in this article.

Thank you for reading this article.

If you've made it this far, you might like to connect with me on 𝕏 where I post similar content and interact with like-minded people. If this article was helpful to you I'd really appreciate it if you would consider buying me a coffee.
Continue Reading

Extracting Wikilinks For Your Markdown Laravel Blog

3 months ago Tue, Aug 22, 2023

I recently rebuilt this site so I could write my articles in Markdown. I'm used to writing in Obsidian and have come to rely heavily on wikilinks. Laravel comes with Markdown baked in. Behind the scenes, it makes use of a package called league/commonmark. Commonmark offers a large list of extensions, but as we will see, none of them work to add Wikilinks functionality.

TL;DR #Create your own wikilinks custom delimiter

#What is a Wikilink?

First things first, let's just do a quick recap. What exactly is a wikilink? Created and used by Wikipedia, wikilinks are a convenient way to link to internal pages.

Say we have an internal article called "Tidying Tips", which it just so happens we do, then the conventional way to link to it would be by using an HTML a tag:

<a href="https://www.carlcassar.com/articles/tidying-tips">
	Tidying Tips
</a>

In Markdown, this can be done by using markdown's link syntax:

[Tidying Tips](https://www.carlcassar.com/articles/tidying-tips)

Now, its not unusual to link to several other internal pages within one article and links tend to be quite cumbersome to type out by hand. All the slashes and w's make it all too easy to make a mistake. Wikilinks were created as a wrapper to make it quick and convenient to link to other internal content. Using our earlier example, the syntax for a wikilink is as follows:

[[Tidying Tips]]

It's as simple as that. You just wrap the title of the page you are linking to in double square brackets, [[ and ]].

Wikilinks come with some additional features. We can change the "looks like" or alt text of the link by adding our preferred text after the title:

[[Tidying Tips|an short article on refactoring]]

Additionally, we can link to an id on the same page by using a # symbol.

[[#Some Heading On The Page]]

#League/Commonmark and Wikilinks

Commonmark is a fantastic package that handles a lot of work when it comes to using markdown in Laravel and PHP. Unfortunately, it does not support Wikilinks and will simply ignore any text wrapped in two square brackets.

Looking down the list of extensions, you will find one called Mentions. The mentions extension allows one to parse mentions like @carlcassar and #2343. Unfortunately, it seems that although it will parse the prefixes @, # and almost anything else that I experimented with, including digits (3...) and random letters (s...), it will ignore square brackets, even when they are escaped correctly in a regular expression.

#Create your own wikilinks custom delimiter

Handily, not all is lost. Commonmark exposes its delimiter processor API.

Delimiter processors allow you to implement delimiter runs the same way the core library implements emphasis.

Using a delimiter processor, we can process text that is encapsulated in between a number of matching symbols, e.g. *example*, {example}, {{example}}.

First, we must add a delimiter processor to the Commonmark Enviroment:

$environment->addDelimiterProcessor(new WikilinksDelimiterProcessor());

Next, we must create the WikilinksDelimiterProcessor which must implement the DelimiterProcessorInterface.

class WikilinksDelimiterProcessor implements DelimiterProcessorInterface  
{
	//
}

In order to satisfy the contract of the Interface, we must implement 5 methods:

public function getOpeningCharacter(): string  
{  
    return '[';  
}  
  
public function getClosingCharacter(): string  
{  
    return ']';  
}  
  
public function getMinLength(): int  
{  
    return 2;  
}  
  
public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int  
{  
    return 2;  
}

public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void  
{
	// What now?
}

In our case, the opening character is [, the closing character is ] and we require two of each in order to process the literal string contained in our delimiter.

All that's left is to implement the process function which will tell commonmark what to do when it encounters our wikilink.

First, we need to get the literal string from the AbstractStringContainer $opener.

Now this is where it gets a little bit tricky. It seems that commonmark really doesn't like working with double square brackets. In this case, although it correctly identifies the string we are looking for, it fails to remove the second opening bracket and we are left with the literal string [Tidying Tips.

No problem, we can simply remove the bracket ourselves:

private function getLiteralFrom(AbstractStringContainer $opener): Stringable  
{  
    $literal = $opener->next()->getLiteral();  
  
    // Commonmark does not work for double square brackets,  
    // so we will remove a leftover square bracket from    
    // the beginning of the opener literal string.    
    return Str::of($literal)->substr(1);  
}

At this point, we should keep in mind our eventual goal - to replace the text with a link. Commonmark has our back and provides a link node, which requires a url parameter and accepts an optional label and title. With this in mind, lets create a function to get those attributes from the literal:

$attributes = $this->getAttributes(  
    $this->getLiteralFrom($opener)  
);
private function getAttributes(Stringable $literal): Collection  
{  
    $explodedLiteral = $literal->explode('|');  
  
    $wikiTitle = $explodedLiteral[0];  
    $wikiLooksLike = count($explodedLiteral) > 1 ? $explodedLiteral[1] : null;  
  
    return collect([  
        'url' => $this->getUrlFor($wikiTitle),  
        'label' => $wikiLooksLike ?? $wikiTitle,  
        'title' => $wikiLooksLike ?? $wikiTitle,  
    ]);}

Finally, we need to cater for hash links as well as ordinary links:

private function getUrlFor(string $wikiTitle)  
{  
    $slug = Str::of($wikiTitle)->slug();  
  
    return $this->isHashLink($wikiTitle) ? "#$slug" : $slug;  
}  
  
private function isHashLink(string $wikiTitle): bool  
{  
    return Str::of($wikiTitle)->substr(0, 1) == '#';  
}

Here is the final WikilinksDelimiterProcessor class:

<?php  
  
namespace App\Console\Commands\Support;  
  
use Illuminate\Support\Collection;  
use Illuminate\Support\Stringable;  
use League\CommonMark\Delimiter\DelimiterInterface;  
use League\CommonMark\Delimiter\Processor\DelimiterProcessorInterface;  
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;  
use League\CommonMark\Node\Inline\AbstractStringContainer;  
use Str;  
  
class WikilinksDelimiterProcessor implements DelimiterProcessorInterface  
{  
    public function getOpeningCharacter(): string  
    {  
        return '[';  
    }  
    
    public function getClosingCharacter(): string  
    {  
        return ']';  
    }  
    
    public function getMinLength(): int  
    {  
        return 2;  
    }  
    
    public function getDelimiterUse(DelimiterInterface $opener, DelimiterInterface $closer): int  
    {  
        return 2;  
    }  
    
    public function process(AbstractStringContainer $opener, AbstractStringContainer $closer, int $delimiterUse): void  
    {  
        $attributes = $this->getAttributes(  
            $this->getLiteralFrom($opener)  
        );  
        
        $opener->next()->replaceWith(new Link(  
            $attributes->get('url'),  
            $attributes->get('label'),  
            $attributes->get('title')  
        ));    
	}
	  
    private function getLiteralFrom(AbstractStringContainer $opener): Stringable  
    {  
        $literal = $opener->next()->getLiteral();  
  
        // Commonmark does not work for double square brackets,  
		// so we will remove a leftover square bracket from   
		// the beginning of the opener literal string.    
	    return Str::of($literal)->substr(1);  
    }  
    
    private function getAttributes(Stringable $literal): Collection  
    {  
        $explodedLiteral = $literal->explode('|');  
  
        $wikiTitle = $explodedLiteral[0];  
        $wikiLooksLike = count($explodedLiteral) > 1 ? $explodedLiteral[1] : null;  
  
        return collect([  
            'url' => $this->getUrlFor($wikiTitle),  
            'label' => $wikiLooksLike ?? $wikiTitle,  
            'title' => $wikiLooksLike ?? $wikiTitle,  
        ]);    
	}  
        
    private function getUrlFor(string $wikiTitle)  
    {        
	    $slug = Str::of($wikiTitle)->slug();  
  
        return $this->isHashLink($wikiTitle) ? "#$slug" : $slug;  
    }  
    
    private function isHashLink(string $wikiTitle): bool  
    {  
        return Str::of($wikiTitle)->substr(0, 1) == '#';  
    }
}

#Test it out

All being well, I will include a few links using wikilinks syntax and you should be able to click through to each of them.

Thank you for reading this article.

If you've made it this far, you might like to connect with me on 𝕏 where I post similar content and interact with like-minded people. If this article was helpful to you I'd really appreciate it if you would consider buying me a coffee.
Continue Reading

How My Blog Has Evolved Over The Years: A Look Back At The Wayback Machine

3 months ago Sun, Aug 20, 2023

Today I launched a new version of this blog. It got me thinking that I've been at this for a long time and have updated the design and functionality many times. I thought it would be fun to take a look at how this site has changed over time by using the Wayback Machine at archive.org.

When you search for this site on the Wayback Machine, you will see that I've been tinkering on this domain for over thirteen years, since February 16th 2010. I've not been a hundred percent consistent over that whole period, mostly due to work and other commitments, but you can also see that I always come back to it given the chance and that web development and blogging have been my long term passion.

Way Back History

I'm a firm believer that the best way to learn to code is to dream up a project and make it happen one way or another. The second you have a goal, you can start typing questions into Google. How do I do this? How to I get that button where I want it? How do I add a search bar. This has always been part of the motivation for this site. Whenever I want to learn something or try out that new web development fad, I have a platform on which I can tinker. You'd be amazed at how much you can learn by making a personal website and hacking away at it.

The Wayback Machine tells me that it has taken no less than 54 snapshots between February 16, 2010 and May 31, 2023. Now that you know a little bit about the reasons behind why I started and continue to work on carlcassar.com, lets jump right in and take a look at what the site looked like in each iteration over the last decade or so.

Caveat: It seems like Wayback machine hasn't always been able to capture images from the site, so the site might sometimes look incomplete in some of the screenshots.

#2010

2010 carlcassar.com 16th February 2010.

It's 2010. I've been on Twitter for a few months. I know the basics, but learning things at university is not the same as making things in practice. I sound like a cheesy salesman. I can't spell portfolio, and what on earth is going on with that logo?! When you don't know, you don't know, but the important thing is that you can always get better. There's one thing there that I still agree with:

every site should be designed by default ... to be in the best possible position ... on all major search engines.

#2011

2011 carlcassar.com Christmas Day 2011.

Well, what a difference a year makes. Before you shoot it down, remember how much the internet has changed in the last twelve years. Fun, patterned backgrounds were all the rage back then. We still hadn't moved into the minimalist era we now inhabit. Websites were bold and colourful and the only rule was not to make things blink and scroll around.

I'm quite proud that the 2011 version includes a few features that must have taken a lot to learn and implement back then:

  • Feedback and contact forms
  • An image carousel for my portfolio of sites
  • Rounded corners
  • Opaque icons

These things would be trivially easy to implement today, but it's easy to forget that CSS3 was new and not fully supported by all browsers. Meanwhile, Laravel was only released in June of that year.

It seems as though I was still persisting with that horrible logo:

2011 carlcassar.com Logo A fun if confusing and slightly scary logo.

2011 carlcassar.com quote form A quotation form complete with rounded inputs and validation.

#2014

2014 carlcassar.com 16th December 2014.

Fast forward a few years. Despite working full-time, my passion for web design and development was growing. I worked hard to improve my design skills, which did not come naturally to me. I started to get to grips with the fact that software development was not something you learned once. There is always something new to take on, and judging by the banner I put up on the site, I had come to realisation that I love to learn new skills.

2014 carlcassar.com I love to learn I loved to learn in 2014 and I still do in 2023.

And it's a good thing too, because then as now, there is always something new to learn. Over the years, I've become faster at picking up new skills, because knowledge, like many things in life, benefits from a compounding effect. Perhaps, more importantly, I've learned identify the things I don't need to learn (at least not immediately). Other things, like SQL, Vim, Laravel, PHP and Javascript are timeless and have stood the test of time.

2014 carlcassar.com skills There are a 100 tools to learn at any given time, but only some of them stand the test of time.

Finally, I seem to have realised the error of my ways and made a new logo:

2014 carlcassar.com new logo A new, and I'm sure you'll agree, much nicer logo.

2014 also seems to be the first time I mentioned Laravel. I can still remember what a breath of fresh air it was to adopt common conventions and not have to reinvent the wheel on every feature I wanted to add.

2014 carlcassar.com laravel

By this time, I was also trying my hand at freelance development for friends, family and a few brave customers. I started a small company called Versd with what was a pretty modern and intricate design at the time.

2014 carlcassar.com Versd My first web development company: Versd

#2016

By 2016, I'd taken up a full-time full-stack developer job and so it was time to simplify the site and remove any references to freelance work and Versd.

2016 carlcassar.com Simple and elegant - often less is more.

This dark design still feels quite modern and reminds me of the current trend in dark landing pages triggered by the beautiful design of the Linear App. I love the Bokeh effect. Other than that, the 2016 design was pretty simple and completely pared down. I guess that I no longer felt the need to show off every skill on this one site.

Less is more and simplicity is the hardest skill to master.

The site didn't change much at all for another couple of years. My time was occupied by a small gig-economy business I helped to start as well as my full-time job as a Senior Developer and later as Lead Software Developer and Manager.

#2019

2019 carlcassar.com carlcassar.com as a blog

2019 brought a lot of changes for me. It was time to embrace new challenges and maybe start to share one or two tips and tricks that I had picked up over the years. I seem to have started my fascination with TailwindCSS and with various shades of grey. The design is clear and simple, but Wayback machine seems to have had trouble finding any content. Javascript is powerful but it takes some effort to make it accessible.

#2020-2023

2020 carlcassar.com

Lockdown gave me plenty of time to think and work on my site amongst other things. I came up with a new design inspired loosely by tools like Instapaper. I have always loved what the look and feel of blogs that use simple black typography on a white background. I tried to add some colour but I felt that this never worked as well as I hoped it would.

Still, after a couple of redesigns on the backend, I ended up with a very functional site that allowed me to write articles quickly. I added a way to leave comments using Utterances and functionality to search articles on the site.

Over the last two years, I've been busy with another kind of development. I've taken on a large restoration project on a house I bought during Covid. I kept up my software development throughout, experimenting with technologies that were completely new to me such as Swift, SwiftUI and Wolfram Language. I often felt the urge to share and write about things I've learned, but I had painted myself into a bit of a corner. My setup was too complicated and I had added a lot of unnecessary friction between writing and posting a new article. Recently, I decided to do something about it and have carved out the time to make the umpteenth revision to this site.

This time round, I'm practicing a new skill. Deliverability. All too often, as software developers who enjoy our craft, we find ourselves tinkering in the depths of some system or other convinced that we are doing good work. While we all know that this can be fun, we also know we would never get away with it at work and if I want this blog to be as helpful to as many people as possible then I need to focus on making it easy to create and post articles on a whim, whilst the ideas and lessons are still fresh in my mind.

I once read (I wish I could remember where) that the best educational material is written by someone who has just gone through the pain of learning that thing. Often, by the time one has mastered something, one tends to forget about how it felt to not know it. It becomes easy to make assumptions about the ambient level of knowledge that your audience possesses about a given topic. I hope that my latest efforts will prevent me from falling into this trap.

#Today

2023 carlcassar.com

Today, I launch a new design and more importantly a new method of releasing articles onto the site which feels more comfortable to me. I hope to write about the technical details soon, but for now, I hope you will agree that the new design, though simple, offers the functionality that you would expect of a half-decent blog.

I have focused on making articles easy to read and navigate. Updates will come soon to allow you to comment, find related content and bookmark articles that you find useful.

For now, I would really appreciate any feedback you might have. Feel free to get in touch with me on Twitter / X.

Thank you for reading this article.

If you've made it this far, you might like to connect with me on 𝕏 where I post similar content and interact with like-minded people. If this article was helpful to you I'd really appreciate it if you would consider buying me a coffee.
Continue Reading