繁花

繁花

想成为一个有用的人

Typecho VOID 个人优化方案

今天是七夕,但不是因为没有对象才伤心的。

小理发的😶

什么年代还用传统 VOID🤣#

太没实力了直接给我🪑👇

这里相当多内容都得感谢友链里的 Given、老园和千秋助我一臂之力。
我们四个人是一个 17 年发起的小团体,大家天涯各异,从初中玩到高中玩到大学,个个都是人才,说话又好听🥰

首页瀑布流文章圆角#

和原版的对比

在 VOID 主 css 找到 section#index-list>ul>li 往里面加

border-radius: 1.5rem;overflow: hidden;

右键复制弹窗#

image

oncopy 加个 sweetalert2 就完事了,任何网页都可以使用。

打开主题的文件夹找到includes\footer.php
往最下面那一滑在</body><?php endif; ?>前加入如下代码

<script src="https://cdn.jsdelivr.net/npm/sweetalert2@8"></script>
<script>document.body.oncopy = function(){Swal.fire({allowOutsideClick:false,type:'success',title: '复制成功,如转载请注明出处!',showConfirmButton: false,timer: 2000});};</script>

圆点小指针#

image

在 Xecades 大佬的这篇文章学来的,但是实际对 VOID 的使用观感并不好,后来就没有用。

cursor.css

        #cursor {
            position: fixed;
            width: 16px;
            height: 16px;
            background: #694d4d;
            border-radius: 8px;
            opacity: 0.25;
            z-index: 10086;
            pointer-events: none;
            transition: 0.2s ease-in-out;
            transition-property: background, opacity, transform;
        }

        #cursor.hidden {
            opacity: 0;
        }

        #cursor.hover {
            opacity: 0.1;
            transform: scale(2.5);
        }

        #cursor.active {
            opacity: 0.5;
            transform: scale(0.5);
        }

cursor.js

        var CURSOR;

        Math.lerp = (a, b, n) => (1 - n) * a + n * b;

        const getStyle = (el, attr) => {
            try {
                return window.getComputedStyle
                    ? window.getComputedStyle(el)[attr]
                    : el.currentStyle[attr];
            } catch (e) { }
            return "";
        };

        class Cursor {
            constructor() {
                this.pos = { curr: null, prev: null };
                this.pt = [];
                this.create();
                this.init();
                this.render();
            }

            move(left, top) {
                this.cursor.style["left"] = `${left}px`;
                this.cursor.style["top"] = `${top}px`;
            }

            create() {
                if (!this.cursor) {
                    this.cursor = document.createElement("div");
                    this.cursor.id = "cursor";
                    this.cursor.classList.add("hidden");
                    document.body.append(this.cursor);
                }

                var el = document.getElementsByTagName('*');
                for (let i = 0; i < el.length; i++)
                    if (getStyle(el[i], "cursor") == "pointer")
                        this.pt.push(el[i].outerHTML);
                document.body.appendChild((this.scr = document.createElement("style")));
                this.scr.innerHTML = `* {cursor: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8' width='8px' height='8px'><circle cx='4' cy='4' r='4' opacity='.5'/></svg>") 4 4, auto !important}`;
            }

            refresh() {
                this.scr.remove();
                this.cursor.classList.remove("hover");
                this.cursor.classList.remove("active");
                this.pos = { curr: null, prev: null };
                this.pt = [];
                this.create();
                this.init();
                this.render();
            }

            init() {
                document.onmouseover = e => this.pt.includes(e.target.outerHTML) && this.cursor.classList.add("hover");
                document.onmouseout = e => this.pt.includes(e.target.outerHTML) && this.cursor.classList.remove("hover");
                document.onmousemove = e => { (this.pos.curr == null) && this.move(e.clientX - 8, e.clientY - 8); this.pos.curr = { x: e.clientX - 8, y: e.clientY - 8 }; this.cursor.classList.remove("hidden"); };
                document.onmouseenter = e => this.cursor.classList.remove("hidden");
                document.onmouseleave = e => this.cursor.classList.add("hidden");
                document.onmousedown = e => this.cursor.classList.add("active");
                document.onmouseup = e => this.cursor.classList.remove("active");
            }

            render() {
                if (this.pos.prev) {
                    this.pos.prev.x = Math.lerp(this.pos.prev.x, this.pos.curr.x, 0.15);
                    this.pos.prev.y = Math.lerp(this.pos.prev.y, this.pos.curr.y, 0.15);
                    this.move(this.pos.prev.x, this.pos.prev.y);
                } else {
                    this.pos.prev = this.pos.curr;
                }
                requestAnimationFrame(() => this.render());
            }
        }

        (() => {
            CURSOR = new Cursor();
        })();

