Skip to content

侧边栏

公告欢迎卡片

  1. 修改主题配置文件,引入 jquery、welcome.js
yml
inject:
  head:
    - <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
  bottom:
    - <script src="https://blog.xdog.run/js/welcome.js"></script>
  1. 修改主题配置文件,开启公告侧边栏
yml
aside:
  card_announcement:
    enable: true
    content: '<div id="welcome-info"></div>'

welcome.js 代码备份

js
js
/**
 * @Author: 糖丸
 * @Date: 2023-06-18 16:18:51
 * @LastEditTime: 2023-07-27 12:33:20
 * @FilePath: \theme\source\js\welcome.js
 * @Tips: 纵使前路黑暗,也有可以照亮你的星光,而你自身就是光!
 */

//get请求
$.ajax({
    type: 'get',
    url: 'https://apis.map.qq.com/ws/location/v1/ip',
    data: {
        key: 'PV3BZ-HMSCT-UW6XY-VBKAB-6PV5E-7UFSX',
        output: 'jsonp',
    },
    dataType: 'jsonp',
    success: function (res) {
        // ipLocation = ipToNumber(res);
        ipLocation = res;
    }
})

// function ipToNumber(ip) {
// 	var numbers = ip.split(".");
// 	return parseInt(numbers[0])*256*256*256 +
// 	parseInt(numbers[1])*256*256 +   
// 	parseInt(numbers[2])*256 +
// 	parseInt(numbers[3]);
// }

// function numberToIp(number) {  
// 	return (Math.floor(number/(256*256*256))) + "." +   
// 	(Math.floor(number%(256*256*256)/(256*256))) + "." +   
// 	(Math.floor(number%(256*256)/256)) + "." +   
// 	(Math.floor(number%256));  
// }

function getDistance(e1, n1, e2, n2) {
    const R = 6371
    const { sin, cos, asin, PI, hypot } = Math
    let getPoint = (e, n) => {
        e *= PI / 180
        n *= PI / 180
        return { x: cos(n) * cos(e), y: cos(n) * sin(e), z: sin(n) }
    }

    let a = getPoint(e1, n1)
    let b = getPoint(e2, n2)
    let c = hypot(a.x - b.x, a.y - b.y, a.z - b.z)
    let r = asin(c / 2) * 2 * R
    return Math.round(r);
}

