Compare commits

..

1 Commits

Author SHA1 Message Date
Rin 2b93a43494 wip: font changes 2023-06-07 10:24:51 +10:00
16 changed files with 257 additions and 375 deletions

View File

@ -1,3 +1,92 @@
/* Example Font-Face Set-Up */
@font-face {
font-family: 'Majesty';
src: url('/fonts/Majesty/majesty-medium.otf');
weight: 600;
}
@font-face {
font-family: 'Majesty Display';
src: url('/fonts/Majesty/majesty-display.otf');
weight: 400;
}
@font-face {
font-family: 'Majesty Light';
src: url('/fonts/Majesty/majesty-light.otf');
weight: 200;
}
@font-face {
font-family: 'Quincy';
src: url('/fonts/Fontspring-DEMO-quincycf-regular.otf');
font-weight: normal;
}
@font-face {
font-family: 'Quincy';
src: url('/fonts/Fontspring-DEMO-quincycf-regularitalic.otf');
font-weight: normal;
font-style: italic, oblique;
}
@font-face {
font-family: 'Quincy';
src: url('/fonts/Fontspring-DEMO-quincycf-bolditalic.otf');
font-weight: bold;
font-style: italic, oblique;
}
@font-face {
font-family: 'Roxborough';
src: url('/fonts/Fontspring-DEMO-Calluna-Regular.otf');
font-weight: normal;
}
@font-face {
font-family: 'Roxborough';
src: url('/fonts/Fontspring-DEMO-Calluna-It.otf');
font-weight: normal;
font-style: italic;
}
@font-face {
font-family: 'Roxborough';
src: url('/fonts/Fontspring-DEMO-Calluna-SemiboldIt.otf');
font-weight: bold;
font-style: italic, oblique;
}
html {
line-height: 1.1;
/*font-family: 'Roxborough';*/
}
a {
font-family: 'Roxborough';
}
time, .reading-time, .word-count {
font-family: 'Roxborough';
}
h1 {
font-family: 'Roxborough';
}
h2, h3, h4, h5, h6 {
font-family: 'Roxborough';
}
p, article {
font-family: 'Roxborough';
}
.text {
font-family: 'Roxborough';
}
/* Max Content Width */
.max-w-prose {
max-width: 80ch;
@ -31,6 +120,11 @@
color: rgba(var(--color-primary-700),var(--tw-text-opacity));
}
.prose :where(code):not(:where([class~=not-prose] *)) {
font-weight: normal;
}
.dark .chroma .ow {
color: rgba(var(--color-primary-400),var(--tw-text-opacity));
}
@ -55,22 +149,12 @@
background-color: rgba(var(--color-neutral-100),var(--tw-bg-opacity));
}
/* Selection Text */
::selection {
background-color: rgba(var(--color-secondary-200), var(--tw-bg-opacity));
}
.dark ::selection {
background-color: rgba(var(--color-secondary-800), var(--tw-bg-opacity));
}
/* CheckBoxes and Radio Buttons */
[type=checkbox], [type=radio] {
color: rgba(var(--color-secondary-500),var(--tw-text-opacity));
}
/* Make transitions slightly longer for aesthetic */
/* TODO: This seems to have changed, reimpl */
body a, body button {
transition-duration: 250ms;
}

View File

@ -9,20 +9,20 @@
--color-neutral-400: 165, 177, 196; /* a5b1c4 */
--color-neutral-500: 126, 144, 170; /* 7e90aa */
--color-neutral-600: 103, 119, 142; /* 67778e */
--color-neutral-700: 76, 84, 102; /* 4c5666 */
--color-neutral-800: 61, 69, 82; /* 3d4552 */
--color-neutral-700: 76, 84, 102; /* 4c5666 */
--color-neutral-800: 61, 69, 82; /* 3d4552 */
--color-neutral-900: 40, 46, 53; /* 282e35 */
/* Violet */
--color-primary-50: 245, 243, 255; /* f5f3ff */
--color-primary-100: 237, 233, 254; /* ede9fe */
--color-primary-200: 221, 214, 254; /* ddd6fe */
--color-primary-300: 196, 181, 253; /* c4b5fd */
--color-primary-400: 167, 139, 250; /* a78bfa */
--color-primary-500: 139, 92, 246; /* 8b5cf6 */
--color-primary-600: 124, 58, 237; /* 7c3aed */
--color-primary-700: 93, 57, 149; /* 5d3995 */
--color-primary-800: 78, 48, 124; /* 4e307c */
--color-primary-900: 65, 41, 102; /* 412966 */
--color-primary-50: 245, 243, 255;
--color-primary-100: 237, 233, 254;
--color-primary-200: 221, 214, 254;
--color-primary-300: 196, 181, 253;
--color-primary-400: 167, 139, 250;
--color-primary-500: 139, 92, 246;
--color-primary-600: 124, 58, 237;
--color-primary-700: 93, 57, 149;
--color-primary-800: 78, 48, 124;
--color-primary-900: 65, 41, 102;
/* Cerise */
--color-secondary-50: 253, 252, 250; /* fdfcfa */
--color-secondary-100: 251, 240, 238; /* fbf0ee */

