masochist.git
3 weeks agochore: clean up Keybase references main master
Greg Hurrell [Wed, 27 Apr 2022 20:41:20 +0000 (22:41 +0200)] 
chore: clean up Keybase references

Closes: https://github.com/wincent/masochist/issues/191
7 weeks agochore: clean up stray '";' strings
Greg Hurrell [Sun, 27 Mar 2022 20:27:47 +0000 (22:27 +0200)] 
chore: clean up stray '";' strings

7 weeks agodocs: update broken hextrapolate.wincent.com links
Greg Hurrell [Sun, 27 Mar 2022 20:02:59 +0000 (22:02 +0200)] 
docs: update broken hextrapolate.wincent.com links

Seeing as the subdomain doesn't resolve any more, update to point at
hex.wincent.com instead.

2 months agochore: fix some more broken links
Greg Hurrell [Mon, 28 Feb 2022 22:43:59 +0000 (23:43 +0100)] 
chore: fix some more broken links

2 months agochore: fix some broken links
Greg Hurrell [Mon, 28 Feb 2022 22:35:34 +0000 (23:35 +0100)] 
chore: fix some broken links

4 months agochore: ignore "next/" worktree
Greg Hurrell [Sat, 15 Jan 2022 14:06:07 +0000 (15:06 +0100)] 
chore: ignore "next/" worktree

Don't want to see noise that results from:

    git worktree add next upstream/next

4 months agorefactor: use `overflow-wrap: break-word` more extensively
Greg Hurrell [Sat, 8 Jan 2022 21:28:35 +0000 (22:28 +0100)] 
refactor: use `overflow-wrap: break-word` more extensively

Is this a good idea? This question was asked here:

    https://twitter.com/adamwathan/status/1317915868483956738

and the consensus seems to be it's a bad idea, but only for some
non-English languages, and all my content is in English.

This will stop pages like:

    https://wincent.com/wiki/macOS_%22must_haves%22

which have long URLs visible inside `a` tags from looking like crap on
mobile (where they overflow the width and make the page too wide,
creating a horizontal scroll).

4 months agochore: remove stale package from cache
Greg Hurrell [Sat, 8 Jan 2022 21:17:55 +0000 (22:17 +0100)] 
chore: remove stale package from cache

5 months agorefactor: tweak navbar background to be not so deeply black
Greg Hurrell [Fri, 17 Dec 2021 20:48:27 +0000 (21:48 +0100)] 
refactor: tweak navbar background to be not so deeply black

Full black can be a bit too intense.

5 months agochore: switch license to MIT
Greg Hurrell [Thu, 16 Dec 2021 08:11:34 +0000 (09:11 +0100)] 
chore: switch license to MIT

Had only been using CC-BY-NC-SA-4 because Corporate Overlords at
previous job had recommended it for use in personal projects. Left there
some years ago, and MIT is a better fit in the JS ecosystem.

Closes: https://github.com/wincent/masochist/issues/181
5 months agofeat: implement retry/reconnect on Redis client
Greg Hurrell [Mon, 13 Dec 2021 22:16:17 +0000 (23:16 +0100)] 
feat: implement retry/reconnect on Redis client

At the moment I am just catching the two most obvious possible errors;
EPIPE and ECONNREFUSED, but the truth is there are others that might
conceivably occur — from:

    https://www.columbia.edu/sec/acis/db2/db2m0/db2tcp.htm

maybe ECONNRESET and ETIMEDOUT (even though Node sockets don't time out
by default) are obvious candidates... I might end up just doing a
blanket retry, too... not sure.

5 months agofeat: add --trace-warnings to `yarn start` (in dev)
Greg Hurrell [Mon, 13 Dec 2021 22:15:37 +0000 (23:15 +0100)] 
feat: add --trace-warnings to `yarn start` (in dev)

Useful for when I do things like leaking EventEmitters.

5 months agochore: remove express-graphql
Greg Hurrell [Mon, 13 Dec 2021 17:57:45 +0000 (18:57 +0100)] 
chore: remove express-graphql

I was only using it as a shortcut to getting GraphiQL in dev, but the
schema is basically "finished" at this point and I don't think I'm going
to need to troubleshoot it again (if I'm wrong about that, I can easily
revert this change). In the meantime, killing this is a small step
towards reducing the dependency footprint.

5 months agochore: remove stale comment
Greg Hurrell [Mon, 13 Dec 2021 17:53:20 +0000 (18:53 +0100)] 
chore: remove stale comment