function showWelcome() {

    // 针对 pjax 的优化,防止在非公告页面也执行下面代码
    if(document.getElementById("welcome-info") === null){return;}
    let dist = getDistance(30.313172,120.382477, ipLocation.result.location.lng, ipLocation.result.location.lat); //这里记得换成自己的经纬度
    let pos = ipLocation.result.ad_info.nation;
    let ip;
    let posdesc;
    //根据国家、省份、城市信息自定义欢迎语
    switch (ipLocation.result.ad_info.nation) {
        case "日本":
            posdesc = "よろしく,一起去看樱花吗";
            break;
        case "美国":
            posdesc = "Let us live in peace!";
            break;
        case "英国":
            posdesc = "想同你一起夜乘伦敦眼";
            break;
        case "俄罗斯":
            posdesc = "干了这瓶伏特加!";
            break;
        case "法国":
            posdesc = "C'est La Vie";
            break;
        case "德国":
            posdesc = "Die Zeit verging im Fluge.";
            break;
        case "澳大利亚":
            posdesc = "一起去大堡礁吧!";
            break;
        case "加拿大":
            posdesc = "拾起一片枫叶赠予你";
            break;
        case "中国":
            pos = ipLocation.result.ad_info.province + " " + ipLocation.result.ad_info.city + " " + ipLocation.result.ad_info.district;
            ip = ipLocation.result.ip;
            switch (ipLocation.result.ad_info.province) {
                case "北京市":
                    posdesc = "北——京——欢迎你~~~";
                    break;
                case "天津市":
                    posdesc = "讲段相声吧";
                    break;
                case "河北省":
                    posdesc = "山势巍巍成壁垒,天下雄关铁马金戈由此向,无限江山";
                    break;
                case "山西省":
                    posdesc = "展开坐具长三尺,已占山河五百余";
                    break;
                case "内蒙古自治区":
                    posdesc = "天苍苍,野茫茫,风吹草低见牛羊";
                    break;
                case "辽宁省":
                    posdesc = "我想吃烤鸡架!";
                    break;
                case "吉林省":
                    posdesc = "状元阁就是东北烧烤之王";
                    break;
                case "黑龙江省":
                    posdesc = "很喜欢哈尔滨大剧院";
                    break;
                case "上海市":
                    posdesc = "众所周知,中国只有两个城市";
                    break;
                case "江苏省":
                    switch (ipLocation.result.ad_info.city) {
                        case "南京市":
                            posdesc = "这是我挺想去的城市啦";
                            break;
                        case "苏州市":
                            posdesc = "上有天堂,下有苏杭";
                            break;
                        default:
                            posdesc = "散装是必须要散装的";
                            break;
                    }
                    break;
                case "浙江省":
                    posdesc = "东风渐绿西湖柳,雁已还人未南归!博主家乡~ 欢迎来玩~";
                    break;
                case "河南省":
                    switch (ipLocation.result.ad_info.city) {
                        case "郑州市":
                            posdesc = "豫州之域,天地之中";
                            break;
                        case "南阳市":
                            posdesc = "臣本布衣,躬耕于南阳此南阳非彼南阳!";
                            break;
                        case "驻马店市":
                            posdesc = "峰峰有奇石,石石挟仙气嵖岈山的花很美哦!";
                            break;
                        case "开封市":
                            posdesc = "刚正不阿包青天";
                            break;
                        case "洛阳市":
                            posdesc = "洛阳牡丹甲天下";
                            break;
                        default:
                            posdesc = "可否带我品尝河南烩面啦?";
                            break;
                    }
                    break;
                case "安徽省":
                    switch (ipLocation.result.ad_info.city) {
                        case "合肥市":
                            posdesc = "一座让你“乐不思蜀”的城市!";
                            break;
                        case "安庆市":
                            switch (ipLocation.result.ad_info.district) {
                                case "潜山市":
                                    posdesc = "我在天柱山很想你😘";
                                    break;
                            }
                            break;
                            default:
                                posdesc = "千里轻帆外,层层见水楼";
                                break;
                            }
                    break;
                case "福建省":
                    posdesc = "井邑白云间,岩城远带山";
                    break;
                case "江西省":
                    posdesc = "落霞与孤鹜齐飞,秋水共长天一色";
                    break;
                case "山东省":
                    posdesc = "遥望齐州九点烟,一泓海水杯中泻";
                    break;
                case "湖北省":
                    switch (ipLocation.result.ad_info.city) {
                        case "黄冈市":
                            posdesc = "红安将军县!辈出将才!";
                            break;
                        default:
                            posdesc = "来碗热干面~";
                            break;
                    }
                    break;
                case "湖南省":
                    posdesc = "74751,长沙斯塔克";
                    break;
                case "广东省":
                    switch (ipLocation.result.ad_info.city) {
                        case "广州市":
                            posdesc = "看小蛮腰,喝早茶了嘛~";
                            break;
                        case "深圳市":
                            posdesc = "今天你逛商场了嘛~";
                            break;
                        case "阳江市":
                            posdesc = "阳春合水!";
                            break;
                        default:
                            posdesc = "来两斤福建人~";
                            break;
                    }
                    break;
                case "广西壮族自治区":
                    posdesc = "桂林山水甲天下";
                    break;
                case "海南省":
                    posdesc = "朝观日出逐白浪,夕看云起收霞光";
                    break;
                case "四川省":
                    posdesc = "康康川妹子";
                    break;
                case "贵州省":
                    posdesc = "茅台,学生,再塞200";
                    break;
                case "云南省":
                    posdesc = "玉龙飞舞云缠绕,万仞冰川直耸天";
                    break;
                case "西藏自治区":
                    posdesc = "躺在茫茫草原上,仰望蓝天";
                    break;
                case "陕西省":
                    posdesc = "来份臊子面加馍";
                    break;
                case "甘肃省":
                    posdesc = "羌笛何须怨杨柳,春风不度玉门关";
                    break;
                case "青海省":
                    posdesc = "牛肉干和老酸奶都好好吃";
                    break;
                case "宁夏回族自治区":
                    posdesc = "大漠孤烟直,长河落日圆";
                    break;
                case "新疆维吾尔自治区":
                    posdesc = "驼铃古道丝绸路,胡马犹闻唐汉风";
                    break;
                case "台湾省":
                    posdesc = "我在这头,大陆在那头";
                    break;
                case "香港特别行政区":
                    posdesc = "永定贼有残留地鬼嚎,迎击光非岁玉";
                    break;
                case "澳门特别行政区":
                    posdesc = "性感荷官,在线发牌";
                    break;
                default:
                    posdesc = "带我去你的城市逛逛吧!";
                    break;
            }
            break;
        default:
            posdesc = "带我去你的国家逛逛吧";
            break;
    }

    //根据本地时间切换欢迎语
    let timeChange;
    let date = new Date();
    if (date.getHours() >= 5 && date.getHours() < 11) timeChange = "<span>🌤️ 早上好,一日之计在于晨</span>";
    else if (date.getHours() >= 11 && date.getHours() < 13) timeChange = "<span>☀️ 中午好,记得午休喔~</span>";
    else if (date.getHours() >= 13 && date.getHours() < 17) timeChange = "<span>🕞 下午好,饮茶先啦!</span>";
    else if (date.getHours() >= 17 && date.getHours() < 19) timeChange = "<span>🚶‍♂️ 即将下班,记得按时吃饭~</span>";
    else if (date.getHours() >= 19 && date.getHours() < 24) timeChange = "<span>🌙 晚上好,夜生活嗨起来!</span>";
    else timeChange = "夜深了,早点休息,少熬夜";

    try {
        //自定义文本和需要放的位置
        document.getElementById("welcome-info").innerHTML =
            `欢迎来自<br><span style="font-size: 12px;"><b><span style="color: #49B1F5;">${pos}</span></b> 的小友💖</span><br><span style="font-size: 12px;">当前位置距博主约 <b><span style="color: #49B1F5;">${dist}</span></b> 公里!<br>您的IP地址为: <b><span>${ip}</span></b><br>${timeChange} <br></span>`;
            // `欢迎来自<br><b><span style="color: var(--kouseki-ip-color);font-size: var(--kouseki-gl-size);">${pos}</span></b> 的小友💖<br><span style="font-size: 12px;"> ${posdesc}🍂</span><br>当前位置距博主约 <b><span style="color: var(--kouseki-ip-color);">${dist}</span></b> 公里!<br>您的IP地址为: <b><span>${ip}</span></b><br>${timeChange} <br>`;
    } catch (err) {
         console.log("Pjax无法获取元素")
    }
}
window.onload = showWelcome;
// 如果使用了pjax在加上下面这行代码
document.addEventListener('pjax:complete', showWelcome);