View File

@ -1,20 +1,18 @@
languages:
en:
languageCode: en
languageName: English
displayName: EN
isoCode: en
weight: 1
rtl: false
params:
title: "Rin"
# logo = "img/logo.png"
description: "As in 凛冽时雨"
copyright: "Copyright 2023 Rin (Tamara Vassileva) <br /> All opinions herein are our own
and not those of employers past, present, or potential.<br /> Icon courtesy of
[https://picrew.me/image_maker/41329/](https://picrew.me/image_maker/41329/)"
languageCode: en
languageName: English
displayName: EN
isoCode: en
weight: 1
rtl: false
dateFormat: "Mon Jan 2 2006"
title: "Rin"
# logo = "img/logo.png"
description: "As in 凛冽时雨"
copyright: "Copyright 2022 Rin (Tamara Vassileva) <br /> All opinions herein are our own
and not those of employers past, present, or potential. <br /> Icon courtesy of
[https://picrew.me/image_maker/41329/](https://picrew.me/image_maker/41329/)"
dateFormat: "Mon Jan 2 2006"
author:
name: "Rin"
@ -43,6 +41,7 @@ author:
# - kickstarter: 'https://www.kickstarter.com/profile/username'
# - lastfm: 'https://lastfm.com/user/username'
# - linkedin: 'https://linkedin.com/in/username'
- mastodon: 'https://tech.lgbt/@tammy'
- mastodon: 'https://social.treehouse.systems/@tammy'
# - medium: 'https://medium.com/username'
# - microsoft: 'https://www.microsoft.com/'

View File

@ -1,7 +1,7 @@
---
title: "Pay Transparency"
date: 2022-11-01T11:11:29+11:00
lastmod: 2023-12-06T18:45:00+11:00
lastmod: 2022-11-06T10:45:00+11:00
draft: false
summary: "This page lists every job we have ever held in tech, inspired by Xes salary transparency page."
showSummary: true
@ -17,14 +17,12 @@ follow suit, as the more data pay/salary data exists, the more others can reason
Data on this page is sourced from contracts, emails, and other communication with employers.
We do our best to ensure that this information is up-to-date and accurate.
| Position | Start Date | End Date | Salary | Benefits | How we left |
| ------------------------------------ | ----------- | ----------- | ----------- | ------------------------------------------------------------- | ----------------- |
| Network Engineer | 10-Mar-2017 | 08-May-2017 | 120 AUD/hr | None - Contract | Quit |
| Network Engineer | 10-May-2017 | 07-Aug-2021 | 80,000 AUD | {{< hover "Time Off In Lieu" >}}TOIL{{< /hover >}}for CRs | Quit |
| Senior Infrastructure Technical Lead | 08-Aug-2021 | 05-Aug-2022 | 100 AUD/hr | {{< hover "Time Off In Lieu" >}}TOIL{{< /hover >}}for On-Call | Hired Full-Time |
| Senior Infrastructure Technical Lead | 15-Aug-2022 | N/A | 140,000 AUD | {{< hover "Time Off In Lieu" >}}TOIL{{< /hover >}}for On-Call | Converted to Perm |
| Senior Infrastructure Technical Lead | 15-Aug-2023 | N/A | 162,000 AUD | {{< hover "Time Off In Lieu" >}}TOIL{{< /hover >}}for On-Call | Raise |
| Senior Infrastructure Technical Lead | 13-Dec-2023 | N/A | 166,663 AUD | {{< hover "Time Off In Lieu" >}}TOIL{{< /hover >}}for On-Call | N/A |
| Position | Start Date | End Date | Salary | Benefits | How we left |
| ------------------------------------ | ----------- | ----------- | ----------- | ---------------- | --------------- |
| Network Engineer | 10-Mar-2017 | 08-May-2017 | 120 AUD/hr | None - Contract | Quit |
| Network Engineer | 10-May-2017 | 07-Aug-2021 | 80,000 AUD | {{< hover "Time Off In Lieu" >}}TOIL{{< /hover >}}for CRs | Quit |
| Senior Infrastructure Technical Lead | 08-Aug-2021 | 05-Aug-2022 | 100 AUD/hr | {{< hover "Time Off In Lieu" >}}TOIL{{< /hover >}}for On-Call | Hired Full-Time |
| Senior Infrastructure Technical Lead | 15-Aug-2022 | N/A | 140,000 AUD | {{< hover "Time Off In Lieu" >}}TOIL{{< /hover >}}for On-Call | N/A |
## Updates
This page is typically updated whenever we:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

View File

@ -1,80 +0,0 @@
---
title: "iCalendar, Google Calendar, CalDAV, and friends"
date: 2023-06-19T19:19:19+10:00
draft: false
showSummary: true
summary: "Ever wondered if it's possible to link Calendar.app to a Google Suite Calendar that isn't your default account calendar? Let's find out!"
---
# Syncing GSuite Calendars to Calendar.app
## TL;DR
If you're just looking for a solution to syncing your GSuite Calendars to Calendar.app, go to [The Actual How-To]({{< relref "ical-and-google.md#the-actual-how-to" >}}).
## Background: CalDAV and friends
So before we get into this, it'll be useful to explain how online calendars work. You've probably seen calendar invites in your email before, and noticed that a lot of email providers also provide planning/calendar apps. The way this integration is done is via [CalDAV](https://en.wikipedia.org/wiki/CalDAV).
## What is CalDAV?
CalDAV, or Calendering Extensions for WebDAV, is a standard to allow for standardised events, tasks, and busy/free info to be shared and subscribed to. It structures data using the iCalendar format (not to be confused with the macOS app iCal, which uses this same format), and allows for sharing and subscription to calendars via an updated ics file, and can fall back to delivering updates via email (this is how Microsoft Exchange handles sending out event updates to external CalDAV servers, for example). Access can be public, or controlled via a multitude of authentication mechanisms, and ACLs are used to control whether a user can view events, free/busy information only, or edit/create/delete events.
## Authentication with CalDAV
CalDAV servers can allow for a myriad methods of authentication, including OAuth, Basic Auth, SAML, OIDC, and so on. This is where our issue comes in.
## The Problem
By default, Calendar.app *does* allow for the import of and syncing with Google Calendar accounts, however there exist several limitations:
1. You can only import the main calendar associated with your account. If you have several calendars, or are invited to another calendar that you want to sync to Calendar.app, this is not possible.
2. You can import the Calendar address as an arbitrary CalDAV endpoint, however the Google API only accepts OAuth requests, which Calendar.app doesn't know and will not open the flow for.
## How do we fix it?
We need some way to either force Calendar.app to open the OAuth flow, or get the google API to accept some other authentication mechanism. After fighting Calendar.app for a while, including some time in IDA, we found no easy (or hard) way to do this, so we turned our attention to making the Google CalDAV API behave.
After digging around the API Docs for a while, we discovered that there exists a legacy endpoint:
!["A screenshot showing that an \"old endpoint\" at https://google.com/calendar/dav exists, but is deprecated" !](gsuite-caldav-dep.png)
With a little more google-fu, we managed to find some old tutorials on syncing to the google CalDAV servers that use this deprecated endpoint.
If we put all that together, we can maybe clobber Calendar.app into syncing properly while also allowing you to have more than one calendar per Google account.
Some testing later, it turns out we were right!
## The Actual How-To
*Note: This has been tested on macOS 13.3.1(a) (22E772610a) with Apple Calendar 11.0 (2932.4.5).*
### Steps
1. Create an app password for Calendar from [My Account](https://myaccount.google.com) →
Security → 2-Step Verification → App passwords
2. Generate App password for Calendar. (Device type likely doesn't matter here, but we tested Mac)
3. In Apple Calendar, go to Calendar → Add Account → Other CalDAV Account
Account Type → Advanced:
* **User Name:** \<Google account email\>
* **Password:** \<App password from above\>
* **Server Address:** www.google.com
* **Server Path:** /calendar/dav/\<calid\>@group.calendar.google.com/user
* **Port:** 443
* **Use SSL:** [X]
4. Click "Sign In" and it should Just Work™!
### Notes
The `calid` value comes from Other calendars → Settings → Integrate calendar → Calendar ID.
This seemingly only works with the old www.google.com/calendar/dav endpoint, since the newer https://apidata.googleusercontent.com/caldav/v2 one requires OAuth, and the DataAccess.framework handling for CalDAV requests will only use OAuth for Google account types, and not generic CalDAV.
### Resources
* [Google CalDAV API Docs](https://developers.google.com/calendar/caldav/v2/guide)
* [CalDAV URL example for deprecated endpoint](https://www.davx5.com/tested-with/google)
* [App-password Docs](https://support.google.com/accounts/answer/185833?hl=en)
## The Caveats
Since this is a deprecated endpoint, this could stop working at any time, and [knowing Google](https://9to5google.com/2023/06/15/google-domains-squarespace), it really could be ANY TIME.
## Thanks
Massive thanks to arc and one alice, who did most of the legwork here, in between their knowledge of GSuite and macOS; we just did the write-up and background.

View File

@ -1,68 +0,0 @@
---
title: "Lies Programmers Believe About Names"
date: "2024-02-09T12:30:00+11:00"
draft: false
showSummary: true
summary: "Programmers tend to believe a lot of lies. Let's talk about some name-based ones."
---
# Introduction
> **(Ashe)** You ever read that classic list about [Falsehoods Programmers Believe About Time](https://gist.github.com/timvisee/fcda9bbdff88d45cc9061606b4b923ca)?
>
> **(Tammy)** Oh yeah, I remember that one!
>
> **(Ashe)** Well that *itself* is based on [Falsehoods Programmers Believe About Names](https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/).
>
> **(Tess)** Soooo, where's that leave us?
>
> **(Ashe)** Well it's been a little while since that post, and we've had our own *fun* experiences regarding names and IT systems, so we thought it might be fun to try extending that list.
> **(Ashe)** On that note, you may notice us restating some of the items in the above list. When we do so, we will try to provide slightly more precision or add some information that might not be obvious from that list's phrasing.
>
> **(Octavia)** With that all said, let's begin!
>
# The Lies
- No two users have the same name.
- If two users *do* have the same name, they are the same user.
- If two users *do not* have the same name, they are *not* the same user.
- A user's name will never change.
- Only a user's surname will ever change.
- A user's surname/family name will only change if their marital status does.
- A user's surname/family name *will* change if their marital status does.
- Only one part of a user's name will change at a time.
- If a user's name changes, you will be able to access documentation that confirms this.
- All users have a middle name.
- No user has a middle name.
- Surnames contain no non-alphabetic characters.
- First names contain no non-alphabetic characters.
- Users *have* a surname, family name, or other second name.
- Users will have a consistent, canonical name ordering.
- The first letter/character of any name section should be capitalised[^1].
- Users have a legal name.
- Legal names can be easily verified.
- Legal names are consistent across all records.
- A user only has one legal name.
- A user's preferred name is their first name.
- A user's preferred name is their last name.
- A user's preferred name does not differ from one or more of their legal names.
- Legal name is a term that has a concrete meaning.
- Users have a canonical name that is consistent across services.
- Any two names will be bit-identical and visually identical if the same Unicode codepoints in the same order are used by the data entry system as by the accessing system.
- A user's title is always prefixed to the name.
- A user's title will never change.
- A user's title will change if their marital status does.
- A user's title will change if their marital status, education, or clerical status does.
- There exists a consistent, canonical list of titles that covers all possible users.
- A user's title is used in addition to their name, not instead of it.
- Users have a title.
- A user only has *one* title.
[^1]: Assuming the character set supports capitalisation
# Commentary
Now that you've read all that, if you ever find yourself dealing with user's names, there is unfortunately no good name/naming library we can point you at (unlike the date/time problem, which is mostly stable on most operating systems). Instead, try to keep these falsehoods in mind, and link them to people you know who are working with names.
> **(Tess)** As an exercise, see if you can figure out a counter-example to demonstrate each rule. It's good fun! :)

View File

@ -1,157 +0,0 @@
<head>
{{/* Instant Page Script */}}
{{/* Optimised by A Friend */}}
<link rel="preload" href="{{ .Site.BaseURL }}instant.page.v5.1.1.js" as="script" />
<script defer>
window.addEventListener('load', () => {
const el = document.createElement('script')
el.src = '{{ .Site.BaseURL }}instant.page.v5.1.1.js'
document.body.append(el)
})
</script>
<meta charset="utf-8" />
{{ with .Site.Language.Params.htmlCode | default .Site.LanguageCode }}
<meta http-equiv="content-language" content="{{ . }}" />
{{ end }}
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
{{/* Title */}}
{{ if .IsHome -}}
<title>{{ .Site.Title | emojify }}</title>
<meta name="title" content="{{ .Site.Title | emojify }}" />
{{- else -}}
<title>{{ .Title | emojify }} &middot; {{ .Site.Title | emojify }}</title>
<meta name="title" content="{{ .Title | emojify }} &middot; {{ .Site.Title | emojify }}" />
{{- end }}
{{/* Metadata */}}
{{ with .Site.Params.description -}}
<meta name="description" content="{{ . }}" />
{{- end }}
{{ with .Site.Params.keywords -}}
<meta name="keywords" content="{{ . }}" />
{{- end }}
{{ with .Site.Params.robots }}
<meta name="robots" content="{{ . }}" />
{{ end }}
{{ with .Params.robots }}
<meta name="robots" content="{{ . }}" />
{{ end }}
<link rel="canonical" href="{{ .Permalink }}" />
{{ range .AlternativeOutputFormats -}}
{{ printf `
<link rel="%s" type="%s" href="%s" title="%s" />` .Rel .MediaType.Type .RelPermalink ($.Site.Title | emojify) |
safeHTML }}
{{ end -}}
{{/* Asset bundles */}}
{{ $assets := newScratch }}
{{ $cssScheme := resources.Get (printf "css/schemes/%s.css" (.Site.Params.colorScheme | default "blowfish")) }}
{{ if not $cssScheme }}
{{ $cssScheme = resources.Get "css/schemes/blowfish.css" }}
{{ end }}
{{ $assets.Add "css" (slice $cssScheme) }}
{{ $cssMain := resources.Get "css/compiled/main.css" }}
{{ $assets.Add "css" (slice $cssMain) }}
{{ $cssCustom := resources.Get "css/custom.css" }}
{{ if $cssCustom }}
{{ $assets.Add "css" (slice $cssCustom) }}
{{ end }}
{{ $bundleCSS := $assets.Get "css" | resources.Concat "css/main.bundle.css" | resources.Minify | resources.Fingerprint
"sha512" }}
<link type="text/css" rel="stylesheet" href="{{ $bundleCSS.RelPermalink }}"
integrity="{{ $bundleCSS.Data.Integrity }}" />
{{ $jsAppearance := resources.Get "js/appearance.js" }}
{{ $jsAppearance = $jsAppearance | resources.Minify | resources.Fingerprint "sha512" }}
<script type="text/javascript" src="{{ $jsAppearance.RelPermalink }}"
integrity="{{ $jsAppearance.Data.Integrity }}"></script>
{{ if .Site.Params.enableSearch | default false }}
{{ $jsFuse := resources.Get "lib/fuse/fuse.min.js" }}
{{ $jsSearch := resources.Get "js/search.js" }}
{{ $assets.Add "js" (slice $jsFuse $jsSearch) }}
{{ end }}
{{ if .Site.Params.enableCodeCopy | default false }}
{{ $jsCode := resources.Get "js/code.js" }}
{{ $assets.Add "js" (slice $jsCode) }}
{{ end }}
{{ if .Site.Params.rtl | default false }}
{{ $jsRTL := resources.Get "js/rtl.js" }}
{{ $assets.Add "js" (slice $jsRTL) }}
{{ end }}
{{ if $assets.Get "js" }}
{{ $bundleJS := $assets.Get "js" | resources.Concat "js/main.bundle.js" | resources.Minify | resources.Fingerprint
"sha512" }}
<script defer type="text/javascript" id="script-bundle" src="{{ $bundleJS.RelPermalink }}"
integrity="{{ $bundleJS.Data.Integrity }}" data-copy="{{ i18n " code.copy" }}" data-copied="{{ i18n " code.copied"
}}"></script>
{{ end }}
<script src="/js/zoom.min.js"></script>
{{/* Icons */}}
{{ if templates.Exists "partials/favicons.html" }}
{{ partialCached "favicons.html" .Site }}
{{ else }}
<link rel="apple-touch-icon" sizes="180x180" href="{{ "apple-touch-icon.png" | relURL }}" />
<link rel="icon" type="image/png" sizes="32x32" href="{{ "favicon-32x32.png" | relURL }}" />
<link rel="icon" type="image/png" sizes="16x16" href="{{ "favicon-16x16.png" | relURL }}" />
<link rel="manifest" href="{{ "site.webmanifest" | relURL }}" />
{{ end }}
{{/* Site Verification */}}
{{ with .Site.Params.verification.google }}
<meta name="google-site-verification" content="{{ . }}" />
{{ end }}
{{ with .Site.Params.verification.bing }}
<meta name="msvalidate.01" content="{{ . }}" />
{{ end }}
{{ with .Site.Params.verification.pinterest }}
<meta name="p:domain_verify" content="{{ . }}" />
{{ end }}
{{ with .Site.Params.verification.yandex }}
<meta name="yandex-verification" content="{{ . }}" />
{{ end }}
{{/* Social */}}
{{ template "_internal/opengraph.html" . }}
{{ template "_internal/twitter_cards.html" . }}
{{/* Schema */}}
{{ partial "schema.html" . }}
{{/* Me */}}
{{ with .Site.Author.name }}
<meta name="author" content="{{ . }}" />{{ end }}
{{ with .Site.Author.links }}
{{ range $links := . }}
{{ range $name, $url := $links }}
<link href="{{ $url }}" rel="me" />{{ end }}
{{ end }}
{{ end }}
{{/* Vendor */}}
{{ partial "vendor.html" . }}
{{/* Analytics */}}
{{ partialCached "analytics.html" .Site }}
{{/* Extend head - eg. for custom analytics scripts, etc. */}}
{{ if templates.Exists "partials/extend-head.html" }}
{{ partialCached "extend-head.html" .Site }}
{{ end }}
{{/* Firebase */}}
{{ with $.Site.Params.firebase }}
{{ if isset $.Site.Params "firebase" }}
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/8.10.0/firebase-auth.js"></script>
<script>
const firebaseConfig = {
apiKey: {{ $.Site.Params.firebase.apiKey }},
authDomain: {{ $.Site.Params.firebase.apiKey }},
projectId: {{ $.Site.Params.firebase.projectId }},
storageBucket: {{ $.Site.Params.firebase.storageBucket }},
messagingSenderId: {{ $.Site.Params.firebase.messagingSenderId }},
appId: {{ $.Site.Params.firebase.appId }},
measurementId: {{ $.Site.Params.firebase.measurementId }}
};
var app = firebase.initializeApp(firebaseConfig);
var db = firebase.firestore();
var auth = firebase.auth();
</script>
{{ end }}
{{ end }}
</head>

View File

@ -0,0 +1,95 @@
{{ $constrainItemsWidth := .Page.Site.Params.list.constrainItemsWidth | default false }}
{{ $articleClasses := "flex flex-wrap article" }}
{{ if .Site.Params.list.showCards }}
{{ $articleClasses = delimit (slice $articleClasses "border border-neutral-200 dark:border-neutral-700 border-2 rounded-md backdrop-blur") " " }}
{{ else }}
{{ $articleClasses = delimit (slice $articleClasses "") " " }}
{{ end }}
{{ $articleImageClasses := "w-full md:w-auto h-full thumbnail nozoom" }}
{{ if .Site.Params.list.showCards }}
{{ $articleImageClasses = delimit (slice $articleImageClasses "") " " }}
{{ else }}
{{ $articleImageClasses = delimit (slice $articleImageClasses "thumbnailshadow md:mr-7") " " }}
{{ end }}
{{ $disableImageOptimization := .Page.Site.Params.disableImageOptimization | default false }}
{{ $articleInnerClasses := "" }}
{{ if .Site.Params.list.showCards }}
{{ $articleInnerClasses = delimit (slice $articleInnerClasses "p-4") " " }}
{{ else }}
{{ $articleInnerClasses = delimit (slice $articleInnerClasses "mt-3 md:mt-0") " " }}
{{ end }}
{{ if $constrainItemsWidth }}
{{ $articleClasses = delimit (slice $articleClasses "max-w-prose") " " }}
{{ end }}
{{ with .Params.externalUrl }}
<a class="{{ $articleClasses }}" href="{{ . }}" target="_blank" rel="external">
{{ else }}
<a class="{{ $articleClasses }}" href="{{ .RelPermalink }}">
{{ end }}
{{- with $.Params.images -}}
{{- range first 6 . }}
<meta property="og:image" content="{{ . | absURL }}" />{{ end -}}
{{- else -}}
{{- $images := $.Resources.ByType "image" -}}
{{- $featured := $images.GetMatch "*feature*" -}}
{{- if not $featured }}{{ $featured = $images.GetMatch "{*cover*,*thumbnail*}" }}{{ end -}}
{{- with $featured -}}
{{ if $disableImageOptimization }}
{{ with . }}
<div class="{{ $articleImageClasses }}" style="background-image:url({{ .RelPermalink }});"></div>
{{ end }}
{{ else }}
{{ with .Resize "600x" }}
<div class="{{ $articleImageClasses }}" style="background-image:url({{ .RelPermalink }});"></div>
{{ end }}
{{ end }}
{{- else -}}
{{- with $.Site.Params.images }}
<meta property="og:image" content="{{ index . 0 | absURL }}" />{{ end -}}
{{- end -}}
{{- end -}}
<div class="{{ $articleInnerClasses }}">
<div class="items-center text-xl font-semibold">
{{ with .Params.externalUrl }}
<div>
<div
class="text-neutral-800 decoration-primary-500 hover:underline hover:underline-offset-2 dark:text-neutral">
{{ $.Title | emojify }}
<span class="text-xs align-top cursor-default text-neutral-400 dark:text-neutral-500">
<span class="rtl:hidden">&#8599;</span>
<span class="ltr:hidden">&#8598;</span>
</span>
</div>
</div>
{{ else }}
<div class="text-neutral-800 decoration-primary-500 hover:underline hover:underline-offset-2 dark:text-neutral"
href="{{ .RelPermalink }}"><h2>{{ .Title | emojify }}</h2></div>
{{ end }}
{{ if and .Draft .Site.Params.article.showDraftLabel }}
<div class=" ltr:ml-2 rtl:mr-2">
{{ partial "badge.html" (i18n "article.draft" | emojify) }}
</div>
{{ end }}
{{ if templates.Exists "partials/extend-article-link.html" }}
{{ partial "extend-article-link.html" . }}
{{ end }}
</div>
<div class="text-sm text-neutral-500 dark:text-neutral-400">
{{ partial "article-meta/basic.html" . }}
</div>
{{ if .Params.showSummary | default (.Site.Params.list.showSummary | default false) }}
<div class="py-1 max-w-fit prose dark:prose-invert">
{{ .Summary | emojify }}
</div>
{{ end }}
</div>
</a>

View File

@ -1,4 +1,14 @@
<head>
{{/* Instant Page Script */}}
{{/* Optimised by A Friend */}}
<link rel="preload" href="{{ .Site.BaseURL }}instant.page.v5.1.1.js" as="script" />
<script defer>
window.addEventListener('load', () => {
const el = document.createElement('script')
el.src = '{{ .Site.BaseURL }}instant.page.v5.1.1.js'
document.body.append(el)
})
</script>
<meta charset="utf-8" />
{{ with .Site.Language.Params.htmlCode | default .Site.LanguageCode }}
<meta http-equiv="content-language" content="{{ . }}" />
@ -14,11 +24,11 @@
<meta name="title" content="{{ .Title | emojify }} &middot; {{ .Site.Title | emojify }}" />
{{- end }}
{{/* Metadata */}}
{{ with (.Params.Summary | default .Params.Description) | default .Site.Params.description -}}
{{ with .Site.Params.description -}}
<meta name="description" content="{{ . }}" />
{{- end }}
{{ with .Params.Tags | default .Site.Params.keywords -}}
<meta name="keywords" content="{{ range . }}{{ . }}, {{ end -}}" />
{{ with .Site.Params.keywords -}}
<meta name="keywords" content="{{ . }}" />
{{- end }}
{{ with .Site.Params.robots }}
<meta name="robots" content="{{ . }}" />
@ -50,7 +60,7 @@
<link type="text/css" rel="stylesheet" href="{{ $bundleCSS.RelPermalink }}"
integrity="{{ $bundleCSS.Data.Integrity }}" />
{{ $jsAppearance := resources.Get "js/appearance.js" }}
{{ $jsAppearance = $jsAppearance | resources.ExecuteAsTemplate $jsAppearance.RelPermalink . | resources.Minify | resources.Fingerprint "sha512" }}
{{ $jsAppearance = $jsAppearance | resources.Minify | resources.Fingerprint "sha512" }}
<script type="text/javascript" src="{{ $jsAppearance.RelPermalink }}"
integrity="{{ $jsAppearance.Data.Integrity }}"></script>
{{ if .Site.Params.enableSearch | default false }}
@ -73,7 +83,7 @@
integrity="{{ $bundleJS.Data.Integrity }}" data-copy="{{ i18n " code.copy" }}" data-copied="{{ i18n " code.copied"
}}"></script>
{{ end }}
<script src="{{ "js/zoom.min.js" | relURL }}"></script>
<script src="/js/zoom.min.js"></script>
{{/* Icons */}}
{{ if templates.Exists "partials/favicons.html" }}
{{ partialCached "favicons.html" .Site }}
@ -113,12 +123,12 @@
{{/* Vendor */}}
{{ partial "vendor.html" . }}
{{/* Analytics */}}
{{ partial "analytics/main.html" .Site }}
{{ partialCached "analytics.html" .Site }}
{{/* Extend head - eg. for custom analytics scripts, etc. */}}
{{ if templates.Exists "partials/extend-head.html" }}
{{ partialCached "extend-head.html" .Site }}
{{ end }}
<meta name="theme-color"/>
{{/* Firebase */}}
{{ with $.Site.Params.firebase }}
{{ if isset $.Site.Params "firebase" }}
@ -142,18 +152,6 @@
var auth = firebase.auth();
</script>
{{ end }}
{{ end }}
{{/* Instant Page Script */}}
{{/* Optimised by A Friend */}}
<link rel="preload" href="/instant.page.v5.1.1.js" as="script" />
<script defer>
window.addEventListener('load', () => {
const el = document.createElement('script')
el.src = '/instant.page.v5.1.1.js'
document.body.append(el)
})
</script>
</head>

View File

@ -0,0 +1,4 @@
<time datetime="{{ . }}">
{{- i18n "article.date_updated" (dict "Date" (partial "functions/date.html" .)) | markdownify | emojify -}}
</time>
{{- /* Trim EOF */ -}}

View File

@ -0,0 +1,4 @@
<time datetime="{{ . }}">
{{- i18n "article.date" (dict "Date" (partial "functions/date.html" .)) | markdownify | emojify -}}
</time>
{{- /* Trim EOF */ -}}

View File

@ -0,0 +1,4 @@
<span title="{{ i18n "article.reading_time_title" }}" class="reading-time">
{{- i18n "article.reading_time" .ReadingTime | markdownify | emojify -}}
</span>
{{- /* Trim EOF */ -}}

View File

@ -0,0 +1,4 @@
<span title="Word count" class="word-count">
{{- i18n "article.word_count" .WordCount | markdownify | emojify -}}
</span>
{{- /* Trim EOF */ -}}

View File

@ -1,3 +0,0 @@
/*! instant.page v5.1.1 - (C) 2019-2020 Alexandre Dieulot - https://instant.page/license */
/* Modified by Rin - https://rin.systems/ */
let z,x;const n=new Set,o=document.createElement("link"),i=o.relList&&o.relList.supports&&o.relList.supports("prefetch")&&window.IntersectionObserver&&"isIntersecting"in IntersectionObserverEntry.prototype,s="instantAllowQueryString"in document.body.dataset,a="instantAllowExternalLinks"in document.body.dataset,r="instantWhitelist"in document.body.dataset,c="instantMousedownShortcut"in document.body.dataset,d=1111;let l=65,u=!1,f=!1,m=!1;if("instantIntensity"in document.body.dataset){const t=document.body.dataset.instantIntensity;if("mousedown"==t.substr(0,"mousedown".length))u=!0,"mousedown-only"==t&&(f=!0);else if("viewport"==t.substr(0,"viewport".length))navigator.connection&&(navigator.connection.saveData||navigator.connection.effectiveType&&navigator.connection.effectiveType.includes("2g"))||("viewport"==t?document.documentElement.clientWidth*document.documentElement.clientHeight<45e4&&(m=!0):"viewport-all"==t&&(m=!0));else{const e=parseInt(t);isNaN(e)||(l=e)}}if(i){const t={capture:!0,passive:!0};if(f||document.addEventListener("touchstart",(function(t){x=performance.now();const e=t.target.closest("a");h(e)&&v(e.href)}),t),u?c||document.addEventListener("mousedown",(function(t){const e=t.target.closest("a");h(e)&&v(e.href)}),t):document.addEventListener("mouseover",(function(t){if(performance.now()-x<d)return;if(!("closest"in t.target))return;const e=t.target.closest("a");h(e)&&(e.addEventListener("mouseout",p,{passive:!0}),z=setTimeout((()=>{v(e.href),z=void 0}),l))}),t),c&&document.addEventListener("mousedown",(function(t){if(performance.now()-x<d)return;const e=t.target.closest("a");if(t.which>1||t.metaKey||t.ctrlKey)return;if(!e)return;e.addEventListener("click",(function(t){1337!=t.detail&&t.preventDefault()}),{capture:!0,passive:!1,once:!0});const n=new MouseEvent("click",{view:window,bubbles:!0,cancelable:!1,detail:1337});e.dispatchEvent(n)}),t),m){let t;(t=window.requestIdleCallback?t=>{requestIdleCallback(t,{timeout:1500})}:t=>{t()})((()=>{const t=new IntersectionObserver((e=>{e.forEach((e=>{if(e.isIntersecting){const n=e.target;t.unobserve(n),v(n.href)}}))}));document.querySelectorAll("a").forEach((e=>{h(e)&&t.observe(e)}))}))}}function p(t){t.relatedTarget&&t.target.closest("a")==t.relatedTarget.closest("a")||z&&(clearTimeout(z),z=void 0)}function h(t){if(t&&t.href&&(!r||"instant"in t.dataset)&&(a||t.origin==location.origin||"instant"in t.dataset)&&["http:","https:"].includes(t.protocol)&&("http:"!=t.protocol||"https:"!=location.protocol)&&(s||!t.search||"instant"in t.dataset)&&!(t.hash&&t.pathname+t.search==location.pathname+location.search||"noInstant"in t.dataset))return!0}function v(t){if(n.has(t))return;const e=document.createElement("link");e.rel="prefetch",e.href=t,document.head.appendChild(e),n.add(t)}

@ -1 +1 @@
Subproject commit 9818cfd07b7038a22e582ec26f95159817e38d1a
Subproject commit 7df01846210fb56fc8ba2bcadea53317505094bb