F12 提示条#

image

snackbar.css

/* Snackbar */
.snackbar-container {
    background: #425AEF!important;
    color: #fff!important;
    border-radius: 0!important;
    display: flex!important;
    justify-content: center!important;
    max-width: none!important;
    min-width: 100%!important;
    margin: 0!important;
    left: 0!important;
    height: 60px!important;
    transform: none!important;
}

@keyframes snackbar-progress{from{width:0}to{width:100%}}

.snackbar-container:after {
    position: absolute;
    width: 0;
    height: 100%;
    left: 0;
    top: 0;
    background: #fff;
    opacity: .1;
    content: "";
    animation: snackbar-progress var(--snackbar-time) linear forwards;
    pointer-events: none;
}

core.js

var utils = {
    snackbarShow: function(e, t, n) {
        var r = void 0 !== t && t,
            o = void 0 !== n ? n : 5e3,
            i = "top-center",
            a = "light" === document.documentElement.getAttribute("data-theme") ? "#49b1f5" : "#121212";
        document.styleSheets[0].addRule(":root", "--snackbar-time:" + o + "ms!important"), Snackbar.show({ text: e, backgroundColor: a, showAction: r, duration: o, pos: i })
    }
}

window.onkeydown = function(e) { 123 === e.keyCode && utils.snackbarShow("开发者模式已打开,请遵循GPL协议", !1, 3e3) };


snackbar.js

/*!
 * Snackbar v0.1.14
 * http://polonel.com/Snackbar
 *
 * Copyright 2018 Chris Brame and other contributors
 * Released under the MIT license
 * https://github.com/polonel/Snackbar/blob/master/LICENSE
 */

