[js] 思源笔记左侧空白区域显示心灵毒鸡汤或倒计时

根据这个帖子的灵感 [js] 思源笔记左侧空白部分显示自定义文字 写了这个显示心灵毒鸡汤的功能。

感觉不错,分享给大家。

功能介绍

  1. 左侧 dock 空白区域显示心灵毒鸡汤
  2. 双击显示下一个
  3. 右键复制到剪切板
  4. 可显示为跑马灯效果
  5. 可显示倒计时
  6. 可在右侧 dock 空白区域显示哲理名言

使用方法,请参考代码参数中的注释。

效果

image.png image.png r107.gif image.png

动画效果实际上比较顺滑,录制原因有点抖。

代码
// 左侧dock空白区显示心灵毒鸡汤/倒计时等
// version 0.0.3
// 功能介绍:
// 1. 左侧dock空白区域显示心灵毒鸡汤
// 2. 双击显示下一个
// 3. 右键复制到剪切板
// 4. 可显示为跑马灯效果
// 5. 可显示倒计时
// 6. 可在右侧dock空白区域显示哲理名言
(()=>{
    // 设置多久显示一次,单位秒,默认5分钟
    const delay = 300;

    // 是否显示为跑马灯效果,true显示为跑马灯效果
    const marquee = false;

    // 鼠标悬停时是否显示提示
    const showTitle = true;

    // 显示倒计时,显示倒计时时将不再显示心灵毒鸡汤
    const showCountdown = false;

    // 倒计时到期日期
    const countdownExpireDate = '2025-01-01';

    // 倒计时模板
    const countdownTemplate = '距离 2025-01-01 还剩 {day} 天';

    // 右侧dock空白区域显示信息,不显示保持为空间即可
    const dockRightWords = '人生最大的敌人是自己';
  
    // 左侧dock空白区文本样式
    addStyle(`
        #dockLeft .fn__flex-1.dock__item--space, #dockRight .fn__flex-1.dock__item--space {
        	display: flex;
        	justify-content: center; /* 水平居中 */
        	align-items: center; /* 垂直居中 */
        	font-size: clamp(12px, 3vh, 18px); /* 字体大小 */
        	writing-mode: vertical-rl; /* 竖向排列 */
        	text-align: center; /* 文字居中对齐 */
            line-height: 120%;
            overflow: hidden;
        }
        #dockLeft .fn__flex-1.dock__item--space marquee {
            display: flex;
            align-items: center;
            white-space: nowrap;
            font-size: 18px;
            height: 100vh;
        }
    `);

    // 手机版退出
    if(isMobile()) return;

    // 监听事件
    let dockSpace = getDockSpace();
    if(dockSpace){
        // 添加双击事件,双击显示下一个
        listenDockSpaceDblclick();
        // 右键事件,右键复制到剪切板
        listenDockSpaceContextmenu();
    } else {
        setTimeout(() => {
            dockSpace = getDockSpace();
            listenDockSpaceDblclick();
            listenDockSpaceContextmenu();
        }, 1500);
    }

    // 定时显示心灵毒鸡汤
    setInterval(async () => {
        yiyan((text) => {
            setDockSpace(text);
        });
    }, delay * 1000 || 300000);

    // 加载时显示一次
    yiyan((text) => {
        setDockSpace(text);
    });

    // 右侧dock空白区域显示文字
    showDockRightWords(dockRightWords);

    //每日一言
    async function yiyan(callback) {
        if(showCountdown) {
            // 定义目标日期,比如(2025年1月1日)
            const targetDate = new Date(countdownExpireDate + 'T00:00:00');
            // 获取当前日期
            const currentDate = new Date();
            // 计算时间差(以毫秒为单位)
            const timeDifference = targetDate - currentDate;
            // 将毫秒转换为天数
            const daysRemaining = Math.ceil(timeDifference / (1000 * 60 * 60 * 24));
            // 输出结果
            const response = countdownTemplate.replace(/\{day\}/ig, daysRemaining);
            callback(response);
        } else {
            var response = await fetch("https://v.api.aa1.cn/api/yiyan/index.php");
            response = await response.text();
            response = extractTextFromHtml(response);
            response = cleanText(response);
            callback(response);
        }
    }

    // 右侧dock空白区域显示文字
    function showDockRightWords(dockRightWords) {
        if(!dockRightWords) return;
        const selector = '#dockRight .fn__flex-1.dock__item--space';
        let dockRightSpace = document.querySelector(selector);
        if(dockRightSpace){
            dockRightSpace.innerHTML = dockRightWords;
        } else {
            setTimeout(() => {
                dockRightSpace = document.querySelector(selector);
                if(dockRightSpace) dockRightSpace.innerHTML = dockRightWords;
            }, 1500);
        }
    }

    // 清除空白符换行等
    function cleanText(str) {
        // 去除所有换行符
        let noNewlines = str.replace(/[\r\n]+/g, '');
        // 替换多个连续的空白字符为单个空格,并去除开头和结尾的空白
        return noNewlines.replace(/\s+/g, ' ').trim();
    }

    // 解析出文本字符
    function extractTextFromHtml(htmlString) {
        // 创建一个新的DOMParser实例
        const parser = new DOMParser();
        // 使用DOMParser将HTML字符串解析为一个文档对象
        const doc = parser.parseFromString(htmlString, 'text/html');
        // 获取所有 <script> 标签并移除它们
        const scripts = doc.querySelectorAll('script');
        scripts.forEach(script => script.remove());
        // 返回文档中的纯文本内容,去除多余的空白字符
        return doc.body.textContent || doc.body.innerText || '';
    }

    // 获取左侧dock空白区域对象
    function getDockSpace() {
        return document.querySelector('#dockLeft .fn__flex-1.dock__item--space');
    }
  
    // 设置左侧dock空白文字
    function setDockSpace(html) {
        dockSpace = dockSpace || getDockSpace();
        if(dockSpace) {
            const text = html;
            if(marquee) {
                html = '<marquee direction="up">'+html+'</marquee>';
            }
            dockSpace.innerHTML = html;
            dockSpace.title = text;
        }
    }

    // 监听左侧dock空白区域双击事件
    function listenDockSpaceDblclick() {
        dockSpace = dockSpace || getDockSpace();
        dockSpace.addEventListener('dblclick', () => {
            yiyan((text) => {
                setDockSpace(text);
            });
        });
    }

    // 监听左侧dock空白区域右键事件
    function listenDockSpaceContextmenu() {
        dockSpace = dockSpace || getDockSpace();
        dockSpace.addEventListener('contextmenu', () => {
            const successful = copyTextToClipboard(dockSpace.textContent);
            if(successful) {
                showMessage('已复制到剪切板', false, 3000);
            } else {
                showMessage('复制失败', true, 3000);
            }
        });
    }

    // 复制文本到剪切板
    function copyTextToClipboard(text) {
        // 创建一个隐藏的textarea元素
        const textarea = document.createElement("textarea");
        textarea.value = text;
        document.body.appendChild(textarea);
        // 隐藏此输入框
        textarea.style.position = 'fixed'; // 移出正常文档流
        textarea.style.left = '-9999px';  // 移动到屏幕外
        textarea.style.top = 0; // 确保不占用可见区域
        // 选中并复制文本
        textarea.select();
        textarea.setSelectionRange(0, 99999); // 对于移动设备
        let successful = false;
        try {
            successful = document.execCommand('copy');
        } catch (err) {
            console.error('无法复制文本: ', err);
        }
        // 移除输入框
        document.body.removeChild(textarea);
        return successful;
    }
  
    // 添加样式
    function addStyle(css) {
        // 创建一个 <style> 元素
        const styleElement = document.createElement('style');
        // 设置样式内容
        styleElement.type = 'text/css';
        styleElement.appendChild(document.createTextNode(css));
        // 将 <style> 元素添加到 <head> 中
        document.head.appendChild(styleElement);
    }

    // 判断是否手机版
    function isMobile() {
        return !!document.getElementById("sidebar");
    }

    // 发送消息
    function showMessage(message, isError = false, delay = 7000) {
        return fetch('/api/notification/' + (isError ? 'pushErrMsg' : 'pushMsg'), {
            "method": "POST",
            "body": JSON.stringify({"msg": message, "timeout": delay})
        });
    }
})();
砸彩蛋啦,打赏后可见,有惊喜哦~~
打赏 15 积分后可见
15 积分 • 16 打赏
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    23000 引用 • 92500 回帖 • 2 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    90 引用 • 556 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...