prime8dev

prime8dev
git clone https://git.prime8.dev/prime8dev.git
Log | Files | Refs | README | LICENSE

about.js (3891B)


      1 import { getWakaTimeData, subscribeWakaTimeRefresh } from "./wakatime.js";
      2 
      3 let unsubscribeAboutRefresh = null;
      4 
      5 export function initAbout() {
      6   const statsContainer = document.getElementById("activity-stats");
      7   const section = document.getElementById("activity-section");
      8   if (!statsContainer || !section) return;
      9 
     10   function hideActivity() {
     11     section.style.display = "none";
     12   }
     13 
     14   async function loadActivityData(data = null) {
     15     if (!section.isConnected) {
     16       if (unsubscribeAboutRefresh) {
     17         unsubscribeAboutRefresh();
     18         unsubscribeAboutRefresh = null;
     19       }
     20       return;
     21     }
     22 
     23     try {
     24       const stats = data || (await getWakaTimeData());
     25 
     26       if (!stats || !stats.Weekly || !Array.isArray(stats.Weekly.Days)) {
     27         hideActivity();
     28         return;
     29       }
     30 
     31       const totalText = stats.Weekly.TotalText;
     32       const dayBars = stats.Weekly.Days;
     33       if (!totalText || dayBars.length === 0) {
     34         hideActivity();
     35         return;
     36       }
     37 
     38       const days = dayBars.map((bar) => ({
     39         dayText: (bar.DayText || "").toLowerCase(),
     40         timeText: bar.TimeText || "",
     41         barWidthPercent:
     42           bar.BarWidthPercent && typeof bar.BarWidthPercent === "string"
     43             ? bar.BarWidthPercent.trim()
     44             : "0%",
     45       }));
     46 
     47       renderWeeklyStats(statsContainer, totalText, days);
     48     } catch {
     49       hideActivity();
     50     }
     51   }
     52 
     53   loadActivityData();
     54 
     55   if (unsubscribeAboutRefresh) {
     56     unsubscribeAboutRefresh();
     57   }
     58   unsubscribeAboutRefresh = subscribeWakaTimeRefresh((data) => {
     59     void loadActivityData(data);
     60   });
     61 }
     62 
     63 function renderWeeklyStats(statsContainer, totalText, days) {
     64   statsContainer.innerHTML = "";
     65 
     66   const width = 24;
     67   const pre = document.createElement("pre");
     68   pre.className = "weekly-ascii";
     69 
     70   const totalLabel = document.createElement("span");
     71   totalLabel.className = "weekly-total-label";
     72   totalLabel.textContent = "total: ";
     73 
     74   const totalValue = document.createElement("span");
     75   totalValue.className = "weekly-total-value";
     76   totalValue.textContent = totalText;
     77 
     78   pre.appendChild(totalLabel);
     79   pre.appendChild(totalValue);
     80   pre.appendChild(document.createTextNode("\n\n"));
     81 
     82   days.forEach((day, index) => {
     83     const label = (day.dayText || "").slice(0, 3).padEnd(3, " ");
     84     const percent = clampPercent(day.barWidthPercent);
     85     const { filled, empty } = asciiBarSegments(percent, width);
     86 
     87     const dayLabel = document.createElement("span");
     88     dayLabel.className = "weekly-day-label";
     89     dayLabel.textContent = `${label} `;
     90 
     91     const barFrame = document.createElement("span");
     92     barFrame.className = "weekly-day-bar-frame";
     93     barFrame.appendChild(document.createTextNode("|"));
     94 
     95     const barFilled = document.createElement("span");
     96     barFilled.className = "weekly-day-bar-filled";
     97     barFilled.textContent = filled;
     98 
     99     const barEmpty = document.createElement("span");
    100     barEmpty.className = "weekly-day-bar-empty";
    101     barEmpty.textContent = empty;
    102 
    103     const dayTime = document.createElement("span");
    104     dayTime.className = "weekly-day-time";
    105     dayTime.textContent = ` ${day.timeText}`;
    106 
    107     barFrame.appendChild(barFilled);
    108     barFrame.appendChild(barEmpty);
    109     barFrame.appendChild(document.createTextNode("|"));
    110 
    111     pre.appendChild(dayLabel);
    112     pre.appendChild(barFrame);
    113     pre.appendChild(dayTime);
    114 
    115     if (index < days.length - 1) {
    116       pre.appendChild(document.createTextNode("\n"));
    117     }
    118   });
    119 
    120   statsContainer.appendChild(pre);
    121 }
    122 
    123 function clampPercent(value) {
    124   const parsed = Number.parseFloat((value || "0").replace("%", ""));
    125   if (!Number.isFinite(parsed)) return 0;
    126   if (parsed < 0) return 0;
    127   if (parsed > 100) return 100;
    128   return parsed;
    129 }
    130 
    131 function asciiBarSegments(percent, width) {
    132   const filled = Math.round((percent / 100) * width);
    133   return {
    134     filled: "#".repeat(filled),
    135     empty: "-".repeat(width - filled),
    136   };
    137 }
    138