(function(root, factory) {
    'use strict';

    if (typeof define === 'function' && define.amd) {
        define([], function() {
            return (root.Snackbar = factory());
        });
    } else if (typeof module === 'object' && module.exports) {
        module.exports = root.Snackbar = factory();
    } else {
        root.Snackbar = factory();
    }
})(this, function() {
    var Snackbar = {};

    Snackbar.current = null;
    var $defaults = {
        text: 'Default Text',
        textColor: '#FFFFFF',
        width: 'auto',
        showAction: true,
        actionText: 'Dismiss',
        actionTextAria: 'Dismiss, Description for Screen Readers',
        alertScreenReader: false,
        actionTextColor: '#4CAF50',
        showSecondButton: false,
        secondButtonText: '',
        secondButtonAria: 'Description for Screen Readers',
        secondButtonTextColor: '#4CAF50',
        backgroundColor: '#323232',
        pos: 'bottom-left',
        duration: 5000,
        customClass: '',
        onActionClick: function(element) {
            element.style.opacity = 0;
        },
        onSecondButtonClick: function(element) {},
        onClose: function(element) {}
    };

    Snackbar.show = function($options) {
        var options = Extend(true, $defaults, $options);

        if (Snackbar.current) {
            Snackbar.current.style.opacity = 0;
            setTimeout(
                function() {
                    var $parent = this.parentElement;
                    if ($parent)
                    // possible null if too many/fast Snackbars
                        $parent.removeChild(this);
                }.bind(Snackbar.current),
                500
            );
        }

        Snackbar.snackbar = document.createElement('div');
        Snackbar.snackbar.className = 'snackbar-container ' + options.customClass;
        Snackbar.snackbar.style.width = options.width;
        var $p = document.createElement('p');
        $p.style.margin = 0;
        $p.style.padding = 0;
        $p.style.color = options.textColor;
        $p.style.fontSize = '18px';
        $p.style.fontWeight = 300;
        $p.style.lineHeight = '1em';
        $p.innerHTML = options.text;
        Snackbar.snackbar.appendChild($p);
        Snackbar.snackbar.style.background = options.backgroundColor;

        if (options.showSecondButton) {
            var secondButton = document.createElement('button');
            secondButton.className = 'action';
            secondButton.innerHTML = options.secondButtonText;
            secondButton.setAttribute('aria-label', options.secondButtonAria);
            secondButton.style.color = options.secondButtonTextColor;
            secondButton.addEventListener('click', function() {
                options.onSecondButtonClick(Snackbar.snackbar);
            });
            Snackbar.snackbar.appendChild(secondButton);
        }

        if (options.showAction) {
            var actionButton = document.createElement('button');
            actionButton.className = 'action';
            actionButton.innerHTML = options.actionText;
            actionButton.setAttribute('aria-label', options.actionTextAria);
            actionButton.style.color = options.actionTextColor;
            actionButton.addEventListener('click', function() {
                options.onActionClick(Snackbar.snackbar);
            });
            Snackbar.snackbar.appendChild(actionButton);
        }

        if (options.duration) {
            setTimeout(
                function() {
                    if (Snackbar.current === this) {
                        Snackbar.current.style.opacity = 0;
                        // When natural remove event occurs let's move the snackbar to its origins
                        Snackbar.current.style.top = '-100px';
                        Snackbar.current.style.bottom = '-100px';
                    }
                }.bind(Snackbar.snackbar),
                options.duration
            );
        }

        if (options.alertScreenReader) {
           Snackbar.snackbar.setAttribute('role', 'alert');
        }

        Snackbar.snackbar.addEventListener(
            'transitionend',
            function(event, elapsed) {
                if (event.propertyName === 'opacity' && this.style.opacity === '0') {
                    if (typeof(options.onClose) === 'function')
                        options.onClose(this);

                    this.parentElement.removeChild(this);
                    if (Snackbar.current === this) {
                        Snackbar.current = null;
                    }
                }
            }.bind(Snackbar.snackbar)
        );

        Snackbar.current = Snackbar.snackbar;

        document.body.appendChild(Snackbar.snackbar);
        var $bottom = getComputedStyle(Snackbar.snackbar).bottom;
        var $top = getComputedStyle(Snackbar.snackbar).top;
        Snackbar.snackbar.style.opacity = 1;
        Snackbar.snackbar.className =
            'snackbar-container ' + options.customClass + ' snackbar-pos ' + options.pos;
    };

    Snackbar.close = function() {
        if (Snackbar.current) {
            Snackbar.current.style.opacity = 0;
        }
    };

    // Pure JS Extend
    // http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/
    var Extend = function() {
        var extended = {};
        var deep = false;
        var i = 0;
        var length = arguments.length;

        if (Object.prototype.toString.call(arguments[0]) === '[object Boolean]') {
            deep = arguments[0];
            i++;
        }

        var merge = function(obj) {
            for (var prop in obj) {
                if (Object.prototype.hasOwnProperty.call(obj, prop)) {
                    if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') {
                        extended[prop] = Extend(true, extended[prop], obj[prop]);
                    } else {
                        extended[prop] = obj[prop];
                    }
                }
            }
        };

        for (; i < length; i++) {
            var obj = arguments[i];
            merge(obj);
        }

        return extended;
    };

    return Snackbar;
});

