Maintaining websites with Bear App and Quarto

Productivity processes
Web sites
bear
highlight
processes
Making this website enjoyable and fun to edit has been the single most important change I ever have made to my productivity processes.
Published

January 23, 2025

Watch this video on Youtube.

The most important change I made to my productivity processes last year was to create a new process so I could edit this website using the Bear App.

I use the static website generator Quarto to generate this website. Of course there are other static website generators available, such as Hugo (which is very fast), and each has its pros and cons. I use Quarto because one of my main interests is information and data visualization, and Quarto is specifically designed for this. So I can write essays that include diagrams, animations and charts, and they are automatically handled by Quarto.

A standard tool to maintain a Quarto website is the programmer’s editor VS Code. I do like VS Code and use it regularly. But for writing? Ugh. It’s for programming, not for writing. I’m not sure why — perhaps it’s because programming principally requires a focused mindset rather than a diffuse one — but I just really dislike writing essays in VS Code. VS Code may work for writing for guru programmers — people who code every day and for whom programming is similar to speaking, but for me — for whom programming is definitely a system 2 task, VS code puts me in the wrong mindset. Whilst VS Code is a great code editor, it is not nice to use to write essays like this one. I wanted something that was both great for writing essays, and could also do technical stuff like incorporate bits of code, YAML front-matter, markdown, etcetera. I have tried many apps in the past for writing and keeping notes, and Bear App is by far my favorite1. It is also very markdown friendly, and has a great tagging system. Converting this website so that I can edit it in Bear had a huge positive effect on my productivity, and makes it a pleasure to write and publish new content. I don’t think I’ve ever been as productive as I am now.

1 You can read about other methods I have tried for writing and keeping notes (such as Obsidian, Notion, Craft, etc) here: My Personal Knowledge Management system

I am very pleased with some of the features my new system has. Here are some highlights:

2 Wikilinks are a simple way to make internal links. You write two square brackets and start typing a word from a page title and Bear lists all the matching pages. You then select the one you want and the link is made.

I haven’t even started to fully exploit all the possibilities of this new set-up. If you want to try setting up something like this yourself, more details follow.

Details

I had used Bear App before to experiment keeping a website of notes, just by using the export HTML option. If you just want a simple clean website then its a great option — very easy to do and it looks great. You can read about my experiments doing that here: Creating a website with Bear app

My process uses Bear App and Quarto, but there are other combinations that may be more appropriate for other people. For example, Obsidian and Hugo make a great combination. Bear and Hugo would also work well. Hugo is much faster than Quarto when generating the pages. I use Quarto because it has features related to data visualization. If you don’t need those then Hugo may be a better option for generating the site as it’s fast.

Bear has a lovely method of tagging — tags can be nested in a way that is similar to a folder structure, and when you export the Markdown the exported files conform to that structure. This means that you can have your website reflect the structure of your Bear App setup (or vice-versa, depending on how you want to think about it.)


This is what my website setup looks like in my Bear App

The Markdown export in Bear is very good, but there were various changes that I want to make so that it renders with all the functionality I want in Quarto.

Bear markdown processing

Following is the process I use to modify the markdown output to qmd files. I created the scripts using OpenAI GTP-4o. An example prompt is given at the end of this document. I created multiple scripts because I have found that GTP-4o is great at writing short scripts that do only one or a small number of things, it can often get them right first time if the prompt is good. Whoever, if you try to write longer scripts that do multiple things, it is more likely to have problems, and when it starts to have problems it is often best to just start again. So using lots of small scripts is efficient. It also makes it easy to remove steps from the process — I just remove that script from the list in the main master-script.

Don’t process files with Python on iCloud Drive

Keep the processing process on your local drive, not on the iCloud Drive. This is because if you create, modify and delete a lot of files very rapidly with Python, the iCloud system can get out of sync., and permanently screw your iCloud system up. I speak from bitter experience.

This is the directory structure for the scripts:

/input/quarto_template/ The base Quarto site
/input/raw_markdown/ The Bear export
/processing/processed_markdown/ The Bear Markdown after processing
/processing/quarto_combined/ The processed Markdown combined with the base Quarto site
/output/ The output of the Quarto render

Scripts

I have a simple master script that accepts the website name and then calls each of these scripts in turn.

There is no reason why all these scripts need to be in Python. Quite a few could be replaced with one-line shell commands.

