春林沐雨 發表於 2025-5-29 14:21:00

solitude组件wakatime编码时长侧边栏

<p>本人博客原文<br>
https://www.konoxin.top/posts/82e0e7c7/</p>
<h1 id="前言">前言</h1>
<p>最近想在博客引入waketime的编码热力图,就研究了一下,</p>
<p>效果是这样的:</p>
<p><img src="https://img2024.cnblogs.com/other/3648630/202505/3648630-20250529142103239-1054053346.png" alt="" loading="lazy"></p>
<p>首先你已经使用过wakatime,</p>
<p>如果没有起前往如下教程,</p>
<p>{% link 'WakaTime的使用(vscode,idea,hbuilder)' 'WakaTime' 'https://juejin.cn/post/6981098690312142861' %}</p>
<h1 id="教程">教程</h1>
<h2 id="第一步">第一步</h2>
<p>接下来前往WakaTime的API文档</p>
<p>{% link 'WakaTime的API文档' 'WakaTime' 'https://wakatime.com/share/embed' %}</p>
<p>按照如下操作会得到json的接口</p>
<p><img src="https://img2024.cnblogs.com/other/3648630/202505/3648630-20250529142103661-1165488016.png" alt="" loading="lazy"></p>
<h2 id="第二步">第二步</h2>
<p>在source -&gt; _data -&gt; aside.yml (没有就新建)</p>
<p>下增加如下代码</p>
<pre><code class="language-js">- name: code
title: 编码时长
class: card-code
id:
icon: fas fa-calendar-days
content_id: code-info
# content_css: 'height:160px;overflow:hidden'
content_html: '&lt;div class="codeTime"&gt;&lt;div class="code" id="code"&gt;&lt;/div&gt;&lt;/div&gt;
    &lt;div class="legend"&gt;
      &lt;div class="legend-item"&gt;&lt;div class="legend-color" style="background: #ebedf0;"&gt;&lt;/div&gt;无数据&lt;/div&gt;
      &lt;div class="legend-item"&gt;&lt;div class="legend-color" style="background: #9be9a8;"&gt;&lt;/div&gt;0-2小时&lt;/div&gt;
      &lt;div class="legend-item"&gt;&lt;div class="legend-color" style="background: #40c463;"&gt;&lt;/div&gt;2-4小时&lt;/div&gt;
      &lt;div class="legend-item"&gt;&lt;div class="legend-color" style="background: #30a14e;"&gt;&lt;/div&gt;4-6小时&lt;/div&gt;
      &lt;div class="legend-item"&gt;&lt;div class="legend-color" style="background: #216e39;"&gt;&lt;/div&gt;6+小时&lt;/div&gt;
    &lt;/div&gt;'

</code></pre>
<p>然后在你的自定义入口 js 下输入</p>
<p>在source -&gt; js -&gt; 你的js (没有就新建)</p>
<p>在const response = await fetch('')引入你在wakatime得到的接口</p>
<pre><code class="language-js">async function fetchData() {

    try {
      // 使用CORS代理
      const response = await fetch(`https://wakatime.com/xxx.json`);
      const data = await response.json();
      // 修正数据访问路径
      if (data) {
            console.log('成功获取数据,天数:', data.days.length);
            return data.days;
      } else {
            console.warn('数据格式不符合预期:', data);
            return [];
      }
    } catch (error) {
      console.error('获取数据失败:', error);
      return [];
    }
}

function getColor(hours) {
    if (!hours || hours === 0) return '#ebedf0'; // 无数据或0小时显示灰色
    if (hours &lt; 2) return '#9be9a8'; // 0-2小时: 浅绿
    if (hours &lt; 4) return '#40c463'; // 2-4小时: 中绿
    if (hours &lt; 6) return '#30a14e'; // 4-6小时: 深绿
    return '#216e39'; // 6+小时: 最深绿
}