Originally added in 375562c7dfb92691e6b32954be1d47a4e8550cfd ("Unbreak
webpack build", Nov 23, 2018). The problematic syntax was stripped out
in 7765e44d81c543c191a9deb78705a53885c29151 ("chore: remove unused Flow
types", Dec 12, 2021).

5 months agochore: remove dead code
Greg Hurrell [Sun, 12 Dec 2021 22:25:55 +0000 (23:25 +0100)] 
chore: remove dead code

I initially thought I might use these, which correspond to the commands
that I actually use, but in reality, I only use `get()`, and all the
others get used via `multi()`.

Now, when I start rewriting stuff in TypeScript, there will be some
value in having named methods like this, although I will probably want
to expose them on `multi()` like this:

    multi()
      .zrange(...)
      .zcard(...)
      .exec();

as opposed to calling them individually (but having said that, I kind of
like the way the array calling convention mirrors the array result, so I
might see how far I can get with static types using that approach...)

5 months agorefactor: prefer ZRANGE over ZREVRANGE
Greg Hurrell [Sun, 12 Dec 2021 22:22:32 +0000 (23:22 +0100)] 
refactor: prefer ZRANGE over ZREVRANGE

As noted here:

    https://redis.io/commands/zrevrange

> As per Redis 6.2.0, this command is considered **deprecated.** Please
> prefer using the ZRANGE command with the REV argument in new code.

(emphasis added)

5 months agochore: remove commented-out test code
Greg Hurrell [Sun, 12 Dec 2021 22:19:49 +0000 (23:19 +0100)] 
chore: remove commented-out test code

5 months agofix: adjust readIndex call in Tag model to work with new client
Greg Hurrell [Sun, 12 Dec 2021 22:11:19 +0000 (23:11 +0100)] 
fix: adjust readIndex call in Tag model to work with new client

So the old client returned an array with doubled rows, like:

   foo
   10
   bar
   5
   baz
   3
   ...

The new client returns proper arrays:

   [foo, 10]
   [bar, 5]
   [baz, 3]
   ...

I think the only place where this matters is in the tags index, because
it is the only place where we're using `WITHSCORES`.

5 months agofeat: do a better job of logging interesting errors
Greg Hurrell [Sun, 12 Dec 2021 14:13:16 +0000 (15:13 +0100)] 
feat: do a better job of logging interesting errors

Like the one fixed in the parent commit. That kind of bug would cause a
500 in the browser, but in the server's console out, nothing would be
logged.

5 months agofix: add back PropTypes import
Greg Hurrell [Sun, 12 Dec 2021 14:10:03 +0000 (15:10 +0100)] 
fix: add back PropTypes import

I was moving quickly and not paying attention, but I _think_ the LSP
told me this was unused so I just deleted it. Or perhaps I blew it away
by accident while trying to delete the comment right above it.

Whatever. This was causing 500 errors.

5 months agofix: don't leak event listeners
Greg Hurrell [Sun, 12 Dec 2021 13:55:26 +0000 (14:55 +0100)] 
fix: don't leak event listeners

Because we were setting up an `on('line')` listener for every command
we ran, we were leaking these quite badly. Wouldn't be a problem if
the clients were short-lived (because when the client is GC'd, the
emitter/listener would go away, because the emitter and the listeners
are all the same object), but the clients live for as long as the server
process runs.

5 months agochore: clean up additional Flow loose ends
Greg Hurrell [Sun, 12 Dec 2021 10:16:26 +0000 (11:16 +0100)] 
chore: clean up additional Flow loose ends

Some stuff that didn't get covered in the last commit, which I made
with:

    yarn global add flow-remove-types
    flow-remove-types --pretty src -d lib
    cp -R lib/* src/
    yarn run pretty

Then I backed out the changes to `**/__generated__/*` files.

Now I've swept through, cleaning up empty comments, removing lint
suppressions etc, as well as converting the `scripts/` directory that I
had neglected, and removing some type-only imports.

5 months agochore: remove unused Flow types
Greg Hurrell [Sun, 12 Dec 2021 10:09:57 +0000 (11:09 +0100)] 
chore: remove unused Flow types

I stopped using Flow a while ago, and have a pending ticket open for
porting to TypeScript[^1], and another in-progress rewrite anyway[^2]...
so for now these are mostly just noise (at best, you can consider them
as inline documentation that might go stale).

[^1]: https://github.com/wincent/masochist/issues/142
[^2]: https://github.com/wincent/masochist/issues/140 — although note
the ticket is nominally about updating the Relay version, which is way
behind, but which is tantamount to doing a full rewrite anyway because
so much is going to have to change.

5 months agorefactor: switch `then()` to use `async`/`await` instead
Greg Hurrell [Sun, 12 Dec 2021 09:55:16 +0000 (10:55 +0100)] 
refactor: switch `then()` to use `async`/`await` instead

Micro-refactoring that collapses 4 lines into 3 in a couple of places.

(Places, BTW, that I could DRY up by extracting out the common
functionality, but I don't won't to because the dumb and simple
duplicated version is easier to read.)

5 months agorefactor: turn lines into a property
Greg Hurrell [Sun, 12 Dec 2021 09:51:41 +0000 (10:51 +0100)] 
refactor: turn lines into a property

As all we ever do is pass it around unconditionally without changing it.
I originally had it as a param because I wasn't sure whether it was
going to be needed everywhere.

5 months agorefactor: rename parseResponse() to parse()
Greg Hurrell [Sun, 12 Dec 2021 09:48:24 +0000 (10:48 +0100)] 
refactor: rename parseResponse() to parse()

I only had it under a different name as an intermediate step while
preparing the parent commit.

5 months agorefactor: make redis client more robust
Greg Hurrell [Sat, 11 Dec 2021 23:36:57 +0000 (00:36 +0100)] 
refactor: make redis client more robust

I tried a few things here but eventually "settled" on this design; that
is to say, I wanted to make the async handling a bit more
robust/idiomatic, so I explored using an async generator, then switched
to using an async iterator. The problem should fix is that when we are
pipelining a bunch of commands and executing them with MULTI + EXEC, we
may get several data payloads back with the responses. In the parent
commit, I could run the little test case multiple times, and my MULTI
request would sometimes get 4 `undefined` responses, or 1, or none.

I think I've fixed that now, and just need to add in error handling
everywhere, but we don't actually expect too many errors as Redis should
pretty reliably return exactly what I'm asking it for.

How does this work? Basically, we want to be able to `await` one line at
a time until we've got everything we need, hence the async iterator.
This ended up being a bit more useful than the generator because we can
pass it around (eg. to parse bulk strings in a subroutine) or into a
recursive call (which we need in order to parse maps, sets, arrays etc).

5 months agochore: update some "safe" packages
Greg Hurrell [Fri, 10 Dec 2021 23:49:59 +0000 (00:49 +0100)] 
chore: update some "safe" packages

    yarn upgrade-interactive
    npx yarn-deduplicate yarn.lock
    yarn

After this, `yarn audit` reports:

    12 vulnerabilities found - Packages audited: 1166
    Severity: 2 Low | 4 Moderate | 6 High

5 months agorefactor: cut over to WIP Redis client
Greg Hurrell [Fri, 10 Dec 2021 23:36:11 +0000 (00:36 +0100)] 
refactor: cut over to WIP Redis client

As noted in parent commit, it has some problems, but it still works well
enough to render the blog index in the local development environment
(this is the only page I've tested so far, and I only tested it once, so
you _know_ this is good).

Split up big file into smaller files so that I can keep things tidy as I
slowly refactor this into something robust.

5 months agofeat: add more stuff to WIP redis client
Greg Hurrell [Fri, 10 Dec 2021 22:16:21 +0000 (23:16 +0100)] 
feat: add more stuff to WIP redis client

As noted from the TODOs inline, still lots of missing pieces, and it's
not totally robust. Oh, and also, it's ugly. But it is pretty much
"feature complete" at this point and just needs to be fixed up, cleaned
up, and redesigned a bit. Ha.

5 months agorefactor: add WIP replacement Redis client
Greg Hurrell [Thu, 9 Dec 2021 23:06:37 +0000 (00:06 +0100)] 
refactor: add WIP replacement Redis client

We only need to handle a tiny number of commands:

- GET

(used alone, and...)

- SET
- ZADD
- ZCARD
- ZINCRBY
- ZREM
- ZREMRANGEBYSCORE
- ZREVRANGE

(used in `multi` transactions).

So something crude like this is probably going to be enough. It is
definitely not going to be efficient, but the payloads we are talking
about here are miniscule, so it really won't matter.

Still to do:

- Implement error handling.
- Add `multi` support.
- Address missing features and "TODOs" noted inline (for example, we
  aren't bailing early if we get an incomplete response).
- Add reconnect.
- Maybe write some tests.

Adding this as a .txt file just to show that it's not intended for
actual execution yet, but I do want it in version control in case my
machine dies.

5 months agodocs: s/master/main in README.md
Greg Hurrell [Wed, 8 Dec 2021 23:40:05 +0000 (00:40 +0100)] 
docs: s/master/main in README.md

5 months agodocs: fix and clean-up some paths in README
Greg Hurrell [Wed, 8 Dec 2021 23:38:33 +0000 (00:38 +0100)] 
docs: fix and clean-up some paths in README

Backticks because they look nicer when rendered, and "var" isn't true
any more — it's "srv".

5 months agochore: empty commit for redeploy
Greg Hurrell [Wed, 8 Dec 2021 23:22:01 +0000 (00:22 +0100)] 
chore: empty commit for redeploy

Our post-receive hook was dying trying to run Gulp:

    remote: $ node_modules/.bin/gulp build
    remote: error: aborting due to non-zero exit status (127)

I just changed it to run `node build.js` instead, and now need to retry
deploying, hence this empty commit.

5 months agorefactor: replace Gulp with crude script
Greg Hurrell [Wed, 8 Dec 2021 23:16:36 +0000 (00:16 +0100)] 
refactor: replace Gulp with crude script

Script was coded up in haste so is probably riddled with bugs, but it
seems to do what Gulp did without the enormous dependency footprint.

`yarn audit` is a bit happier after this:

```
19 vulnerabilities found - Packages audited: 1167
Severity: 2 Low | 11 Moderate | 6 High
```

Previously, it was:

```
28 vulnerabilities found - Packages audited: 1416
Severity: 2 Low | 17 Moderate | 9 High
```

Most of the remaining issues are in the relay-compiler, of which I am
running a super-old version.

Closes: https://github.com/wincent/masochist/issues/177
5 months agofix: use correct name for license file
Greg Hurrell [Wed, 8 Dec 2021 23:14:42 +0000 (00:14 +0100)] 
fix: use correct name for license file

Instead of:

    [object Object].LICENSE.txt

generate something like:

    bundle-81f9425e983ef01950a9.mjs.LICENSE.txt

5 months agochore: remove unused Flow file
Greg Hurrell [Wed, 8 Dec 2021 23:14:21 +0000 (00:14 +0100)] 
chore: remove unused Flow file

5 months agorefactor: improve contrast in footer area
Greg Hurrell [Wed, 8 Dec 2021 18:50:28 +0000 (19:50 +0100)] 
refactor: improve contrast in footer area

5 months agochore: clean up stray packages
Greg Hurrell [Wed, 8 Dec 2021 18:17:34 +0000 (19:17 +0100)] 
chore: clean up stray packages

Just by running `yarn`.

5 months agochore: run `npx yarn-deduplicate yarn.lock`
Greg Hurrell [Wed, 8 Dec 2021 18:17:17 +0000 (19:17 +0100)] 
chore: run `npx yarn-deduplicate yarn.lock`

5 months agochore: back out redis "upgrade"
Greg Hurrell [Wed, 8 Dec 2021 18:13:54 +0000 (19:13 +0100)] 
chore: back out redis "upgrade"

Because it's not worth it.

The `ZREVRANGE` command is not implemented, which breaks things for us.

Note that we can get the same with `ZRANGE` and passing a `REV` option:

    https://github.com/redis/node-redis/issues/1705

but that still leaves headaches elsewhere, where we were using
`ZREVRANGE` with the `WITHSCORES` option. This isn't supported by the
npm package, even though Redis itself supports it:

    https://redis.io/commands/zrange

The suggestion is to switch overt to `ZRANGEBYSCORE` instead, but that
is starting to sound awfully like a hassle.

5 months agorefactor: switch multi invocation to v4 style
Greg Hurrell [Wed, 8 Dec 2021 17:57:53 +0000 (18:57 +0100)] 
refactor: switch multi invocation to v4 style

As documented here:

    https://github.com/redis/node-redis

But here's the interesting thing about it — it doesn't work for all
Redis commands. So, for example, we can hit a blog permalink page just
fine but not a page using a reverse-sorted index, like the blog index
page.

This shows up as a server crash:

    TypeError: Cannot read property 'posts' of null
        at PostsIndex.render (/Users/wincent/code/masochist/src/client/components/PostsIndex.js:64:35)

Dicking around in the console I established that the API works for some
commands but not others; for example, `ZREVRANGE` is missing, but
`ZCARD` is not:

    in loop ZREVRANGE masochist:6:blog-index [ 0, 2 ]
    command undefined
    in loop ZCARD masochist:6:blog-index []
    command [Function (anonymous)]

So, if I can't find a way to work around this I may just have to
"downgrade" (that is, "upgrade") to the previously working version of
the software.

5 months agoRevert "chore: revert to state as of 447b2a875"
Greg Hurrell [Wed, 8 Dec 2021 16:55:09 +0000 (17:55 +0100)] 
Revert "chore: revert to state as of 447b2a875"

Now that I've got the production site back up by "rolling back" to the
prior rev, I'm doing this revert (to the bad rev) in the hope of
reproducing locally and finding out what's going on.

This reverts commit 43dee176285d111227a31634425188d91f4a29c2.

5 months agochore: revert to state as of 447b2a875
Greg Hurrell [Wed, 8 Dec 2021 16:52:00 +0000 (17:52 +0100)] 
chore: revert to state as of 447b2a875

This reverts the last 13 commits because something isn't liking the
changes in prod, where the server serves up the top part of the document
and then nothing.

"Rolling back" in order to do some troubleshooting.

5 months agochore: bump graphql-relay v0.6.0 to v0.7.0
Greg Hurrell [Wed, 8 Dec 2021 16:39:58 +0000 (17:39 +0100)] 
chore: bump graphql-relay v0.6.0 to v0.7.0

To get rid of the duplicate prettier version it was bringing in to the
graph.

5 months agochore: update Prettier
Greg Hurrell [Wed, 8 Dec 2021 16:34:20 +0000 (17:34 +0100)] 
chore: update Prettier

Although note that we still have an old duplicate copy lying around
because:

    => Found "graphql-relay#prettier@1.19.1"
    info This module exists because "graphql-relay" depends on it.

I don't know/recall why it has it as a non-dev dependency; all its other
deps are under `devDependencies`... looking, seems it is unintended and
was fixed in:

    https://github.com/graphql/graphql-relay-js/commit/0155159f2276fa4c2b194ddfefc85145d9329c2e

but there are too many breaking changes for me to feel all that
enthusiastic about moving from 0.6.0 to the current release (0.9.0):

    https://github.com/graphql/graphql-relay-js/releases

although admittedly, we could get that fix by going just to v0.7.0, I
think, which does look relatively safe. I might try that in the next
commit.

5 months agochore: update sinon package too
Greg Hurrell [Wed, 8 Dec 2021 16:31:28 +0000 (17:31 +0100)] 
chore: update sinon package too

Another safe upgrade; `yarn test` still green.

If only getting rid of Gulp were so easy... *sigh*

5 months agochore: update some more (hopefully safe) packages
Greg Hurrell [Wed, 8 Dec 2021 16:16:53 +0000 (17:16 +0100)] 
chore: update some more (hopefully safe) packages

The redis update requires some shenanigans to get around breaking
changes:

    https://github.com/redis/node-redis/blob/HEAD/docs/v3-to-v4.md

5 months agochore: update webpack-dev-server
Greg Hurrell [Wed, 8 Dec 2021 16:04:38 +0000 (17:04 +0100)] 
chore: update webpack-dev-server

Note that I had to go through a few tweak-restart loops to flush out all
the problems:

    ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
     - options has an unknown property 'noInfo'. These properties are valid:

    ValidationError: Invalid options object. Dev Server has been initialized using an options object that does not match the API schema.
    - options has an unknown property 'publicPath'. These properties are valid:

    (node:46306) [DEP_WEBPACK_DEV_SERVER_CONSTRUCTOR] DeprecationWarning: Using 'compiler' as the first argument is deprecated. Please use 'options' as the first argument and 'compiler' as the second argument.

    (node:46332) [DEP_WEBPACK_DEV_SERVER_LISTEN] DeprecationWarning: 'listen' is deprecated. Please use async 'start' or 'startCallback' methods.

    <w> [webpack-dev-server] "hot: true" automatically applies HMR plugin, you don't have to add it manually to your webpack configuration.

5 months agochore: clean up lockfile and straggling packages
Greg Hurrell [Wed, 8 Dec 2021 16:01:06 +0000 (17:01 +0100)] 
chore: clean up lockfile and straggling packages

This is the diff produced by running just `yarn` alone.

5 months agochore: run `npx yarn-deduplicate yarn.lock`
Greg Hurrell [Wed, 8 Dec 2021 16:00:48 +0000 (17:00 +0100)] 
chore: run `npx yarn-deduplicate yarn.lock`

5 months agochore: update more packages
Greg Hurrell [Wed, 8 Dec 2021 16:00:21 +0000 (17:00 +0100)] 
chore: update more packages

I think this covers all of the "safe" ones.

5 months agochore: update some more webpack-ish deps
Greg Hurrell [Wed, 8 Dec 2021 15:42:20 +0000 (16:42 +0100)] 
chore: update some more webpack-ish deps

Most of these without a hitch, except for terser-webpack-plugin, which
was causing:

    - options has an unknown property 'sourceMap'. These properties are valid:
      object { test?, include?, exclude?, terserOptions?, extractComments?, parallel?, minify? }

So, I just removed the option. According to the changelog:

    https://github.com/webpack-contrib/terser-webpack-plugin/blob/master/CHANGELOG.md

in version v5.0.0 they dropped it:

> removed the `sourceMap` option (respect the `devtool` option by default)

5 months agorefactor: use "Asset Modules" in lieu of url-loader
Greg Hurrell [Wed, 8 Dec 2021 15:32:43 +0000 (16:32 +0100)] 
refactor: use "Asset Modules" in lieu of url-loader

See: https://webpack.js.org/guides/asset-modules/

5 months agochore: update to webpack
Greg Hurrell [Wed, 8 Dec 2021 15:07:45 +0000 (16:07 +0100)] 
chore: update to webpack

This is the minimal set of changes specified in:

    https://webpack.js.org/migrate/5/

with tweaks to make `yarn start` and `yarn build` complete without
errors.

Note I had to get rid of the `!` chaining syntax, as noted here:

    Error: Compiling RuleSet failed: Exclamation mark separated
    loader lists has been removed in favor of the 'use'
    property with arrays (at ruleSet[1].rules[2].loader:
    style-loader!css-loader!postcss-loader)

`yarn build` spews out a lot of deprecation notices and other warnings
(edited for readability):

    (node:33331) [DEP_WEBPACK_MAIN_TEMPLATE_RENDER_MANIFEST] DeprecationWarning: MainTemplate.hooks.renderManifest is deprecated (use Compilation.hooks.renderManifest instead)
    (Use `node --trace-deprecation ...` to show where the warning was created)
    (node:33331) [DEP_WEBPACK_CHUNK_TEMPLATE_RENDER_MANIFEST] DeprecationWarning: ChunkTemplate.hooks.renderManifest is deprecated (use Compilation.hooks.renderManifest instead)
    (node:33331) [DEP_WEBPACK_MAIN_TEMPLATE_HASH_FOR_CHUNK] DeprecationWarning: MainTemplate.hooks.hashForChunk is deprecated (use JavascriptModulesPlugin.getCompilationHooks().chunkHash instead)
    (node:33331) [DEP_WEBPACK_COMPILATION_OPTIMIZE_CHUNK_ASSETS] DeprecationWarning: optimizeChunkAssets is deprecated (use Compilation.hooks.processAssets instead and use one of Compilation.PROCESS_ASSETS_STAGE_* as stage option)
    (node:33331) [DEP_WEBPACK_COMPILATION_NORMAL_MODULE_LOADER_HOOK] DeprecationWarning: Compilation.hooks.normalModuleLoader was moved to NormalModule.getCompilationHooks(compilation).loader
    [16:06:38] Finished 'graphql' after 2.18 s
    (node:33331) [DEP_WEBPACK_COMPILATION_ASSETS] DeprecationWarning: Compilation.assets will be frozen in future, all modifications are deprecated.
    BREAKING CHANGE: No more changes should happen to Compilation.assets after sealing the Compilation.
            Do changes to assets earlier, e. g. in Compilation.hooks.processAssets.
            Make sure to select an appropriate stage from Compilation.PROCESS_ASSETS_STAGE_*.
    (node:33331) [DEP_WEBPACK_MODULE_ID] DeprecationWarning: Module.id: Use new ChunkGraph API
    (node:33331) [DEP_WEBPACK_MODULE_UPDATE_HASH] DeprecationWarning: Module.updateHash: Use new ChunkGraph API
    (node:33331) [DEP_WEBPACK_CHUNK_MODULES_ITERABLE] DeprecationWarning: Chunk.modulesIterable: Use new ChunkGraph API
    (node:33331) [DEP_WEBPACK_CHUNK_GROUP_GET_MODULE_INDEX_2] DeprecationWarning: ChunkGroup.getModuleIndex2 was renamed to getModulePostOrderIndex
    (node:33331) [DEP_WEBPACK_COMPILATION_CACHE] DeprecationWarning: Compilation.cache was removed in favor of Compilation.getCache()

    WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
    This can impact web performance.
    Assets:
      bundle-45d526449584b2234f04.js (525 KiB)

    WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
    Entrypoints:
      main (541 KiB)
          styles-a5a8105f24841352a5be.css
          bundle-45d526449584b2234f04.js

    WARNING in webpack performance recommendations:
    You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
    For more info visit https://webpack.js.org/guides/code-splitting/

    WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
    Entrypoints:
      main (425 KiB)
          styles-a5a8105f24841352a5be.css
          bundle-8ff3e30a9a2750cb82ed.mjs

    WARNING in webpack performance recommendations:
    You can limit the size of your bundles by using import() or require.ensure to lazy load some parts of your application.
    For more info visit https://webpack.js.org/guides/code-splitting/

5 months agochore: update webpack to latest v4 version
Greg Hurrell [Wed, 8 Dec 2021 14:52:44 +0000 (15:52 +0100)] 
chore: update webpack to latest v4 version

Because this is the first step in the migration to v5:

    https://webpack.js.org/migrate/5/

`yarn start` still works after this, as does `yarn build`.

5 months agochore: update some CSS dependencies
Greg Hurrell [Wed, 8 Dec 2021 14:33:44 +0000 (15:33 +0100)] 
chore: update some CSS dependencies

To avoid this deprecation warning caused by a transitive dep,
es-abstract, as seen on the machine I'm currently on, which happens to
have NodeJS v16.8.0:

    (node:25719) [DEP0148] DeprecationWarning: Use of deprecated folder mapping "./" in the "exports" field module resolution of the package at $HOME/code/masochist/node_modules/es-abstract/package.json.
    Update this package.json to use a subpath pattern like "./*".
        at emitFolderMapDeprecation (node:internal/modules/esm/resolve:88:11)
        at packageExportsResolve (node:internal/modules/esm/resolve:648:7)
        at resolveExports (node:internal/modules/cjs/loader:482:36)
        at Function.Module._findPath (node:internal/modules/cjs/loader:522:31)
        at Function.Module._resolveFilename (node:internal/modules/cjs/loader:919:27)
        at Function.Module._load (node:internal/modules/cjs/loader:778:27)
        at Module.require (node:internal/modules/cjs/loader:1005:19)
        at require (node:internal/modules/cjs/helpers:94:18)
        at Object.<anonymous> ($HOME/code/masochist/node_modules/object.values/implementation.js:3:10)
        at Module._compile (node:internal/modules/cjs/loader:1101:14)

So, updated cssnano from 4.1.10 to 5.0.12, because that's the one that
was pulling in es-abstract. That, in turn, required a couple of other
updates. postcss got bumped to 8.4.4 (we still have some duplicate
divergent versions hiding away in various places though), as per `yarn
why postcss`:

    => Found "postcss@8.4.4"
    info Has been hoisted to "postcss"
    info This module exists because it's specified in "dependencies".
    => Found "css-loader#postcss@7.0.27"
    info This module exists because "css-loader" depends on it.
    => Found "autoprefixer#postcss@7.0.27"
    info This module exists because "autoprefixer" depends on it.
    => Found "icss-utils#postcss@7.0.27"
    info This module exists because "css-loader#icss-utils" depends on it.
    => Found "postcss-modules-local-by-default#postcss@7.0.27"
    info This module exists because "css-loader#postcss-modules-local-by-default" depends on it.
    => Found "postcss-modules-extract-imports#postcss@7.0.27"
    info This module exists because "css-loader#postcss-modules-extract-imports" depends on it.
    => Found "postcss-modules-scope#postcss@7.0.27"
    info This module exists because "css-loader#postcss-modules-scope" depends on it.
    => Found "postcss-modules-values#postcss@7.0.27"
    info This module exists because "css-loader#postcss-modules-values" depends on it.

and postcss-loader went from 3.0.0 to 4.2.0; I couldn't go all the way
to the latest (6.2.1), because that depends on webpack v5, and I'm on
v4:

    https://github.com/webpack-contrib/postcss-loader/blob/master/CHANGELOG.md

Other release notes:

    https://github.com/postcss/postcss/blob/main/CHANGELOG.md
    https://github.com/cssnano/cssnano/releases

I'll look at doing some more updates in separate commits, as these
things tend to be such a cluster that it is best to approach them
incrementally and check that things are still working along the way.

5 months agorefactor: change overflow-wrap from "anywhere" to "break-word"
Greg Hurrell [Sat, 4 Dec 2021 11:56:57 +0000 (12:56 +0100)] 
refactor: change overflow-wrap from "anywhere" to "break-word"

Because "anywhere" is considered an invalid value by Safari, which means
that long `<code>` spans in my blog posts look crap on iOS (even in
Chrome, which is really a thin skin over WebKit on iOS), causing
unwanted horizontal scrolling.

I think this should be adequate. Should work in Chrome and Firefox too.
As described in:

    https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-wrap

the difference is as follows:

> **normal**
> Lines may only break at normal word break points (such as a space
> between two words).
>
> **anywhere**
> To prevent overflow, an otherwise unbreakable string of characters
> — like a long word or URL — may be broken at any point if
> there are no otherwise-acceptable break points in the line. No
> hyphenation character is inserted at the break point. Soft wrap
> opportunities introduced by the word break are considered when
> calculating min-content intrinsic sizes.
>
> **break-word**
> The same as the anywhere value, with normally unbreakable words
> allowed to be broken at arbitrary points if there are no otherwise
> acceptable break points in the line, but soft wrap opportunities
> introduced by the word break are NOT considered when calculating
> min-content intrinsic sizes.

Looking back over the history, I don't think I've tried this before.
See the output of `git log -Goverflow-wrap -p`, and specifically some
interesting commits like:

8d1b60d1aba6f21466e7562fc77aab37aec66516 ("fix: improve wrapping of
  code elements", Jul 9, 2021)
56bd364eb4e8cc4c33dfa70ef5f85dd051bf7fc9 ("fix: don't break words in
  <code> elements quite so aggressively", Jul 9, 2021)
bf8fbaa6647aa2386ccfd0d9ea60cb3800a37df1 ("refactor: don't abuse
  <code> element for styling tag lozenges", Jul 9, 2021)

Closes: https://github.com/wincent/masochist/issues/171
5 months agochore: freshen yarn.lock
Greg Hurrell [Sat, 4 Dec 2021 01:11:04 +0000 (02:11 +0100)] 
chore: freshen yarn.lock

Just ran `yarn` to make sure it is in "canonical form".

5 months agochore: remove duplication from yarn.lock
Greg Hurrell [Sat, 4 Dec 2021 01:09:58 +0000 (02:09 +0100)] 
chore: remove duplication from yarn.lock

With:

    npx yarn-deduplicate yarn.lock

Has the side-effect of improving the `yarn audit` count a bit:

    54 vulnerabilities found - Packages audited: 1581
    Severity: 3 Low | 31 Moderate | 20 High

5 months agochore: update jest 25.1.0 → 27.4.3
Greg Hurrell [Sat, 4 Dec 2021 01:07:28 +0000 (02:07 +0100)] 
chore: update jest 25.1.0 → 27.4.3

Busy work to make `yarn audit` less upset. But still upset.

Before:

    106 vulnerabilities found - Packages audited: 1592
    Severity: 3 Low | 77 Moderate | 26 High

After:

    65 vulnerabilities found - Packages audited: 1666
    Severity: 3 Low | 42 Moderate | 20 High

Note that I also needed to provide a `fail` function to avoid:

    ReferenceError: fail is not defined

5 months agofix: don't undo browser scroll-to-anchor actions
Greg Hurrell [Sat, 4 Dec 2021 00:24:42 +0000 (01:24 +0100)] 
fix: don't undo browser scroll-to-anchor actions

Seeing as I just added footnotes, I'm noticing the brokenness here.

5 months agochore: update React 16.13.0 → 17.0.2
Greg Hurrell [Fri, 3 Dec 2021 23:51:49 +0000 (00:51 +0100)] 
chore: update React 16.13.0 → 17.0.2

Was hoping this would fix some bugs I'm seeing around how click events
are handled (specifically, jump to and back from footnotes is only
working on the first click, or when JS is disabled), but it didn't.
Doesn't hurt to update though, as far as I can tell, so may as well keep
the change.

5 months agorefactor: start using CSS custom properties
Greg Hurrell [Fri, 3 Dec 2021 21:33:40 +0000 (22:33 +0100)] 
refactor: start using CSS custom properties

The copy-pasted hex values have long been getting on my nerves. There
are still lots of hard-coded values to be migrated, but I just want to
port a few to serve as a reminder of the direction I want to head in.

5 months agofeat: highlight footnote when it is active
Greg Hurrell [Fri, 3 Dec 2021 21:21:22 +0000 (22:21 +0100)] 
feat: highlight footnote when it is active

5 months agofeat: add support for footnotes
Greg Hurrell [Fri, 3 Dec 2021 20:37:18 +0000 (21:37 +0100)] 
feat: add support for footnotes

Now that GitHub supports footnotes, I find myself in the habit of using
them there pretty often and therefore wanting to use them here too.

I am not sure if I am fully sold on the design here, but I'm passing in
a DOM identifier so that the `id` attributes in the generated markup can
be unique. One question, for example, is should this field be nullable?
Another is is "DOMIdentifier" the right name? (I wanted to avoid
confusion with GraphQL "id" fields.) Should I be doing more with these
IDs, like using them on title anchor tags? (probably not). Should I
tighten up the schema documentation, where it misleadingly talks of
"prefix"? (As you can see from the link below, the "DOMIdentifier" ends
up being embedded somewhere in the middle of an ID.)

Anyway, all this is possible by setting `docId`, which you can see being
used to construct the anchor names here:

    https://github.com/markdown-it/markdown-it-footnote/blob/337dcc79dfe8b2cb98c32000d8b24691de66105b/index.js#L13

Possible follow-ups: want to check the contrast levels for accessibility
because I eye-balled these and they are probably horrible. May in
general want to do a pass on the styles to make sure they look as pretty
as they should be.

5 months agodocs: drop references to `npm`
Greg Hurrell [Fri, 3 Dec 2021 18:00:25 +0000 (19:00 +0100)] 
docs: drop references to `npm`

Just to reduce clutter. People can probably figure out that wherever
they see `yarn` they could probably use `npm` instead.

5 months agodocs: provide suggestion for how to install prerequisites
Greg Hurrell [Fri, 3 Dec 2021 18:00:09 +0000 (19:00 +0100)] 
docs: provide suggestion for how to install prerequisites

5 months agodocs: remove stale line from README
Greg Hurrell [Fri, 3 Dec 2021 17:51:58 +0000 (18:51 +0100)] 
docs: remove stale line from README

6 months agofix: repair some mangled redirects
Greg Hurrell [Sun, 24 Oct 2021 12:01:32 +0000 (14:01 +0200)] 
fix: repair some mangled redirects

10 months agofix: use "bash" not "shell" for "sh" markup
Greg Hurrell [Fri, 9 Jul 2021 12:18:22 +0000 (14:18 +0200)] 
fix: use "bash" not "shell" for "sh" markup

Turns out that "bash" is for scripts and "shell" is for "shell
sessions".

So you want stuff like this for bash:

    ```bash
    echo "hi"
    ```

And stuff like this for sessions:

    ```shell
    $ sudo -s
    Password:
    # ls
    foo
    ```

Supposedly, "zsh" and "sh" are aliases for "bash", but in my testing, I
can't really see what "sh" actually does.

10 months agorefactor: avoid highlight.js deprecation warning
Greg Hurrell [Fri, 9 Jul 2021 12:01:38 +0000 (14:01 +0200)] 
refactor: avoid highlight.js deprecation warning

    Deprecated as of 10.7.0. highlight(lang, code, ...args) has been deprecated.
    Deprecated as of 10.7.0. Please use highlight(code, options) instead.
    https://github.com/highlightjs/highlight.js/issues/2277

10 months agorefactor: don't abuse <code> element for styling tag lozenges
Greg Hurrell [Fri, 9 Jul 2021 11:36:34 +0000 (13:36 +0200)] 
refactor: don't abuse <code> element for styling tag lozenges

10 months agochore: update highlight.js
Greg Hurrell [Fri, 9 Jul 2021 09:56:38 +0000 (11:56 +0200)] 
chore: update highlight.js

A scary update, but I actually think it's going to be ok:

- https://github.com/highlightjs/highlight.js/releases/tag/10.0.0
- https://github.com/highlightjs/highlight.js/releases/tag/11.0.0
- https://github.com/highlightjs/highlight.js/blob/main/VERSION_11_UPGRADE.md

10 months agochore: remove unused extract-text-webpack-plugin
Greg Hurrell [Fri, 9 Jul 2021 09:48:25 +0000 (11:48 +0200)] 
chore: remove unused extract-text-webpack-plugin

Unused since ba7fdb914c16bca7e0ce062 ("Make ES modules bundle as well",
Dec 16, 2018) and deprecated to boot:

    https://github.com/webpack-contrib/extract-text-webpack-plugin

10 months agochore: clean lockfile
Greg Hurrell [Fri, 9 Jul 2021 09:36:39 +0000 (11:36 +0200)] 
chore: clean lockfile

By running `yarn`. It always seems to want to make changes after
`yarn-deduplicate` has run. As you can see, it also removed a bunch of
dead(?) pages from the cache.

10 months agochore: deduplicate yarn.lock
Greg Hurrell [Fri, 9 Jul 2021 09:35:49 +0000 (11:35 +0200)] 
chore: deduplicate yarn.lock

With `npx yarn-deduplicate yarn.lock`.

10 months agorefactor: relax version ranges in package.json
Greg Hurrell [Fri, 9 Jul 2021 09:32:23 +0000 (11:32 +0200)] 
refactor: relax version ranges in package.json

10 months agochore: update markdown-it
Greg Hurrell [Fri, 9 Jul 2021 09:30:04 +0000 (11:30 +0200)] 
chore: update markdown-it

10 months agofix: don't break words in <code> elements quite so aggressively
Greg Hurrell [Fri, 9 Jul 2021 09:27:23 +0000 (11:27 +0200)] 
fix: don't break words in <code> elements quite so aggressively

The recent addition of `overflow-wrap: anywhere` was breaking my lovely
tag lozenges, which probably shouldn't be using `<code>` anyway because
they aren't code...

10 months agofix: remove unwanted bold styling
Greg Hurrell [Thu, 8 Jul 2021 23:34:06 +0000 (01:34 +0200)] 
fix: remove unwanted bold styling

Whoops, like I said in my last commit:

> Also experimented with bold but it is too heavyweight for my taste.

Somehow I managed to commit the unwanted change though...

10 months agofix: improve wrapping of code elements
Greg Hurrell [Thu, 8 Jul 2021 23:28:52 +0000 (01:28 +0200)] 
fix: improve wrapping of code elements

Chrome seems pretty flaky with `box-decoration-break`. ie. in order to
see the difference between "clone" and "slice" I need to toggle the
border on and off again. Whatever; I think the wrapped spans look better
without borders or rounded corners anyway, so removing those. Also
experimented with bold but it is too heavyweight for my taste.

10 months agorefactor: point at new location for content repo
Greg Hurrell [Tue, 6 Jul 2021 20:41:31 +0000 (22:41 +0200)] 
refactor: point at new location for content repo

10 months agofix: update npm packages
Greg Hurrell [Tue, 6 Jul 2021 17:50:51 +0000 (19:50 +0200)] 
fix: update npm packages

On new machine, we have a newer NodeJS, so we're running into this:

    Error: Cannot find module '$path_to/@babel/compat-data/data/corejs3-shipped-proposals'

Which I think is the issue described here:

    https://github.com/nodejs/node/issues/32852

and fixed here:

    https://github.com/babel/babel/pull/11283

I just ran `yarn upgrade-interactive` and updated all the packages which
looked safe-ish.

10 months agochore: freshen stale vendor/yarn-cache
Greg Hurrell [Tue, 6 Jul 2021 17:38:14 +0000 (19:38 +0200)] 
chore: freshen stale vendor/yarn-cache

Not sure how this got stale, but it is. On trying to deploy to a new EC2
machine, got:

    error Can't make a request in offline mode
    ("https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz")

So, freshening the cache by running `yarn`.

11 months agofix: remove bad index.php
Greg Hurrell [Sun, 13 Jun 2021 21:17:15 +0000 (23:17 +0200)] 
fix: remove bad index.php

Whoops. I had this formerly harmless file in here, but when we added
`index.php` to our nginx `try_files` directive, it started getting
served up to visitors hitting the root. :facepalm:

So let's kill it, and if anybody goes to https://wincent.com/index.php
they'll just get a 404, which is fine.

11 months agofix: mend some broken image resources
Greg Hurrell [Sun, 13 Jun 2021 00:51:27 +0000 (02:51 +0200)] 
fix: mend some broken image resources

11 months agostyle: prettify static HTML files
Greg Hurrell [Sat, 12 Jun 2021 23:55:42 +0000 (01:55 +0200)] 
style: prettify static HTML files

With:

    npx prettier --write "**/*.{html,php}" --parser html

11 months agorefactor: clean up links
Greg Hurrell [Sat, 12 Jun 2021 23:50:23 +0000 (01:50 +0200)] 
refactor: clean up links

Motivation is to avoid broken images caused by CSP violations (eg.
images hosted on www from non-www pages), but there are too many files
to do this in a non-automated way so this is just the dumbest of dumb
changes:

    find ./ -type f -exec gsed -i -e 's/www.wincent.com/wincent.com/g' {} \;
    find . -type f -exec gsed -i -e 's/secure.wincent.com/wincent.com/g' {} \;
    find . -type f -exec gsed -i -e 's#http://wincent.com#https://wincent.com#g' {} \;

11 months agochore: add some static files from old hosts
Greg Hurrell [Sat, 12 Jun 2021 22:17:25 +0000 (00:17 +0200)] 
chore: add some static files from old hosts

I want to "decommission" the hosts running at www.wincent.com and
secure.wincent.com without breaking any links, if I can help it. They
contain a bunch of PHP pages that do some very simple stuff like
composing a header and a footer and so on. There are only two (basically
dead) pages that handle POST requests.

So, I made this simple Ruby script that runs on the hosts and `curl`s
the pages (and other resources), taking a snapshot of everything. I
normally don't like leaking internal paths like this, but like I said,
the machines are going off the net forever shortly, so it's ok.

The directories that are guarded by .htaccess files all return 403s as
intended, so I haven't included those files in the dump.

As follow up I am going to have to tweak DNS records and SSL
certificates (SAN entries). But then I'll be able to kill off the old
servers.

    require 'fileutils'
    require 'shellwords'

    def escape(word)
      Shellwords.shellescape word
    end

    # Note: we don't have to worry about simlinks over here;
    # both directories contain only directories and regular files
    #
    #       find /var/www/secure.wincent.com/public_html -type l
    #       find /var/www/www.wincent.com/public_html -type l
    #
    %w[
      /var/www/secure.wincent.com/public_html
      /var/www/www.wincent.com/public_html
    ].each do |base|
      puts "Scraping from: #{base}"

      # Note that `Dir.[]` won't return dot-files, so we miss out on:
      #
      #       $ find /var/www/www.wincent.com/public_html -name '.*'
      #       /var/www/www.wincent.com/public_html/.well-known
      #
      # and:
      #
      #       $ find /var/www/secure.wincent.com/public_html -name '.*'
      #       /var/www/secure.wincent.com/public_html/a/products/install/licensees/binary-only/.htaccess
      #       /var/www/secure.wincent.com/public_html/a/products/install/licensees/full-source/.htaccess
      #       /var/www/secure.wincent.com/public_html/a/products/install/licensees/binary+framework/.htaccess
      #       /var/www/secure.wincent.com/public_html/a/products/install/licensees/.htaccess
      #       /var/www/secure.wincent.com/public_html/codegen/.htaccess
      #       /var/www/secure.wincent.com/public_html/.well-known
      #
      Dir["#{base}/**/*"].each do |source|
        host = "#{source}".split(%r{/})[3]
        path = "#{source}".split(%r{/})[5..-1].join('/')
        destination = File.join(__dir__, 'output', source)
        if File.file? source
          if system "curl --silent https://#{host}/#{escape path} -o #{escape destination}"
            puts " OK : #{host}/#{path}"
          else
            puts "FAIL: #{host}/#{path}"
          end
        else
          FileUtils.mkdir_p destination
        end
      end
    end

11 months agofeat: add direct link to "About" page from site footer
Greg Hurrell [Wed, 2 Jun 2021 21:29:16 +0000 (23:29 +0200)] 
feat: add direct link to "About" page from site footer

18 months agofeat: dim images a bit in dark mode
Greg Hurrell [Tue, 17 Nov 2020 23:08:12 +0000 (00:08 +0100)] 
feat: dim images a bit in dark mode

18 months agofeat: add dark mode
Greg Hurrell [Tue, 17 Nov 2020 22:58:05 +0000 (23:58 +0100)] 
feat: add dark mode

Just a primitive first pass at this.

19 months agofix: degrade "gracefully" for undefined Search result
Greg Hurrell [Thu, 15 Oct 2020 19:56:13 +0000 (21:56 +0200)] 
fix: degrade "gracefully" for undefined Search result

I don't have time now to dig into why we're getting `undefined` here,
but I can at least stop the app from crashing.

    TypeError: Cannot destructure property `search` of 'undefined' or 'null'.

20 months agorefactor: update Vim link in footer
Greg Hurrell [Thu, 17 Sep 2020 22:38:19 +0000 (00:38 +0200)] 
refactor: update Vim link in footer

21 months agoperf: add `loading="lazy"` attribute to images
Greg Hurrell [Fri, 7 Aug 2020 19:46:58 +0000 (21:46 +0200)] 
perf: add `loading="lazy"` attribute to images

See: https://web.dev/native-lazy-loading/

22 months agofix: use renderToNodeStream instead of renderToStaticNodeStream
Greg Hurrell [Sat, 4 Jul 2020 14:24:00 +0000 (16:24 +0200)] 
fix: use renderToNodeStream instead of renderToStaticNodeStream

As noted in the docs:

> Similar to `renderToNodeStream`, except this doesn't create extra DOM
> attributes that React uses internally, such as `data-reactroot`. This is
> useful if you want to use React as a simple static page generator, as
> stripping away the extra attributes can save some bytes.
>
> The HTML output by this stream is exactly equal to what
> `ReactDOMServer.renderToStaticMarkup` would return.
>
> If you plan to use React on the client to make the markup interactive,
> do not use this method. Instead, use `renderToNodeStream` on the server
> and `ReactDOM.hydrate()` on the client.

https://reactjs.org/docs/react-dom-server.html#rendertostaticnodestream

It was evidently working as-is, but best to stick to what it says in the
docs.

22 months agochore: avoid noisy core-js warnings on startup
Greg Hurrell [Fri, 3 Jul 2020 16:23:59 +0000 (18:23 +0200)] 
chore: avoid noisy core-js warnings on startup

Would move to v3, but for some reason it adds about 60K to the bundle.
Sticking with v2 for now, then.

23 months agofix: broken pagination
Greg Hurrell [Sun, 14 Jun 2020 17:52:49 +0000 (19:52 +0200)] 
fix: broken pagination

Caused due to mismatched variables between route and container query.
They fell out of sync due to incomplete update in 235bb8258793ff841e6.

Closes: https://github.com/wincent/masochist/issues/147
23 months agofix: avoid wrapping issues on external link icons
Greg Hurrell [Sat, 13 Jun 2020 15:57:25 +0000 (17:57 +0200)] 
fix: avoid wrapping issues on external link icons

Noticed on last blog post:

https://wincent.com/blog/on-the-right-to-disagree

That given DOM like this (as seen in inspector):

    "blah, "
    <a href="..." class="external">
      Something
      ::after
    </a>
    ", blah"

we were getting line break before the comma. This is because the icon
had `display: inline-block` in order to give it size, which causes it to
become untethered from the preceding text even though it is immediately
after it. Obviously very sensitive to text content, which is why I
hadn't seen it before.

As explained here:

https://stackoverflow.com/a/38418279/2103996

we can make leave the `display` of the :after pseudoelement as `inline`,
and use padding to give it size, margin to give it spacing.