Research blog setup

Research blog setup

The research blog is a Jekyll blog collection. Every note is a Markdown file in _blog/:

  • _blog/en/my-note.md becomes /blog/en/my-note/
  • _blog/ko/my-note.md becomes /blog/ko/my-note/

Copy the two files in blog-drafts/, put one in each language directory, and give both the same translation_key. The per-post language toggle uses that key to find the paired URL. The translations remain separate Markdown sources, so they can differ where useful.

PDF export

The compact PDF download control beside each post’s reading time links to a pre-rendered A4 file in files/blog/. The filename uses the post’s translation_key and language, such as my-note-en.pdf.

PDFs are generated from the completed Jekyll pages by headless Chromium through Playwright. This uses the same print CSS as the browser, preserves embedded HTML and images, and keeps English and Korean text selectable and searchable. Run the generator after building the site:

bundle exec jekyll build --config _config.yml,_config_pdf.yml
python3 -m http.server 4001 --directory _site
node scripts/generate-blog-pdfs.js

The Generate blog PDFs GitHub Actions workflow performs these steps automatically whenever a blog source, its layout, or its styles change. It installs Noto CJK and core script fonts, regenerates files/blog/*.pdf, and commits changed PDFs to master. Oversized article images are downsampled only for the PDF copy. The workflow needs repository Contents: write permission. Dedicated PDF styles live in _sass/layout/_blog.scss.

_config_pdf.yml points generated asset URLs at the temporary local server. Before rendering, the generator rewrites article hyperlinks back to https://bluesaiyancodes.github.io so downloaded PDFs never contain localhost links.

Giscus comments and reactions

Giscus is enabled and provides GitHub Discussions-backed comments and reactions beneath each post. It uses the repository’s Announcements category:

blog_settings:
  giscus:
    enabled: true
    repo: "bluesaiyancodes/bluesaiyancodes.github.io"
    repo_id: "R_kgDOOSLWcQ"
    category: "Announcements"
    category_id: "DIC_kwDOOSLWcc4DBLPN"
    mapping: "pathname"
    strict: "0"
    reactions_enabled: "1"

The repository must keep GitHub Discussions enabled and the Giscus GitHub App installed. To reconfigure it later:

  1. In the repository’s Settings → Features, enable Discussions.
  2. Install the Giscus GitHub App for bluesaiyancodes/bluesaiyancodes.github.io.
  3. Keep or create the Announcements discussion category.
  4. At giscus.app, enter bluesaiyancodes/bluesaiyancodes.github.io, choose Announcements, and copy only the generated data-category-id value.
  5. Replace the category ID in _config.yml if it changed:

    blog_settings:
      giscus:
        enabled: true
        repo: "bluesaiyancodes/bluesaiyancodes.github.io"
        repo_id: "R_kgDOOSLWcQ"
        category: "Announcements"
        category_id: "DIC_..."
        mapping: "pathname"
        strict: "0"
        reactions_enabled: "1"
    

The remaining defaults use pathname mapping, preferred-color-scheme theming, reactions enabled, metadata emission disabled, and the comment box below existing comments. Set comments: false in a post to omit Giscus there.

The root giscus.json limits embeds to the production site, the giscus setup preview, and localhost development. Smooth language navigation reloads the Giscus client for the destination post, so each English/Korean pathname keeps its own discussion.

GoatCounter page views

GoatCounter is enabled for the research-blog index and individual posts using the bluesaiyancodes site code:

blog_settings:
  goatcounter:
    enabled: true
    code: "bluesaiyancodes"

Set enabled: false to remove the tracker. The existing analytics.provider: "google-analytics-4" and GA4 ID are unchanged.

RSS feed

The blog-only RSS feed is generated by Jekyll at /blog/feed.xml; it does not require an external RSS service. Its visible link and <head> discovery tag are currently disabled until the feed is actively promoted:

blog_settings:
  rss:
    enabled: false

Set enabled: true to show the RSS link and advertise the feed to feed readers. The XML endpoint continues to build while hidden so it can be validated before launch.

Language availability

The /blog/ index renders one card per note and shows the available translations after its date: [EN, 한], [EN], or [한]. Each language label links directly to its separate post URL. Individual posts keep the compact language switch beside the back link and only show languages that exist for that note.

Blog links use assets/js/blog-navigation.js to fetch and replace the main blog content without a full document reload. The address bar and browser history still use each post’s canonical URL, and ordinary link navigation remains the fallback when JavaScript or fetching is unavailable. Client-side transitions send a virtual pageview through GoatCounter’s JavaScript API.