function renderCalendar(days) {
    const calendarEl = document.getElementById('code');
    const today = new Date();
    const startDate = new Date();
    startDate.setMonth(today.getMonth() - 11); // 显示最近12个月

    let currentDate = new Date(startDate);
    let currentMonth = currentDate.getMonth();

    // 添加月份标签
    // const monthLabel = document.createElement('div');
    // monthLabel.className = 'month-label';
    // monthLabel.textContent = currentDate.toLocaleString('zh-CN', { month: 'long' }) + ' ' + currentDate.getFullYear();
    // calendarEl.appendChild(monthLabel);

    // 跳过第一周的空白天数
    const firstDayOfWeek = currentDate.getDay();
    for (let i = 0; i &lt; firstDayOfWeek; i++) {
      const emptyDay = document.createElement('div');
      emptyDay.className = 'day';
      emptyDay.style.visibility = 'hidden';
      calendarEl.appendChild(emptyDay);
    }

    while (currentDate &lt;= today) {
      // 检查是否需要添加新的月份标签
      if (currentDate.getMonth() !== currentMonth) {
            currentMonth = currentDate.getMonth();
            // const monthLabel = document.createElement('div');
            // monthLabel.className = 'month-label';
            // monthLabel.textContent = currentDate.toLocaleString('zh-CN', { month: 'long' }) + ' ' + currentDate.getFullYear();
            // calendarEl.appendChild(monthLabel);
      }

      const dateStr = currentDate.toISOString().split('T');
      const dayData = days.find(d =&gt; d.date === dateStr);
      const hours = dayData ? dayData.total / 3600 : 0; // 使用total字段计算小时数

      const dayEl = document.createElement('div');
      dayEl.className = 'day';
      dayEl.style.backgroundColor = getColor(hours);
      dayEl.setAttribute('data-date', dateStr);
      dayEl.setAttribute('data-hours', hours.toFixed(1));

      calendarEl.appendChild(dayEl);

      currentDate.setDate(currentDate.getDate() + 1);
    }
}

(async function () {

    const data = await fetchData();
    renderCalendar(data);
})();

async function codeTime(){
    const data = await fetchData();
    renderCalendar(data);
}
function handlePjaxComplete() {
    if (isHomePage()) {
      codeTime()
    }
}

function isHomePage() {
    return window.location.pathname === '/' || window.location.pathname === '/index.html';
}

window.onload = function () {
    document.addEventListener("pjax:complete", handlePjaxComplete);
}
</code></pre>
<p>接下来在你的自定义入口 css下输入</p>
<p>在source -&gt; css -&gt; 你的css (没有就新建)</p>
<pre><code class="language-css">      .code {
          display: flex;
          flex-wrap: wrap;
          gap: 3px;
          margin-top: 7px;
      }

      .day {
          width: 10px;
          height: 10px;
          border-radius: 2px;
          background: #ebedf0;
          position: relative;
      }

      .day:hover::after {
          content: attr(data-date) " - " attr(data-hours) "小时";
          position: absolute;
          top: -30px;
          left: 50%;
          transform: translateX(-50%);
          background: #333;
          color: white;
          padding: 3px 6px;
          border-radius: 3px;
          font-size: 12px;
          white-space: nowrap;
          z-index: 100000;

      }

      .month-label {
          width: 100%;
          margin-top: 10px;
          font-size: 12px;
          color: #666;
      }

      .legend {
          margin-top: 5px;
          margin-bottom: 7px;
          display: flex;
          justify-content: space-between;
      }

      .legend-item {
          display: flex;
          align-items: center;
          font-size: 9px;
      }

      .legend-color {
          width: 12px;
          height: 12px;
          border-radius: 2px;
          margin-right: 5px;
      }
</code></pre>
<p>最后修改你的_config.solitude.yml 中的<code>aside</code>下的home新增<code>code</code></p>
<pre><code class="language-js">aside:
# Values: about (info card), newestPost (latest article), allInfo (website information), newest_comment (latest comment)
# 值: about(信息卡), newestPost(最新文章), allInfo(网站信息), newest_comment(最新评论)

# Sticky: Fixed position / noSticky: Not fixed position
# Sticky: 固定位置 / noSticky: 不固定位置
home: # on the homepage
    noSticky: "about"
    Sticky: "code,allInfo"
post: # on the article page
    noSticky: "about"
    Sticky: "newestPost"
page: # on the page
    noSticky: "about"
    Sticky: "newestPost,allInfo"
# 菜单栏位置(0: 左 1: 右)
position: 1 # Sidebar positioning(0: left 1: right)

</code></pre>
<p>以及在<code>extends</code>下的<code>head</code>引入你的 js 和 css</p>
<p>示例:</p>
<pre><code class="language-js">extends:
# Insert in head
# 插入到 head
head:
- &lt;link rel="stylesheet" href="/css/customize.css"&gt;
- &lt;script src="/js/custom.js"&gt;&lt;/script&gt;
</code></pre>
<p>最后在首页就出现效果啦!</p>
<blockquote>
<p>本文由博客一文多发平台 OpenWrite 发布!</p>
</blockquote><br><br>
来源:https://www.cnblogs.com/konoXIN/p/18902499
頁: [1]
查看完整版本: solitude组件wakatime编码时长侧边栏