PageSourceSearch

https://evanyeh5118.github.io/publications/publications-projects.js

js evanyeh5118.github.io collected 2026-10-03 09:10:32 UTC 4,378 bytes, 116 lines download raw bytes

1import { el } from "../js/utils/dom.js";
2import { initParallaxBackground } from "../js/parallax-background.js";
3
4initParallaxBackground();
5
6// Initialize the page
7document.addEventListener('DOMContentLoaded', () => {
8  initPublications();
9});
10
11// Publications section
12function initPublications() {
13  const container = document.getElementById("publicationsList");
14  const countElement = document.getElementById("pubCount");
15  
16  if (!container) return;
17
18  fetch("../data/publications.json", { cache: "no-store" })
19    .then((r) => r.json())
20    .then((items) => {
21      container.innerHTML = "";
22
23      if (!Array.isArray(items) || items.length === 0) {
24        container.innerHTML = '<div class="text-center text-slate-500 py-8">No publications found.</div>';
25        if (countElement) countElement.textContent = "0 publications";
26        return;
27      }
28
29      // Sort by year (newest first)
30      items.sort((a, b) => (b.year || 0) - (a.year || 0));
31
32      // Group by year
33      const groupedByYear = items.reduce((acc, pub) => {
34        const year = pub.year || 'Unknown';
35        if (!acc[year]) acc[year] = [];
36        acc[year].push(pub);
37        return acc;
38      }, {});
39
40      // Render publications grouped by year
41      Object.entries(groupedByYear)
42        .sort(([a], [b]) =>
42 b - a) // Sort years descending
43        .forEach(([year, publications]) => {
44          // Year header
45          const yearHeader = el(
46            "div",
47            { class: "text-lg font-semibold text-slate-700 dark:text-slate-300 mb-4 pt-6 first:pt-0" },
48            year
49          );
50          container.appendChild(yearHeader);
51
52          // Publications for this year
53          publications.forEach((pub) => {
54            const links = [];
55            Object.entries(pub.links || {}).forEach(([k, v]) => {
56              if (v && v !== "#") {
57                links.push(
58                  el(
59                    "a",
60                    {
61                      href: v,
62                      target: "_blank",
63                      rel: "noreferrer",
64                      class: "text-xs px-3 py-1.5 rounded-lg border border-slate-200 dark:border-slate-700 underline hover:bg-slate-50 dark:hover:bg-slate-800 transition-colors",
65                    },
66                    k
67                  )
68                );
69              }
70            });
71
72            const tags = (pub.tags || []).map((t) =>
73              el(
74                "span",
75                {
76                  class: "text-xs px-2 py-1 rounded-full border border-slate-200 dark:border-slate-700 text-slate-500 bg-slate-50 dark:bg-slate-800",
77                },
78                t
79              )
80            );
81
82            const pubCard = el(
83              "article",
84              {
85                class: "publication-block bg-white dark:bg-slate-900 rounded-xl border border-slate-200 dark:border-slate-700 p-5 shadow-soft",
86              },
87              // Basic info (always visible)
88              el("div", { class: "font-semibold text-lg mb-2" }, pub.title ?? ""),
89              el(
90                "div",
91                { class: "text-sm text-slate-600 dark:text-slate-300 mb-2" },
92                pub.authors ?? ""
93              ),
94              el("div", { class: "text-sm font-medium mb-3" }, pub.venue ?? ""),
95              links.length ? el("div", { class: "my-4 flex gap-2 flex-wrap" }, links) : null,
96              tags.length ? el("div", { class: "mb-3 flex gap-2 flex-wrap" }, tags) : null,
97              pub.abstract ? el("details", { class: "mt-4 border-t border-slate-200 dark:border-slate-700 pt-4" },
98                el("summary", { class: "cursor-pointer text-sm font-medium text-blue-600 dark:text-blue-400" }, "Read abstract"),
99                el("p", { class: "text-sm text-slate-600 dark:text-slate-400 mt-3 leading-relaxed" }, pub.abstract)
100              ) : null
101            );
102            
103            container.appendChild(pubCard);
104          });
105        });
106
107      if (countElement) {
108        countElement.textContent = `${items.length} publication${items.length > 1 ? 's' : ''}`;
109      }
110    })
111    .catch((err) => {
112      console.error("Error loading publications:", err);
113      container.innerHTML = '<div class="text-center text-red-600 dark:text-red-400 py-8">Couldn\'t load publications.</div>';
114      if (countElement) countElement.textContent = "Error loading";
115    });
116}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.