last one maybe

This commit is contained in:
Conner Chu 2025-07-06 15:39:54 +02:00
parent e76194457a
commit 2e99c7ea60
30 changed files with 731 additions and 12 deletions

View File

@ -6,10 +6,11 @@ layout = "photography"
+++
{{< gallery
match="*.jpg|*.jpeg|*.png|*.webp|*.gif"
match="*.webp"
sortOrder="desc"
rowHeight="150"
margins="5"
thumbnailResizeOptions="600x600 q90 Lanczos"
previewType="blur"
>}}
{{< /gallery >}}

View File

@ -0,0 +1,462 @@
<!-- Force jQuery to load first -->
<script src="/shortcode-gallery/jquery-3.7.1.min.js"></script>
<!-- Now load the gallery scripts (these will be loaded again by the shortcode, but this ensures jQuery is present) -->
<script src="/shortcode-gallery/lazy/jquery.lazy.min.js"></script>
<script src="/shortcode-gallery/swipebox/js/jquery.swipebox.min.js"></script>
<script src="/shortcode-gallery/justified_gallery/jquery.justifiedGallery.min.js"></script>
<link rel="stylesheet" href="/shortcode-gallery/swipebox/css/swipebox.min.css">
<link rel="stylesheet" href="/shortcode-gallery/justified_gallery/justifiedGallery.min.css">
<!-- Render the original gallery content -->
{{/* The following is a fallback: you may want to copy the full upstream gallery.html here for more advanced features. */}}
<div>
{{ .Inner }}
</div>
{{ $currentPage := . }}
{{ $images := slice }}
{{ $globalMatch := .Get "globalMatch" }}
{{ $localMatch := .Get "match" }}
{{ if $localMatch }}
{{ $images = (.Page.Resources.Match $localMatch )}}
{{ else if $globalMatch }}
{{ $images = (resources.Match (.Get "globalMatch")) }}
{{ else }}
{{ $images = (.Page.Resources.ByType "image") }}
{{ end }}
{{ $filterOptions := .Get "filterOptions" | default (.Site.Params.galleryFilterOptions | default "[]") }}
{{ if not $filterOptions }}
{{ $filterOptions = "[]" }}
{{ end }}
{{ $storeSelectedFilterInUrl := .Get "storeSelectedFilterInUrl" | default (.Site.Params.storeSelectedFilterInUrl | default false) }}
{{ $sortOrder := .Get "sortOrder" | default (.Site.Params.gallerySortOrder | default "asc") }}
{{ $rowHeight := .Get "rowHeight" | default (.Site.Params.galleryRowHeight | default 150) }}
{{ $margins := .Get "margins" | default (.Site.Params.galleryRowMargins | default 5) }}
{{ $randomize := .Get "randomize" | default (.Site.Params.galleryRandomize | default false) }}
{{ $thumbnailResizeOptions := .Get "thumbnailResizeOptions" | default (.Site.Params.galleryThumbnailResizeOptions | default "300x150 q85 Lanczos") }}
{{ $imageResizeOptions := .Get "imageResizeOptions" | default .Site.Params.galleryImageResizeOptions }}
{{ $loadJQuery := .Get "loadJQuery" | default (.Site.Params.galleryLoadJQuery | default false) }}
{{ $showExif := .Get "showExif" | default (.Site.Params.galleryShowExif | default false) }}
{{ $swipeboxParameters := .Get "swipeboxParameters" | default (.Site.Params.gallerySwipeboxParameters | default "") }}
{{ $justifiedGalleryParameters := .Get "justifiedGalleryParameters" | default (.Site.Params.galleryJustifiedGalleryParameters | default "") }}
{{ $previewType := .Get "previewType" | default (.Site.Params.galleryPreviewType | default "blur") }}
{{ $embedPreview := .Get "embedPreview" | default (.Site.Params.galleryEmbedPreview | default true) }}
{{ $thumbnailHoverEffect := .Get "thumbnailHoverEffect" | default (.Site.Params.galleryThumbnailHoverEffect | default "none") }}
<!-- hugos image processing saves images at resources/_gen/images, if the property resourceDir
is changed in hugos config.toml file the images are save <resourceDir>/_gen/images.
Because it is not possible to access the value of resourceDir, users who change resourceDir also have to change
[params] resourceDir. -->
{{ $thumbnailResourceDir := printf "%s%s" (.Site.Params.resourceDir | default "resources") "/_gen/images/" }}
<!-- Load jquery, jquery-lazy, swipebox and justified_gallery only once per page -->
{{ if not (.Page.Scratch.Get "galleryLoaded") }}
{{ .Page.Scratch.Set "galleryLoaded" true }}
<!-- Use relURL to support hugo projects that run in a subdirectory (bug #18) -->
<!-- Always load jQuery first to fix dependency issues -->
<script src="{{ "shortcode-gallery/jquery-3.7.1.min.js" | relURL }}"></script>
{{ if not (eq $previewType "none") }}
<script src="{{ "shortcode-gallery/lazy/jquery.lazy.min.js" | relURL }}"></script>
{{ end }}
<script src="{{ "shortcode-gallery/swipebox/js/jquery.swipebox.min.js" | relURL }}"></script>
<link rel="stylesheet" href="{{ "shortcode-gallery/swipebox/css/swipebox.min.css"| relURL }}">
<script src="{{ "shortcode-gallery/justified_gallery/jquery.justifiedGallery.min.js"| relURL }}"></script>
<link rel="stylesheet" href="{{ "shortcode-gallery/justified_gallery/justifiedGallery.min.css"| relURL }}"/>
{{ end }}
<style>
{{ if (eq $thumbnailHoverEffect "enlarge") }}
.jg-entry img {
transition: transform .25s ease-in-out !important;
}
.jg-entry img:hover {
transform: scale(1.1);
}
{{ end }}
{{ if not (eq $filterOptions "[]") }}
/* inline css from assets folder */
{{ (resources.Get "shortcode-gallery/filterbar.sass" | toCSS).Content | safeCSS }}
{{ end }}
</style>
<!--
Ordinal increases every time this shortcode is used in a document
Ordinal: {{ .Ordinal}}
-->
{{ $galleryId := (printf "gallery-%v-%v" .Page.File.UniqueID .Ordinal)}}
{{ $galleryWrapperId := (printf "gallery-%v-%v-wrapper" .Page.File.UniqueID .Ordinal)}}
<div id="{{ $galleryWrapperId }}" class="gallery-wrapper">
<div id="{{ $galleryId }}" class="justified-gallery">
{{ range $original := sort $images "Name" $sortOrder}}
{{ if eq $original.ResourceType "image" }}
{{/* Get metadata from sidecar file, if present. Else an empty dictionary is used. */}}
{{ $metaFileName := print $original.Name ".meta"}}
{{ $metadata := slice }}
{{ if and $globalMatch (not $localMatch) }}
{{ $metadata = resources.GetMatch ($metaFileName) }}
{{ else }}
{{ $metadata = $currentPage.Page.Resources.GetMatch ($metaFileName) }}
{{ end }}
{{ if $metadata }}
{{ $metadata = $metadata.Content }}
{{ $metadata = $metadata | unmarshal }}
{{ else }}
{{ $metadata = dict }}
{{ end }}
{{/* If the image has EXIF informations, those are merged together with the metadata from the file */}}
{{ if in "jpeg png tiff webp" $original.MediaType.SubType }}
{{ with $original.Exif }}
{{ $metadata = merge .Tags $metadata }}
{{ end }}
{{ end }}
{{/* Correct orientation of the image, this is needed for thumbnails (and downscaled gallery images)
if the EXIF informations contains an orientation value. See issue #22. */}}
{{ $rotated := $original.Filter images.AutoOrient }}
<div>
{{ $full := "" }}
{{ if $imageResizeOptions }}
{{/* Downscale gallery image, rotate it if needed */}}
{{ $full = ($rotated.Fit $imageResizeOptions) }}
{{ else }}
{{/* No need to use the rotated here, the browser will handle care of EXIF orientation */}}
{{ $full = $original }}
{{ end }}
{{ $thumbnail := "" }}
{{ if eq $thumbnailResizeOptions "original" }}
{{/* If thumbnailResizeOptions is set to 'original', use the original (unmodified) image for the thumbnail */}}
{{ $thumbnail = $original }}
{{ else if eq $thumbnailResizeOptions "full" }}
{{/* If thumbnailResizeOptions is set to 'full', use the same image as the lightbox for the thumbnail */}}
{{ $thumbnail = $full }}
{{ else }}
{{/* Create thumbnail, rotate it if needed */}}
{{ $thumbnail = ($rotated.Fit $thumbnailResizeOptions) }}
{{ end }}
<a href="{{ $full.RelPermalink }}"
class="galleryImg"
{{ with $metadata }}
{{ if .Title }}
title="{{ .Title }}"
{{ else if .ImageDescription }}
title="{{ .ImageDescription }}"
{{ end }}
{{ if $showExif }}
data-description="{{ .Model }}{{ if and .Model .LensModel }} + {{ end }}{{ .LensModel }}<br/>{{ if .FocalLength }}{{ .FocalLength }}mm {{ end }}{{ if .FNumber }}f/{{ printf "%.1f" .FNumber.Float64 }} {{ end }}{{ if .ExposureTime }}{{ .ExposureTime }}sec {{ end }} {{ if .ISO }}ISO {{ .ISO }}{{ end }}"
{{ end }}
{{ if not (eq $filterOptions "[]") }}
{{/* only include fields that are currently supported by the filter mechanism (in JS at the end of the file) */}}
data-meta="{{ (dict "Tags" .Tags "Rating" .Rating "ColorLabels" .ColorLabels "ImageDescription" .ImageDescription) | jsonify }}"
{{ end }}
{{ end }}
>
<img
width="{{ $thumbnail.Width }}" height="{{ $thumbnail.Height }}"
{{ if (eq $previewType "blur") }}
{{ $preview_b := ($thumbnail.Fit ("32x32 q70 box jpg")) }}
style="filter: blur(25px);"
{{ if $embedPreview }}
src="data:image/jpeg;base64,{{ $preview_b.Content | base64Encode }}"
{{ else }}
src="{{ $preview_b.RelPermalink }}"
{{ end }}
class="lazy"
data-src="{{ $thumbnail.RelPermalink }}"
{{ else if (eq $previewType "color") }}
{{ $preview_1p := ($thumbnail.Resize ("1x1 box png")) }}
{{ if $embedPreview }}
src="data:image/png;base64,{{ $preview_1p.Content | base64Encode }}"
{{ else }}
src="{{ $preview_1p.RelPermalink }}"
{{ end }}
class="lazy"
data-src="{{ $thumbnail.RelPermalink }}"
{{ else }}
src="{{ $thumbnail.RelPermalink }}"
{{ end }}
{{ with $metadata }}
{{ if .ImageDescription }}
alt="{{ .ImageDescription }}"
{{ else }}
{{ if .Title}}
alt="{{ .Title }}"
{{ end }}
{{ end }}
{{ end }}
>
</a>
</div>
{{ end }}
{{ end }}
</div>
</div>
<script>
if (!("HSCGjQuery" in window)) {
if (!window.jQuery) {
throw new Error("jQuery is not loaded, hugo-shortcode-gallery wont work without it!");
}
window.HSCGjQuery = window.jQuery.noConflict(true);
}
// Isolate all our variables from other scripts.
// See: https://www.nicoespeon.com/en/2013/05/properly-isolate-variables-in-javascript/
// We also expect to get jQuery as a parameter, so that if a second instance of jQuery is loaded
// after this script is executed (e.g. by a Hugo theme), we will still be referencing the previous
// version of jQuery that has all our plugins loaded.
;(function($) {
$( document ).ready(() => {
const gallery = $("#{{ $galleryId }}");
{{ $lastRowJustification := .Get "lastRow" | default (.Site.Params.galleryLastRow | default "justify") }}
// the instance of swipebox, it will be set once justifiedGallery is initialized
let swipeboxInstance = null;
// before the gallery initialization the listener has to be added
// else we can get a race condition and the listener is never called
gallery.on('jg.complete', () => {
{{ if or (eq $previewType "blur") (eq $previewType "color") }}
// if there is already some low resolution image data loaded, then we will wait for loading´
// the hi-res until the justified gallery has done the layout
$(() => {
$('.lazy').Lazy({
visibleOnly: true,
afterLoad: element => element.css({filter: "none", transition: "filter 1.0s ease-in-out"})
});
});
{{ end }}
swipeboxInstance = $('.galleryImg').swipebox(
$.extend({},
{ {{ $swipeboxParameters | safeJS }} }
)
);
});
// initialize the justified gallery
gallery.justifiedGallery($.extend(
{
rowHeight : {{ $rowHeight }},
margins : {{ $margins }},
border : 0,
randomize : {{ $randomize }},
waitThumbnailsLoad : false,
lastRow : {{ $lastRowJustification }},
captions : false,
// if there is at least one filter option
{{ if not (eq $filterOptions "[]") }}
// we first show no images at all
// till the code way below selects a filter and applies it
// this prevent creating the layout twice
filter : () => false
{{ end }}
},
{ {{ $justifiedGalleryParameters | safeJS }} }
));
// only include JS code for filter options if there at least one filter option
{{ if not (eq $filterOptions "[]") }}
// this function can be used to create a function that can be used by justifiedGallery
// for filtering images by their metadata
function createMetadataFilter(filterFunction) {
return (entry, index, array) => {
let meta = $(entry).find("a").attr("data-meta");
meta = meta ? JSON.parse(meta) : {};
let include = filterFunction(meta);
// only those images visible in justified gallery should be displayed
// in swipebox (only <a> with class galleryImg are displayed in swipebox)
$(entry).find("a").toggleClass("galleryImg", include);
return include;
}
}
// this function returns a function that can be used by justifiedGallery
// for filtering images by their tags
function createTagFilter(tagsRegexString) {
const tagsRegex = RegExp(tagsRegexString);
return createMetadataFilter(meta => {
let tags = meta.Tags;
tags = tags ? tags : [];
return tags.some(tag => tagsRegex.test(tag));
});
};
// this function returns a function that can be used by justifiedGallery
// for filtering images by their description
function createImageDescriptionFilter(descriptionRegexString) {
const descriptionRegex = RegExp(descriptionRegexString);
return createMetadataFilter(meta => {
let imageDescription = meta.ImageDescription;
return imageDescription !== null && descriptionRegex.test(imageDescription);
});
};
// this function returns a function that can be used by justifiedGallery
// for filtering images by their star rating
function createRatingFilter(min, max) {
return createMetadataFilter(meta => {
let rating = meta.Rating;
if(rating === null){
rating = -1;
}
return rating >= min && rating <= max;
});
};
// this function returns a function that can be used by justifiedGallery
// for filtering images by their color labels
function createColorLabelFilter(color) {
color = color.charAt(0).toLowerCase()
return createMetadataFilter(meta => {
let colors = meta.ColorLabels;
return colors && colors.includes(color);
});
};
const filterOptions = {{ $filterOptions | safeJS }};
// insert a div for inserting filter buttons before the gallery
const filterBar = $("<div class='justified-gallery-filterbar'/>");
gallery.before(filterBar);
var wrapper = document.getElementById("{{ $galleryWrapperId }}");
// inline svg icons
const expandIcon = '{{ (resources.Get "shortcode-gallery/font-awesome/expand-alt-solid.svg").Content | safeHTML }}';
const compressIcon = '{{ (resources.Get "shortcode-gallery/font-awesome/compress-alt-solid.svg").Content | safeHTML }}';
function setFulltab(activate) {
if(activate == wrapper.classList.contains("fulltab")){
return; // nothing to do, we are already in the right state
}
wrapper.classList.toggle("fulltab");
gallery.justifiedGallery({
rowHeight : {{ $rowHeight }} * (activate ? 1.5 : 1.0),
lastRow: (activate ? "nojustify": {{ $lastRowJustification }}),
// force justifiedGallery to refresh
refreshTime: 0,
});
// force justifiedGallery to refresh
gallery.data('jg.controller').startImgAnalyzer();
fullTabButton.html(wrapper.classList.contains("fulltab") ? compressIcon : expandIcon)
};
const fullTabButton = $("<button/>");
fullTabButton.html(expandIcon);
fullTabButton.click(() => setFulltab(!wrapper.classList.contains("fulltab")));
filterBar.append(fullTabButton);
$(document).keyup(e => {
// when ESC is pressed
if (e.keyCode === 27){
setFulltab(false);
}
});
function activateFilterButton(filterButton) {
// activate associated filter
gallery.justifiedGallery({filter : filterButton.filter});
// remove select class from all other selected buttons
filterBar.find('.selected').removeClass('selected');
filterButton.addClass("selected");
};
// check if the url contains an instruction to apply a specific filter
// eg. example.com/images/#gallery-filter=Birds
const params = new URLSearchParams(location.hash.replace(/^\#/,""));
let activeFilter = params.get('gallery-filter');
if (!activeFilter) {
// default to first filter
activeFilter = filterOptions[0].label;
}
// create a button for each filter entry
filterOptions.forEach(filterConfig => {
let filter; // create a filter function based on the available attributes of filterConfig
if(filterConfig.tags) {
filter = createTagFilter(filterConfig.tags);
} else if(filterConfig.rating){
if(filterConfig.rating.includes("-")){
minMax = filterConfig.rating.split("-"); // e.g. "3-5"
} else {
minMax = [filterConfig.rating, filterConfig.rating]; // e.g. "4"
}
filter = createRatingFilter(parseInt(minMax[0]), parseInt(minMax[1]));
} else if(filterConfig.color_label){
filter = createColorLabelFilter(filterConfig.color_label);
} else if(filterConfig.description){
filter = createImageDescriptionFilter(filterConfig.description);
} else {
// default to always true filter
filter = createMetadataFilter(meta => true);
}
const filterButton = $("<button/>");
filterButton.text(filterConfig.label);
filterButton.filter = filter;
filterButton.click(() => {
activateFilterButton(filterButton);
{{ if $storeSelectedFilterInUrl }}
// save applied filter in browser url
const params = new URLSearchParams(location.hash.replace(/^\#/,""));
params.set('gallery-filter', filterConfig.label);
window.history.replaceState("", "", location.pathname + location.search + "#" + params.toString());
{{ end }}
});
filterBar.append(filterButton);
if(filterConfig.label.toLowerCase() === activeFilter.toLowerCase()) {
activateFilterButton(filterButton);
}
});
{{ end }}
});
// End of our variable-isolating and self-executing anonymous function.
// We call it with the one version of jQuery that was used to load our plugins.
// See: http://blog.nemikor.com/2009/10/03/using-multiple-versions-of-jquery/
})(window.HSCGjQuery)
</script>

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -1,8 +1,256 @@
<!doctype html><html lang=en><head><meta charset=UTF-8><meta http-equiv=X-UA-Compatible content="ie=edge"><meta name=viewport content="width=device-width,initial-scale=1,shrink-to-fit=no"><meta name=author content><meta name=description content><meta name=keywords content><meta name=robots content="noodp"><meta name=theme-color content><link rel=canonical href=https://connerchu.com/tidbits/><title>Tidbits :: Conner Chu
</title><link rel=stylesheet href=/main.min.b35466370c2f708ecabeb5eacc8b59840bcf4578d326a600a15107f3e9f1dc4e.css integrity="sha256-s1RmNwwvcI7KvrXqzItZhAvPRXjTJqYAoVEH8+nx3E4=" crossorigin=anonymous><link rel=apple-touch-icon sizes=180x180 href=/apple-touch-icon.png><link rel=icon type=image/png sizes=32x32 href=/favicon-32x32.png><link rel=icon type=image/png sizes=16x16 href=/favicon-16x16.png><link rel=manifest href=/site.webmanifest><link rel=mask-icon href=/safari-pinned-tab.svg color><link rel="shortcut icon" href=/favicon.ico><meta name=msapplication-TileColor content><meta itemprop=name content="Tidbits"><meta itemprop=datePublished content="2024-09-14T23:30:59-07:00"><meta itemprop=dateModified content="2024-09-14T23:30:59-07:00"><meta name=twitter:card content="summary"><meta name=twitter:title content="Tidbits"><link rel=alternate type=application/rss+xml href=https://connerchu.com/tidbits/index.xml title="Conner Chu"></head><body><div class=container><header class=header><span class=header__inner><a href=/ style=text-decoration:none><div class=logo><span class=logo__mark></span><span class=logo__text>Home</span>
<span class=logo__cursor style=visibility:hidden></span></div></a><span class=header__right><nav class=menu><ul class=menu__inner><li><a href=/photography/>Photography</a></li><li><a href=/research/>Research</a></li><li><a href=/resume/>Resume</a></li><li><a href=/tidbits/>Tidbits</a></li></ul></nav><span class=menu-trigger><svg viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg></span></span></span></header><div class=content><main class=posts><h1>Tidbits</h1><div class=posts-group><div class=post-year>2024</div><ul class=posts-list><li class=post-item><a href=https://connerchu.com/tidbits/cga/ class=post-item-inner><span class=post-title>California Great America</span>
<span class=post-day>Sep 14</span></a></li><li class=post-item><a href=https://connerchu.com/tidbits/svd/ class=post-item-inner><span class=post-title>Singular Value Decomposition</span>
<span class=post-day>Jul 29</span></a></li><li class=post-item><a href=https://connerchu.com/tidbits/sfft/ class=post-item-inner><span class=post-title>Six Flags Fiesta Texas</span>
<span class=post-day>Jul 16</span></a></li></ul></div><div class=posts-group><div class=post-year>2023</div><ul class=posts-list><li class=post-item><a href=https://connerchu.com/tidbits/sfmm/ class=post-item-inner><span class=post-title>Six Flags Magic Mountain</span>
<span class=post-day>Dec 15</span></a></li></ul></div><div class=posts-group><div class=post-year>2022</div><ul class=posts-list><li class=post-item><a href=https://connerchu.com/tidbits/airplane/ class=post-item-inner><span class=post-title>Earbuds and Airplane Toilets</span>
<span class=post-day>Aug 3</span></a></li></ul></div><div class=pagination><div class=pagination__buttons></div></div></main></div><footer class=footer><div class=footer__inner><div class=footer__content><span>&copy Copyright 2025</span></div></div><div class=footer__inner><div class=footer__content><span>Powered by Hugo, Djordje, and Matze</span></div></div></footer></div><script type=text/javascript src=/bundle.min.e89fda0f29b95d33f6f4224dd9e5cf69d84aff3818be2b0d73e731689cc374261b016d17d46f8381962fb4a1577ba3017b1f23509d894f6e66431f988c00889e.js integrity="sha512-6J/aDym5XTP29CJN2eXPadhK/zgYvisNc+cxaJzDdCYbAW0X1G+DgZYvtKFXe6MBex8jUJ2JT25mQx+YjACIng=="></script><script>window.si=window.si||function(){(window.siq=window.siq||[]).push(arguments)}</script><script defer src=/_vercel/speed-insights/script.js></script><script>window.va=window.va||function(){(window.vaq=window.vaq||[]).push(arguments)}</script><script defer src=/_vercel/insights/script.js></script></body></html>
<!DOCTYPE html>
<html lang="en">
<head><script src="/livereload.js?mindelay=10&amp;v=2&amp;port=44669&amp;path=livereload" data-no-instant defer></script>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="author" content="">
<meta name="description" content="" />
<meta name="keywords" content="" />
<meta name="robots" content="noodp" />
<meta name="theme-color" content="" />
<link rel="canonical" href="http://localhost:44669/tidbits/" />
<title>
Tidbits :: Conner Chu
</title>
<link rel="stylesheet" href="/main.min.b35466370c2f708ecabeb5eacc8b59840bcf4578d326a600a15107f3e9f1dc4e.css" integrity="sha256-s1RmNwwvcI7KvrXqzItZhAvPRXjTJqYAoVEH8&#43;nx3E4=" crossorigin="anonymous">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
<link rel="manifest" href="/site.webmanifest">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="">
<link rel="shortcut icon" href="/favicon.ico">
<meta name="msapplication-TileColor" content="">
<meta itemprop="name" content="Tidbits">
<meta itemprop="datePublished" content="2024-09-14T23:30:59-07:00">
<meta itemprop="dateModified" content="2024-09-14T23:30:59-07:00">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Tidbits">
<link rel="alternate" type="application/rss+xml" href="http://localhost:44669/tidbits/index.xml" title="Conner Chu" />
</head>
<body>
<div class="container">
<header class="header">
<span class="header__inner">
<a href="/" style="text-decoration: none;">
<div class="logo">
<span class="logo__mark"> </span>
<span class="logo__text ">
Home</span>
<span class="logo__cursor" style=
"visibility:hidden;
">
</span>
</div>
</a>
<span class="header__right">
<nav class="menu">
<ul class="menu__inner"><li><a href="/photography/">Photography</a></li><li><a href="/research/">Research</a></li><li><a href="/resume/">Resume</a></li><li><a href="/tidbits/">Tidbits</a></li>
</ul>
</nav>
<span class="menu-trigger">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/>
</svg>
</span>
</span>
</span>
</header>
<div class="content">
<main class="posts">
<h1>Tidbits</h1>
<div class="posts-group">
<div class="post-year">2024</div>
<ul class="posts-list">
<li class="post-item">
<a href="http://localhost:44669/tidbits/cga/" class="post-item-inner">
<span class="post-title">California Great America</span>
<span class="post-day">
Sep 14
</span>
</a>
</li>
<li class="post-item">
<a href="http://localhost:44669/tidbits/svd/" class="post-item-inner">
<span class="post-title">Singular Value Decomposition</span>
<span class="post-day">
Jul 29
</span>
</a>
</li>
<li class="post-item">
<a href="http://localhost:44669/tidbits/sfft/" class="post-item-inner">
<span class="post-title">Six Flags Fiesta Texas</span>
<span class="post-day">
Jul 16
</span>
</a>
</li>
</ul>
</div>
<div class="posts-group">
<div class="post-year">2023</div>
<ul class="posts-list">
<li class="post-item">
<a href="http://localhost:44669/tidbits/sfmm/" class="post-item-inner">
<span class="post-title">Six Flags Magic Mountain</span>
<span class="post-day">
Dec 15
</span>
</a>
</li>
</ul>
</div>
<div class="posts-group">
<div class="post-year">2022</div>
<ul class="posts-list">
<li class="post-item">
<a href="http://localhost:44669/tidbits/airplane/" class="post-item-inner">
<span class="post-title">Earbuds and Airplane Toilets</span>
<span class="post-day">
Aug 3
</span>
</a>
</li>
</ul>
</div>
<div class="pagination">
<div class="pagination__buttons">
</div>
</div>
</main>
</div>
<footer class="footer">
<div class="footer__inner">
<div class="footer__content">
<span>&copy Copyright 2025</span>
</div>
</div>
<div class="footer__inner">
<div class="footer__content">
<span>Powered by Hugo, Djordje, and Matze</span>
</div>
</div>
</footer>
</div>
<script type="text/javascript" src="/bundle.min.e89fda0f29b95d33f6f4224dd9e5cf69d84aff3818be2b0d73e731689cc374261b016d17d46f8381962fb4a1577ba3017b1f23509d894f6e66431f988c00889e.js" integrity="sha512-6J/aDym5XTP29CJN2eXPadhK/zgYvisNc&#43;cxaJzDdCYbAW0X1G&#43;DgZYvtKFXe6MBex8jUJ2JT25mQx&#43;YjACIng=="></script>
<script>
window.si = window.si || function () { (window.siq = window.siq || []).push(arguments); };
</script>
<script defer src="/_vercel/speed-insights/script.js"></script>
<script>
window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
</script>
<script defer src="/_vercel/insights/script.js"></script>
</body>
</html>

View File

@ -1,2 +1,10 @@
<!doctype html><html lang=en-us><head><title>https://connerchu.com/tidbits/</title>
<link rel=canonical href=https://connerchu.com/tidbits/><meta name=robots content="noindex"><meta charset=utf-8><meta http-equiv=refresh content="0; url=https://connerchu.com/tidbits/"></head></html>
<!DOCTYPE html>
<html lang="en-us">
<head>
<title>http://localhost:44669/tidbits/</title>
<link rel="canonical" href="http://localhost:44669/tidbits/">
<meta name="robots" content="noindex">
<meta charset="utf-8">
<meta http-equiv="refresh" content="0; url=http://localhost:44669/tidbits/">
</head>
</html>