如腾讯地图key额度用完自行申请:https://lbs.qq.com/service/webService/webServiceGuide/position/webServiceIp

注意:有一个小问题,ajax请求的 第三方 cookie 会导致浏览器控制台出现三个 Third-party cookie will be blocked. Learn more in the Issues tab. 提示,在浏览器设置阻止第三方cookie即可

彩色标签云

自带的彩色标签云太丑了,以前就觉得typecho的那种很好看,直接拿来!

  1. 修改themes\butterfly\scripts\helpers\page.js
diff
hexo.extend.helper.register('cloudTags', function (options = {}) {
  const env = this
  let { source, minfontsize, maxfontsize, limit, unit = 'px', orderby, order } = options
+ source = source.sort('length').reverse() //标签从大到小排序

  if (limit > 0) {
    source = source.limit(limit)
  }

  const sizes = [...new Set(source.map(tag => tag.length).sort((a, b) => a - b))]

- const getRandomColor = () => {
-   const randomColor = () => Math.floor(Math.random() * 201)
-   const r = randomColor()
-   const g = randomColor()
-   const b = randomColor()
-   return `rgb(${Math.max(r, 50)}, ${Math.max(g, 50)}, ${Math.max(b, 50)})`
- }

+ const getRandomColor = () => {
+   const colors = [
+     'rgb(66, 139, 202)',    // 蓝色
+     'rgb(236, 169, 167)',   // 粉色
+     'rgb(218, 153, 255)',   // 紫色
+     'rgb(174, 220, 174)',   // 绿色
+     'rgb(217, 185, 153)',   // 棕色
+     'rgb(255, 179, 128)'    // 黄色
+   ];
+   return colors[Math.floor(Math.random() * colors.length)]
+ }

  const generateStyle = (size, unit) =>
-   `font-size: ${parseFloat(size.toFixed(2)) + unit}; color: ${getRandomColor()};`
+   `font-size: ${parseFloat(size.toFixed(2)) + unit}; margin: 2px 2px;color: white;border-radius: 10px;background-color: ${getRandomColor()};`

  const length = sizes.length - 1
  const result = source.sort(orderby, order).map(tag => {
    const ratio = length ? sizes.indexOf(tag.length) / length : 0
    const size = minfontsize + ((maxfontsize - minfontsize) * ratio)
    const style = generateStyle(size, unit)
-   return `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}</a>`
+   return `<a href="${env.url_for(tag.path)}" style="${style}">${tag.name}<sup>${tag.length}</sup></a>` //添加标签数量角标
  }).join('')

  return result
})
  1. 去除侧边栏彩色标签字体大小变化,修改themes\butterfly\layout\includes\widget\card_tags.pug
