2026.06.11 (Thu)

โœจ GPT-5.5โ€™s Summary ใ€€

A record of replacing the separate JavaScript-built search result cards with a shared Liquid archive card, so dates, categories, views, and the search overlay layout follow the same rules as regular listings.

The search results looked old.

On the home page and category pages, post cards already had a clearer shape. The title was followed by the date, category badges, and view count in the same meta row.

But when I opened search, an older UI appeared.

It showed only the title and excerpt. I could not immediately see when the post was written. There was no category. There was no view count. The same post had enough context in regular listings, but lost that context in search results.

The cause was that search results were still being rendered with a separate JavaScript HTML string.

JavaScript string rendering made search results look outdated

Lunr still handles search.

For a static Jekyll blog, it makes sense to build a search store at build time and let client-side JavaScript query it in the browser.

The problem was that JavaScript was also building the result card.

Regular listings were rendered by _includes/archive-single.html, while search results were assembled as strings in assets/js/lunr/lunr-en.js.

The structure looked roughly like this.

Regular listing
-> Liquid include
-> archive__item
-> date, category, views

Search results
-> Lunr JS
-> hand-built HTML string
-> title and excerpt only

That structure was the bug.

If I added category badges to regular listings, search results stayed unchanged. If I changed the date display rule, search results stayed unchanged. If I adjusted view-count metadata, search results stayed unchanged.

The same post card was being maintained in two places.

I split the post card into a shared include

Instead of making the search JavaScript larger, I made it build less HTML.

I added shared card includes.

_includes/archive-item-card.html
_includes/archive-item-meta-row.html
_includes/archive-item-categories.html

archive-item-card.html receives one document and renders the same structure used by existing archive listings.

list__item
archive__item
archive__item-title
archive__item-meta-row
archive__item-excerpt

archive-item-meta-row.html groups date, views, and categories into one line. Date and views continue to use page__meta.html, and categories are handled by archive-item-categories.html.

Then _includes/archive-single.html became a thin wrapper instead of owning the card HTML directly.

{% include archive-item-card.html document=post type=include.type context="archive" %}

Now regular listings and search results use card HTML from the same include.

I stored complete card HTML in the Lunr store

Lunr still performs the search.

But JavaScript no longer builds the result card HTML.

At Jekyll build time, assets/js/lunr/lunr-store.js renders the card include for each document and stores the output in an html field.

title
excerpt
categories
tags
lang
locale
html
url
teaser

The search JavaScript now pulls entry.html and inserts it.

Before this, the search JS mixed title links, teaser images, excerpt truncation, and HTML string assembly.

var renderSearchResult = function (entry) {
  return entry.html || '';
};

The remaining responsibilities of the search JS are search, locale filtering, result count display, and insertion.

Search result views are displayed, not tracked

Should search results show view counts too?

At first I considered omitting them. Search results could become noisy, and dynamically inserted DOM needed separate view-count timing.

But if the card is supposed to match regular listings, omitting only views is also strange.

So search results show views. Display and tracking are separated.

Search result exposure is not a visit.
The view count in search results is display-only.
Actual visit tracking belongs only to the currently opened page.

This blogโ€™s view elements have data-page-view-path. The actual tracking target is the current page element with data-page-view-track="true".

Search result cards have only data-page-view-path; they do not have data-page-view-track="true".

So a post appearing in search results does not increment that postโ€™s view count.

It only shows the number.

I reapply views to dynamically inserted search results

Search results are not present in the DOM when the page first loads.

They are inserted after the user types a query. If the view script only collects elements once at page load, view counts inside search results never get filled.

So I also changed assets/js/custom/visitor-stats.js.

Instead of storing document.querySelectorAll("[data-page-view-path]") once at the top, it queries those elements again whenever view counts are rendered.

I also cached the analytics payload.

latestAnalyticsPayload

After search results are rendered, the search script dispatches the hyuk:search-results-rendered event.

The visitor stats script listens for that event and, if it already has a payload, reapplies view counts to the new DOM.

It does not call the API again.

Calling the view API for every search input change would make the search UI interfere with the view system. Search results change often, so the network request should not follow every keystroke.

The flow is now:

Page load
-> receive analytics payload once
-> render views for existing listing/current page

Search results render
-> dispatch event
-> reuse cached payload for newly inserted DOM

This keeps search results from polluting the counter.

I matched multilingual search metadata by locale

After the multilingual blog work, the site has locale pages and collections such as /en/, /ja/, and /zh-Hans/. Search cannot mix locales.

The search store includes lang and locale, and the card HTML itself uses the document locale for metadata labels. So English search results show Views, Japanese search results show ้–ฒ่ฆงๆ•ฐ, and so on.

Categories follow the same rule.

The locale prefix itself should not appear as a category badge, so archive-item-categories.html skips the locale segment and displays only the real categories.

I restored the sidebar and wider result width in the search overlay

Matching the card was not enough.

When I opened search, the result width was still strangely narrow. Even though it used the same card HTML as regular listings, it did not use the available right-side space.

There was a larger problem too. Opening search made the side categories disappear.

The search overlay is not layered over the existing page body. When search opens, .initial-content is hidden and a separate #site-search area is shown.

That means the sidebar inside the normal page also disappears. Even with a shared card, the search screen still feels separate if the surrounding layout is different.

So I included the sidebar inside _includes/search/search_form.html.

<div class="search-content__inner-wrap">
  {% include sidebar.html %}
  <div class="archive search-content__archive">
    ...
  </div>
</div>

I also wrapped the result area in archive search-content__archive so search results flow inside the archive layout.

Then I removed the CSS rule that was narrowing the cards.

Minimal Mistakes had this search rule.

.search-content .archive__item {
  @include breakpoint($large) {
    width: 75%;
  }

  @include breakpoint($x-large) {
    width: 50%;
  }
}

So the outdated look was not only caused by the card HTML. On large screens, the result card itself was being cut down to half width.

In custom SCSS, search result cards now use full width.

.search-content .archive__item {
  width: 100%;
}

There was one more layout issue.

The regular archive layout reserves right-side space with padding-inline-end for the right sidebar. The search overlay has no right sidebar. Keeping that padding makes search results narrow again.

So I removed that right padding only for the search overlay archive.

.search-content .search-content__archive {
  padding-inline-end: 0;
}

The card rendering rules are shared with regular listings, while the overlay layout is adjusted for the search screen.

I checked desktop and mobile widths

I ran the build and syntax checks.

bundle exec jekyll build
node --check _site/assets/js/lunr/lunr-store.js
node --check _site/assets/js/lunr/lunr-en.js
node --check _site/assets/js/custom/visitor-stats.js

The generated search store includes page__views and data-page-view-path.

The search card HTML does not include data-page-view-track="true", which would mix search exposure with visit tracking.

Then I opened search on Korean, English, and Japanese pages and tried queries such as:

References
Keymory
Daily review

Result cards showed date, category, and view count in the same meta row as regular listings. The labels followed each locale: Views, ้–ฒ่ฆงๆ•ฐ, and the other registered labels.

Inside search results, data-page-view-track="true" was absent. On actual post pages, the current-page tracking element still appeared once.

The search overlay also had the sidebar again. At a 1280px desktop width, the sidebar had 22 items, and the search result card width reached about 974px.

At a 390px mobile width, the sidebar stacked above the content, and the result card used a 345px width for the title, meta row, and excerpt.

The browser console had no errors.

Leave a comment