顶栏小图标#

image

这个直接动了header.php把原来的顶栏链接改成了自己带图标的链接👉👈
以后还得手动改,没有一劳永逸的方法👉👈

调用好 fontawesome、remixicon、feathericons 这种图标包之后在<span class="dropdown">或者其他 a 标签内加图标代码即可

首页瀑布流文章页头一言#

image

在主题文件夹下的includes\banner.php的 107 行左右<div align="center" class="container wide">插入如下代码

<style>.headline{color:#999;font-size:1.3em;font-weight:300;margin:1.5em 0;position:relative;padding:25px 0;text-align:center;border-top:1px solid rgba(0,0,0,.05);border-bottom:1px solid rgba(0,0,0,.05)}.theme-dark .headline{border-color:rgba(255,255,255,.05)}</style><p id="hitokoto" class="headline" itemprop="headline"><span id="hitokoto_text">:D 让子弹飞一会儿</span></p><script src="https://v1.hitokoto.cn/?encode=js&select=%23hitokoto&c=i" defer></script>

如果你是个精神洁癖,发现首页一言不支持免刷新加载,请在后台主题设置PJAX 重载函数中加入

fetch('https://v1.hitokoto.cn')
    .then(response => response.json())
    .then(data => {
      const hitokoto = document.querySelector('#hitokoto_text')     
      hitokoto.innerText = data.hitokoto
 })
    .catch(console.error)

如果你是个重度精神洁癖,发现不在首页时 console 就会报 pjax 代码中找不到一言函数的错误时
请不要惊慌,无论你怎么百度怎么if page=index都还是会报错的

解决方法一:当你打开 f12 时,刺瞎你的眼睛。
解决方法二:在 footer 也加一个hitokoto_text,当你的眼睛移到 footer 时刺瞎你的眼睛。
解决方法三:只需要在footer 标签输出内容中插入

<div id="hitokoto_text" style="display: none;">&nbsp;</div>

你看,刺瞎这个在 footer 的 hitokoto 的眼睛显然要好一点😘

文章标题下信息美化#

image

我挺讨厌 VOID 带的这个请注意,本文编写于 * 天前,最后修改于 * 天前,其中某些信息可能已经过时,所以我直接把修改日期搬到了标题下信息栏。

依然还是在includes\banner.php大约 68 行左右找到以下代码

<span><a href="<?php $this->author->permalink(); ?>"><?php $this->author(); ?></a></span>&nbsp;&nbsp;
<time datetime="<?php echo date('c', $this->created); ?>"><?php echo date('Y-m-d', $this->created); ?></time>
&nbsp;&nbsp;<a no-pjax target="_self" href="javascript:void(0);" onclick="VOID_SmoothScroller.scrollTo('#comments', -60)"><?php $this->commentsNum(); ?>&nbsp;评论</a>
<?php if($setting['VOIDPlugin']) echo '&nbsp;•&nbsp;<span>'.$this->viewsNum.'&nbsp;阅读</span>'; ?>

替换成

<span>
<i class="ri-rest-time-line" style="padding-right: 5px;"></i> <time datetime="<?php echo date('c', $this->created); ?>"><?php echo date('Y-m-d', $this->created); ?></time>
<?php $postCheck = Utils::isOutdated($this); if($postCheck["is"] && $this->is('post')): ?>                    <?php endif; ?>
&nbsp;&nbsp; <i class="ri-file-warning-line" style="padding-right: 5px;"></i> 修改于 <?php echo $postCheck["updated"]; ?> 天前
&nbsp;&nbsp;<i class="ri-discuss-line" style="padding-right: 5px;"></i> <a no-pjax target="_self" href="javascript:void(0);" onclick="VOID_SmoothScroller.scrollTo('#comments', -60)"><?php $this->commentsNum(); ?>&nbsp;评论</a>
<?php if($setting['VOIDPlugin']) echo '&nbsp;•&nbsp;<span> <i class="ri-focus-3-line" style="padding-right: 5px;"></i>'.$this->viewsNum.'&nbsp;阅读</span>'; ?>

替换的前提是你的网站已经使用了 remixicon,如需修改图标或者舍弃图标请针对代码内的i标签进行修订。

菜单栏随机文章按钮#

image

@kpi 泽大的思路

    $db = Typecho_Db::get();
    $result = $db->fetchRow($db->select()->from('table.contents')->where('type=?', 'post')->where('status=?', 'publish')->limit(1)->order('RAND()'));
    if($result) {
        $f=Helper::widgetById('Contents',$result['cid']);
        $permalink = $f->permalink;
        header('Location: '.$permalink);
    } 

只需要给他加一个判断的条件,放到includes\functions.php33 行左右function themeInit()

if ($_GET['plugin']=='ramdom') {
    $db = Typecho_Db::get();
    $result = $db->fetchRow($db->select()->from('table.contents')->where('type=?', 'post')->where('status=?', 'publish')->limit(1)->order('RAND()'));
    if($result) {
        $f=Helper::widgetById('Contents',$result['cid']);
        $permalink = $f->permalink;
        header('Location: '.$permalink);
    } 
}

再在同目录的footer.php33 行左右<div class="ctrler-item" id="go-top">的闭合标签</div>下插入

<div class="ctrler-item hidden-xs">
<a aria-label="进入后台" href="https://domain/?plugin=ramdom" style="transform: translateX(-2px);"><i class="ri-gift-fill"></i></a>

替换的前提是你的网站已经使用了 remixicon,如需修改图标或者舍弃图标请针对代码内的i标签进行修订。

瀑布流文章时间侧加入文章类目#

1692717342756

模板文件夹下 index.php75 行左右替换<span class="word-count">+ <?php echo $this->wordCount; ?> 字</span>

 <span class="word-count">+ <?php echo $this->wordCount; ?></span> #<?php echo $this->categories[0]['name']; ?>#

第一次访问网站弹出公告#

1692717935051

快说谢谢火喵酱

notice.css

.annotice {
    box-shadow: 0 .25rem .5rem rgba(0,0,0,.05),0 1.5rem 2.2rem rgba(0,0,0,.1)!important;
    padding: 0 30px;
    background: #fff;
    width: 400px;
    /*height: 470px;*/
    position: fixed;
    top: 50%;
    left: 50%;
    z-index: 999999;
    transform: translateX(-50%) translateY(-50%);
    margin: 0 auto;
    border-radius: 18px;
}


.annotice-header {
    color: white;
    line-height: 40px;
    text-align: center;
}

.annotice-main {
    padding: 20px;
}
.annotice-main p {
    padding: 12px 0 0;
}
.annotice-footer {
    padding: 10px 0 30px;
    text-align: center;
}
.annotice-title {
    position: relative;
    font-size: 18px;
    font-weight: 900;
    display: inline-block;
    color:#fff;
}
.annotice strong {
    color: #46A3FF;
}
.annotice-btn {
    font-weight: 700;
    border-radius: 50px;
    width: 100%;
    cursor: pointer;
    background: #46A3FF;
    color: #fff;
    padding: 0 15px;
    line-height: 40px;
    font-size: 14px;
    display: inline-block;
}
.annotice::after {
    content: '';
    height: 80px;
    width: 100%;
    background: #46A3FF;
    position: absolute;
    top: 0;
    left: 0;
    z-index: -1;
    border-radius: 18px 18px 0 0;
}

修改好下面的内容,在你喜欢的地方狠狠的插入他们🤩

<div class="annotice" id="annotice-note" style="display: none;">
    <div class="annotice-header">
        <h3 class="annotice-title"> 『 给初次见面的你的一封信 』 </h3>
    </div>
    <div class="annotice-main">
        <p>嘿,<br>欢迎到访我的博客!</p><p>我的小博客里什么都有,但是又好像什么都没有。我已经<strong>尽力</strong>让它看起来五彩斑斓许多。这里有我的回忆、我的经历、我的见解和我的探讨,希望你在这里可以让你的知识面<strong>焕然一新</strong></p><p>我陪我的小博客走过的快三年啦,最近我给它换了个新名字“<strong>低潮鲸鸣</strong>”,所以以前的朋友记住要忘掉它的老名字“<strong>十月寒冬</strong>”!</p><p>我很喜欢浓厚的学术讨论氛围,所以你在评论区发表的见解一定要<strong>友善一点点</strong>,不然我会把不听话的小坏蛋<strong>打进垃圾箱</strong>!当然如果你想和我说点小秘密,header 里面有我的联系方式。只有<strong>电子邮箱</strong>是我最经常使用的联系方式,除此之外,一切随缘。</p><p>嘛,就暂且说这么多了,以后再加!</p>
    </div>
    <div class="annotice-footer"><span class="annotice-btn" onclick="closeclick()">好哒</span></div>
</div>
<script>
$(function(){
    if(window.localStorage.getItem("isClose") == 'yes'){
        $('#annotice-note')[0].style.display='none';
    }else
    {
         $('#annotice-note')[0].style.display='block';
    }
    
});
function closeclick()
{
   $('#annotice-note')[0].style.display='none';
   window.localStorage.setItem("isClose", "yes");
}
</script>

404 页面#

1692717514130

仅提供个定位,includes\banner.php58 行处的<span class="glitch">0</span>

加入 TianliGPT 自动生成文章的 AI 摘要#

image

具体情况可以看洪佬的文章,VOID 的元素属性的选择器是.articleBody,即

let tianliGPT_postSelector = '.articleBody';

欲想使之支持 VOID 的夜间模式,请将我不成熟的 css 加入到 TianliGPT 的调用 css 中(css 和 js 都可以自行保存调用)
1692713800865

.theme-dark .post-TianliGPT {
  background: #21232A;
  border-radius: 12px;
  padding: 12px;
  line-height: 1.3;
  border: var(--style-border-always);
  margin: 16px 0;
}
.theme-dark .tianliGPT-title {
  display: flex;
  color: #6e6e6e;
  border-radius: 8px;
  align-items: center;
  padding: 0 12px;
  cursor: default;
  user-select: none;
}
.theme-dark .tianliGPT-explanation {
  margin-top: 12px;
  padding: 8px 12px;
  background: #21232A;
  border-radius: 8px;
  border: var(--style-border-always);
  font-size: 15px;
  line-height: 1.4;
  display: flex;
}
.theme-dark .tianliGPT-tag {
  font-size: 12px;
  background-color: #6e6e6e;
  color: var(--heo-card-bg);
  font-weight: bold;
  border-radius: 4px;
  margin-left: auto;
  line-height: 1;
  padding: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: 0.3s;
}

VOID 评论后台 IP 为 IPV6 时报错#

官方的解决方案是识别为 ipv6 就返回N/A,这个问题我最早遇到,好兄弟Given直接动刀文件夹插件下的libs\IP.php,调用了 IPIP 的GeoLite2-City.mmdb数据库,实现了 IPV6 地址识别。
数据库就不提供了,Github 可以找得到。

IP.php

<?php
require_once 'vendor/autoload.php';
use GeoIp2\Database\Reader;
class IPLocation_IP
{
    private static $ip     = NULL;
    private static $fp     = NULL;
    private static $offset = NULL;
    private static $index  = NULL;
    private static $cached = array();
    public static function find($ip)
    {
        if (empty($ip) === TRUE)
        {
            return 'N/A';
        }
        $nip   = gethostbyname($ip);
        $ipdot = explode('.', $nip);
        if ($ipdot[0] < 0 || $ipdot[0] > 255 || count($ipdot) !== 4)
        {
            return 'N/A';
        }
        if (isset(self::$cached[$nip]) === TRUE)
        {
            return self::$cached[$nip];
        }
        if (self::$fp === NULL)
        {
            self::init();
        }
        $nip2 = pack('N', ip2long($nip));
        $tmp_offset = (int)$ipdot[0] * 4;
        $start      = unpack('Vlen', self::$index[$tmp_offset] . self::$index[$tmp_offset + 1] . self::$index[$tmp_offset + 2] . self::$index[$tmp_offset + 3]);
        $index_offset = $index_length = NULL;
        $max_comp_len = self::$offset['len'] - 1024 - 4;
        for ($start = $start['len'] * 8 + 1024; $start < $max_comp_len; $start += 8)
        {
            if (self::$index{$start} . self::$index{$start + 1} . self::$index{$start + 2} . self::$index{$start + 3} >= $nip2)
            {
                $index_offset = unpack('Vlen', self::$index{$start + 4} . self::$index{$start + 5} . self::$index{$start + 6} . "\x0");
                $index_length = unpack('Clen', self::$index{$start + 7});
                break;
            }
        }
        if ($index_offset === NULL)
        {
            return 'N/A';
        }
        fseek(self::$fp, self::$offset['len'] + $index_offset['len'] - 1024);
        self::$cached[$nip] = explode("\t", fread(self::$fp, $index_length['len']));
        return self::$cached[$nip];
    }
    private static function init()
    {
        if (self::$fp === NULL)
        {
            self::$ip = new self();
            self::$fp = fopen(__DIR__ . '/17monipdb.dat', 'rb');
            if (self::$fp === FALSE)
            {
                throw new Exception('Invalid 17monipdb.dat file!');
            }
            self::$offset = unpack('Nlen', fread(self::$fp, 4));
            if (self::$offset['len'] < 4)
            {
                throw new Exception('Invalid 17monipdb.dat file!');
            }
            self::$index = fread(self::$fp, self::$offset['len'] - 4);
        }
    }
    public function __destruct()
    {
        if (self::$fp !== NULL)
        {
            fclose(self::$fp);
        }
    }

    public static function locate ($ip)
    {
        $reader = new Reader('/wwwroot/GeoLite2-City.mmdb的绝对路径');
        if($ip != '127.0.0.1'){
            $record = $reader->city($ip);
            $addresses = IPLocation_IP::find($ip);
            if($addresses == "N/A"){
                $addresses = $record->city->name;
                if($addresses == null){
                    $addresses = $record->country->names['zh-CN'];
                }
            }
            if (is_array($addresses)) {
                $addresses = array_unique($addresses);
                $addresses = implode('', $addresses);
            }
        }
        else{
            $addresses = "未知或保留地址";
        }
        

        #return $address;
        #echo($addresses);
        return $addresses;
    }
}

我推的模块😍#

好好好,喜欢变形记是吧

BracketDown#

1692716360414
BracketDown 是一个适用于 Typecho 的 Markdown 语法拓展插件,加入了一系列短代码,方便博主在编写文章时更好地排版。
BigCoke233/typecho-plugin-BracketDown

assets\default.css VOID 夜间模式 css

.theme-dark .bracketdown-post-title a {
    color: #666;
    border: none;
    text-decoration: none
}
.theme-dark .bracketdown-post-meta a {
    border: none;
    text-decoration: none;
    color: #666;
    display: inline-block;
    font-size: .9em;
    border: 1px solid #222;
    padding: 0 .5em;
    transition-property: border, background, color;
    transition-duration: .3s
}
.theme-dark .bracketdown-post-meta a:hover {
    border-color: #222;
    background: #222;
    color: #fff
}

image
外链转内链,对 seo 有奇效(应该
benzBrake/ShortLinks

And so on..#

剩下的都挺好用,没有啥好说的,放个图吧

1692716656380

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.