diff
      if theme.aside.card_tags.color
-       .card-tag-cloud!= cloudTags({source: site.tags, orderby: orderby, order: order, minfontsize: 1.15, maxfontsize: 1.45, limit: limit, unit: 'em'})
+       .card-tag-cloud!= cloudTags({source: site.tags, orderby: orderby, order: order, minfontsize: 0.9, maxfontsize: 1.1, limit: limit, unit: 'em'})
      else
        .card-tag-cloud!= tagcloud({orderby: orderby, order: order, min_font: 1.1, max_font: 1.5, amount: limit , color: true, start_color: '#999', end_color: '#99a9bf', unit: 'em'})
  1. CSS
css
#aside-content .card-tag-cloud a {
    font-weight: 600;
}

#aside-content .card-tag-cloud a:hover {
    color: #fff !important;
    transform: translateY(-2px);
    background-color: var(--btn-hover-color) !important;
}
  1. 最后在主题配置里开启侧边栏标签颜色即可
yml
aside:
  card_tags:
    color: true

移动端侧边栏增加标签云

  1. 修改themes\butterfly\layout\includes\sidebar.pug,替换为以下内容
diff
    hr.custom-hr
    !=partial('includes/header/menu_item', {}, {cache: true})

+   if theme.aside.card_tags.enable
+     if site.tags.length
+       .card-widget.card-tags
+         span= _p('aside.card_tags')
+
+         - let { limit, orderby, order } = theme.aside.card_tags
+         - limit = limit === 0 ? 0 : limit || 40
+
+         if theme.aside.card_tags.color
+           .card-tag-cloud!= cloudTags({source: site.tags, orderby: orderby, order: order, minfontsize: 0.9, maxfontsize: 1.1, limit: limit, unit: 'em'})
+         else
+           .card-tag-cloud!= tagcloud({orderby: orderby, order: order, min_font: 1.1, max_font: 1.5, amount: limit , color: true, start_color: '#999', end_color: '#99a9bf', unit: 'em'})
  1. css
css
#sidebar #sidebar-menus .card-tag-cloud {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    margin: 20px;
}
#sidebar #sidebar-menus .card-tag-cloud a {
    padding: 0 4px;
}