1 Make Raw Markdown Dir

Renames the folder exported by Bear to raw_markdown in the input directory.

2 Tidy Up Previous Run

Deletes the contents of the processing directory.

3 Copy Source To Dest

Copies files from the input/raw_markdown directory to the processing/processed_markdown directory

4 Rename Files And Folders

Loops through all the .md files in the processing/processed_markdown directory and:

  • Ignores files already named index.md — these are the listing pages on my site.
  • With the other files, Bear App creates a .md file name based on the title of the note, as well as a subdirectory with the same name. I don’t like this as I prefer files to be named index so that URLs are clean and without html file names. So I copy the .md file to the subdirectory (if it exists, create it if it doesn’t), and rename it index.md.

5 Subfolder Dashes

Bear exports markdown file and directory names which include spaces and non-URL friendly characters. Script recursively renames subdirectories changing spaces to dashes, and removing invalid characters.

6 Search And Replace

This script does a search and replace on all the Markdown files, making changes to the Bear markdown to make it compatible with Quarto. Specifically, it:

  • Removes the nested tags I use for organizing content in Bear (the organization is already reflected in the exported directory structure).
  • Removes any instances of `` — these are Quarto listing pages, the titles are defined in the YAML.
  • Replaces {“width":NUMBER} with {width=NUMBER}, so I can resize images in Bear and they will appear the correct size in Quarto.
  • Replaces the code Bear export for highlights to HTML <mark> tags, with the correct coloring.
  • Changes links to PDFs to embeds.
  • Removes the directory path from the image path, since the linking note has moved into the directory containing the image.

7 Process YAML Headers

This adds YAML front matter to all .md files that don’t have them, and modifies them if they do:

  • If no title exists, use the first header in the markdown.
  • If no date exists, use the first date in the markdown.
  • Add categories to the front matter, based on Bear tags in the Markdown. (To make parsing simpler, in Bear I put each tag on a separate line).
  • Removes the extracted title, date, and category lines

8 Add folder variables to the front matter

This adds the folder and subfolder names of the page to the YAML front matter. This means I can create listings based on the folder names. I also use this to create bespoke listings.

9 Rename .md To .qmd

Goes through all the files and simply renames .md files to .qmd (Quarto Markdown).

11 Short Paths

On some pages in Bear I add a variable short-path to the YAML front matter. This is so that I can have short paths for pages, rather than paths based on the title. This script renames the parent directory of for all notes with a short path, and then updates all internal links with the new path.

12 Create thumbnails

This script creates thumbnail images to be used in the listings. I say thumbnails but they are actually quite large — 720 pixels width. This is about twice the resolution of the display size, so on screens with retina displays the image should appear crisp.

The script uses the command line version of the Clop app. The lifetime licence is 15 USD and is well worth it. I use the app all the time. It performs the following operation on every poster image. I use the image variable in the front matter, this script updates the name to the thumbnail version. It writes the thumbnail a thumbnail folder in the input/quarto_template folder. This means that the script only creates the thumbnail once, and not every time the scripts are run (which would be very time consuming).

13 Combine To New Website

This script combines the content so the input/quarto_template and processing/processed_markdown directories into a new directory called processing/quarto_combined.

15 Render Quarto

This script looks through all the YAML front matter in the .qmd files. If the YAML contains this directive:

render: true

then that file is rendered using the Quarto render command.

If no files are found to render, the whole site is rendered.

16 View locally

This script runs a local webserver and displays the local version of the site, so that I can check any changes before publishing them.

17 Publish site

This updates the relevant GitHub repository, which automatically triggers CloudFlare to update the website. It makes just a few seconds.

Creating the scripts

Here is an example of a prompt with OpenAI GTP-4o to create the scripts:

I have a directory of markdown files to process. Each markdown file has a YAML header. We are going to be updating those YAML headers. 
Write a Python script using the click and yaml modules. 
Accept a command line argument, root_dir. 
DIRECTORY_TO_PROCESS = os.path.join(root_dir, "processing", "processed_markdown")
Loop through all subdirectories of DIRECTORY_TO_PROCESS  
For each index.md file, if the file is in a subdirectory of DIRECTORY_TO_PROCESS, add a key "folder" with the name of the folder, and if the file is in a sub-subdirectory of DIRECTORY_TO_PROCESS, add a key "subfolder" with the name of the subfolder.