微信公众号引流卡片

  1. 新建文件source\_data\widget.yml
yml
bottom:
  - class_name: wechat-widget
    id_name: card-wechat
    name:
    icon:
    order: 1
    html: '
          <div id="flip-wrapper">
              <div id="flip-content">
                  <div class="face"
                      style="background:url(https://cdn.xdog.top/site/face.png) center center/100% no-repeat">
                  </div>
                  <div class="back face"
                      style="background:url(https://cdn.xdog.top/site/back_face.png) center center/100% no-repeat">
                  </div>
              </div>
          </div>
          '
  1. CSS
CSS
css
#aside-content .card-widget#card-wechat {
  background: #57bd6a;
  display: flex;
  justify-content: center;
  align-content: center;
  padding: 0;
  cursor: pointer;
  border: none;
  height: 110px;
}

#flip-wrapper {
  position: relative;
  width: 235px;
  height: 110px;
  z-index: 1;
}

#flip-content {
  width: 100%;
  height: 100%;
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
  transition: cubic-bezier(0,0,0,1.29) .3s;
}

#aside-content #flip-wrapper #flip-content .face {
  position: absolute;
  width: 100%;
  height: 100%;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  background-size: 100%;
}

#aside-content #flip-wrapper #flip-content .back.face {
  display: block;
  -webkit-transform: rotateY(180deg);
  transform: rotateY(180deg);
  box-sizing: border-box;
  background-size: 100%;
}

#flip-wrapper:hover #flip-content {
  -webkit-transform: rotateY(180deg);
  transform: rotateY(180deg);
}

人生倒计时侧边栏

  1. 修改主题配置文件,引入 jquery
yml
inject:
  head:
    - <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
  bottom:
  1. 新建文件source\_data\widget.yml
yml
bottom:
  - class_name: aside aside-count
    id_name:
    name: 人生倒计时
    icon: fas fa-hourglass-half
    order: 1
    html:   '<div class="content">
                <div class="item" id="dayProgress">
                    <div class="title">今日已经过去<span></span>小时</div>
                    <div class="progress">
                        <div class="progress-bar">
                            <div class="progress-inner progress-inner-1"></div>
                        </div>
                        <div class="progress-percentage"></div>
                    </div>
                </div>
                <div class="item" id="weekProgress">
                    <div class="title">这周已经过去<span></span>天</div>
                    <div class="progress">
                        <div class="progress-bar">
                            <div class="progress-inner progress-inner-2"></div>
                        </div>
                        <div class="progress-percentage"></div>
                    </div>
                </div>
                <div class="item" id="monthProgress">
                    <div class="title">本月已经过去<span></span>天</div>
                    <div class="progress">
                        <div class="progress-bar">
                            <div class="progress-inner progress-inner-3"></div>
                        </div>
                        <div class="progress-percentage"></div>
                    </div>
                </div>
                <div class="item" id="yearProgress">
                    <div class="title">今年已经过去<span></span>个月</div>
                    <div class="progress">
                        <div class="progress-bar">
                            <div class="progress-inner progress-inner-4"></div>
                        </div>
                        <div class="progress-percentage"></div>
                    </div>
                </div>
            </div>'
  1. css
CSS
CSS
/*人生倒计时侧边栏*/
.aside-count .content .item {
    margin-bottom: 5px;
    line-height: initial;
}

.aside-count .content .item:last-child {
    margin-bottom: 0
}
 
.aside-count .content .item .title {
    font-size: 12px;
    color: var(--minor);
    display: flex;
    align-items: center
}
 
.aside-count .content .item .title span {
    color: var(--theme);
    font-weight: 500;
    font-size: 14px;
    margin: 0 5px
}
 
.aside-count .content .item .progress {
    display: flex;
    align-items: center
}
 
.aside-count .content .item .progress .progress-bar {
    height: 10px;
    border-radius: 5px;
    overflow: hidden;
    background: var(--classC);
    width: 0;
    min-width: 0;
    flex: 1;
    margin-right: 5px
}
@keyframes progress {
    0% {
        background-position: 0 0
    }
 
    100% {
        background-position: 30px 0
    }
}
.aside-count .content .item .progress .progress-bar .progress-inner {
    width: 0;
    height: 100%;
    border-radius: 5px;
    transition: width 0.35s;
    -webkit-animation: progress 750ms linear infinite;
    animation: progress 750ms linear infinite
}
 
.aside-count .content .item .progress .progress-bar .progress-inner-1 {
    background: #bde6ff;
    background-image: linear-gradient(135deg, #50bfff 25%, transparent 25%, transparent 50%, #50bfff 50%, #50bfff 75%, transparent 75%, transparent 100%);
    background-size: 30px 30px
}
 
.aside-count .content .item .progress .progress-bar .progress-inner-2 {
    background: #ffd980;
    background-image: linear-gradient(135deg, #f7ba2a 25%, transparent 25%, transparent 50%, #f7ba2a 50%, #f7ba2a 75%, transparent 75%, transparent 100%);
    background-size: 30px 30px
}
 
.aside-count .content .item .progress .progress-bar .progress-inner-3 {
    background: #ffa9a9;
    background-image: linear-gradient(135deg, #ff4949 25%, transparent 25%, transparent 50%, #ff4949 50%, #ff4949 75%, transparent 75%, transparent 100%);
    background-size: 30px 30px
}
 
.aside-count .content .item .progress .progress-bar .progress-inner-4 {
    background: #67c23a;
    background-image: linear-gradient(135deg, #4f9e28 25%, transparent 25%, transparent 50%, #4f9e28 50%, #4f9e28 75%, transparent 75%, transparent 100%);
    background-size: 30px 30px
}
  1. js
JS
js
/*人生倒计时侧边栏*/
function init_life_time() {
    if (document.querySelector('.aside-count') == null) { return; }
    function getAsideLifeTime() {
        let nowDate = +new Date();
        let todayStartDate = new Date(new Date().toLocaleDateString()).getTime();
        let todayPassHours = (nowDate - todayStartDate) / 1000 / 60 / 60;
        let todayPassHoursPercent = (todayPassHours / 24) * 100;
        $('#dayProgress .title span').html(parseInt(todayPassHours));
        $('#dayProgress .progress .progress-inner').css('width', parseInt(todayPassHoursPercent) + '%');
        $('#dayProgress .progress .progress-percentage').html(parseInt(todayPassHoursPercent) + '%');
        let weeks = {
            0: 7,
            1: 1,
            2: 2,
            3: 3,
            4: 4,
            5: 5,
            6: 6
        };
        let weekDay = weeks[new Date().getDay()];
        let weekDayPassPercent = (weekDay / 7) * 100;
        $('#weekProgress .title span').html(weekDay);
        $('#weekProgress .progress .progress-inner').css('width', parseInt(weekDayPassPercent) + '%');
        $('#weekProgress .progress .progress-percentage').html(parseInt(weekDayPassPercent) + '%');
        let year = new Date().getFullYear();
        let date = new Date().getDate();
        let month = new Date().getMonth() + 1;
        let monthAll = new Date(year, month, 0).getDate();
        let monthPassPercent = (date / monthAll) * 100;
        $('#monthProgress .title span').html(date);
        $('#monthProgress .progress .progress-inner').css('width', parseInt(monthPassPercent) + '%');
        $('#monthProgress .progress .progress-percentage').html(parseInt(monthPassPercent) + '%');
        let yearPass = (month / 12) * 100;
        $('#yearProgress .title span').html(month);
        $('#yearProgress .progress .progress-inner').css('width', parseInt(yearPass) + '%');
        $('#yearProgress .progress .progress-percentage').html(parseInt(yearPass) + '%');
    }
    getAsideLifeTime();
    setInterval(() => {
        getAsideLifeTime();
    }, 1000);
}
init_life_time()