Merge pull request '更换到Astro' (#9) from switch-to-astro into master
Reviewed-on: #9 -- [CST 2026-06-19 Friday 13:28:19]
This commit is contained in:
commit
01b5e2e1ba
100 files changed
+48921
No files matched your search
@@ -0,0 +1 @@
|
||||
:root{color-scheme:light;--bg: #f7f5ef;--surface: #fffdf8;--text: #20242a;--muted: #686f78;--line: #ded8cc;--accent: #0f766e;--accent-strong: #14532d;--shadow: 0 14px 45px rgba(58, 51, 38, .1);--page-gutter: clamp(20px, 4vw, 64px);--wide-width: 1440px;--content-width: 1280px;--article-width: 1080px;--narrow-width: 1000px}:root[data-theme=dark]{color-scheme:dark;--bg: #0f171a;--surface: #162225;--text: #e9f0ee;--muted: #a7b4b1;--line: rgba(174, 205, 197, .18);--accent: #72ded2;--accent-strong: #9af0d6;--shadow: 0 18px 48px rgba(0, 0, 0, .28)}*{box-sizing:border-box}body{margin:0;color:var(--text);font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Microsoft YaHei,sans-serif;line-height:1.75;background:linear-gradient(#f7f5efdb,#f7f5eff2),url(/images/background.png) center top / cover fixed;transition:color .22s ease,background-color .22s ease}:root[data-theme=dark] body{background:linear-gradient(#080d10db,#0a1114f0),url(/images/background.png) center top / cover fixed}a{color:inherit;text-decoration:none}.site-header{position:sticky;top:12px;z-index:10;pointer-events:none}.nav{position:relative;width:min(var(--wide-width),calc(100% - (var(--page-gutter) * 2)));min-height:58px;margin:0 auto;padding:0 18px;display:grid;grid-template-columns:minmax(120px,1fr) auto minmax(120px,1fr);align-items:center;gap:24px;overflow:hidden;border:1px solid rgba(255,255,255,.56);border-radius:999px;background:linear-gradient(135deg,#ffffff85,#fff3),#ffffff47;box-shadow:inset 0 1px #ffffffd1,inset 0 -18px 38px #ffffff29,0 18px 54px #2c373f2e;backdrop-filter:blur(22px) saturate(180%);-webkit-backdrop-filter:blur(22px) saturate(180%);pointer-events:auto}.nav:before{content:"";position:absolute;inset:0;background:radial-gradient(circle at 18% 0%,rgba(255,255,255,.72),transparent 30%),linear-gradient(90deg,rgba(255,255,255,.42),transparent 38%,rgba(255,255,255,.22));opacity:.74;pointer-events:none}.nav:after{content:"";position:absolute;top:7px;right:16px;left:16px;height:1px;border-radius:999px;background:#ffffffc7;pointer-events:none}.brand{position:relative;z-index:1;font-size:1.05rem;font-weight:800}.nav-menu{display:contents}.nav-menu-toggle{position:relative;z-index:1;display:none;width:40px;height:40px;place-items:center;border:1px solid transparent;border-radius:999px;color:var(--muted);font:inherit;background:transparent;cursor:pointer;transition:color .2s ease,background-color .2s ease,border-color .2s ease,box-shadow .2s ease,transform .2s ease}.nav-menu-close{display:none}.nav-links{position:relative;z-index:1;display:flex;align-items:center;gap:6px;color:var(--muted);font-size:.94rem;white-space:nowrap}.nav-center{justify-content:center}.nav-actions{justify-content:flex-end}.nav-links a,.nav-random,.nav-search,.theme-toggle{display:inline-flex;align-items:center;gap:6px;border:1px solid transparent;border-radius:999px;padding:7px 12px;transition:color .2s ease,background-color .2s ease,border-color .2s ease,box-shadow .2s ease,transform .2s ease}.nav-search,.nav-random,.theme-toggle{color:inherit;font:inherit;line-height:inherit;background:transparent;cursor:pointer}.nav-icon{display:inline-grid;width:16px;min-width:16px;height:16px;place-items:center;font-size:.95em;line-height:1}.theme-toggle{justify-content:center;width:38px;min-height:38px;padding:0}:root:not([data-theme=dark]) .theme-toggle-sun,:root[data-theme=dark] .theme-toggle-moon{display:none}.nav-links a:hover,.nav-random:hover,.nav-search:hover,.theme-toggle:hover,.site-footer a:hover,.section-heading a:hover{color:var(--accent)}.custom-context-menu{position:fixed;top:0;left:0;z-index:1000;width:min(218px,calc(100vw - 20px));max-height:calc(100vh - 20px);overflow-y:auto;border:1px solid rgba(255,255,255,.58);border-radius:14px;padding:8px;color:#4f565b;background:linear-gradient(145deg,#ffffffc7,#ebf8e7ad),#f5fcf1d1;box-shadow:inset 0 1px #ffffffdb,0 18px 42px #2c373f2e;backdrop-filter:blur(18px) saturate(165%);-webkit-backdrop-filter:blur(18px) saturate(165%);opacity:0;pointer-events:none;transform:translate3d(0,6px,0) scale(.98);transform-origin:top left;transition:opacity .14s ease,transform .14s ease}.custom-context-menu.is-open{opacity:1;pointer-events:auto;transform:translateZ(0) scale(1)}.custom-context-menu [hidden]{display:none!important}.context-menu-nav{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:6px;padding-bottom:7px}.context-menu-group{display:grid;gap:2px;border-top:1px dashed rgba(104,111,120,.18);padding-top:7px}.context-menu-group+.context-menu-group{margin-top:7px}.custom-context-menu :where(a,button){display:flex;align-items:center;width:100%;min-width:0;border:0;color:inherit;font:inherit;line-height:1.25;text-align:left;background:transparent;cursor:pointer}.context-menu-nav :where(a,button){justify-content:center;height:42px;border:1px solid rgba(178,194,170,.42);border-radius:14px;color:#6b7174;background:#ffffff70;box-shadow:inset 0 1px #ffffffc2}.context-menu-group :where(a,buttLine truncated
|
||||
@@ -0,0 +1,282 @@
|
||||
<!DOCTYPE html><html lang="zh-CN"> <head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="description" content="关于 Bi's Blog 和站长 biss 的简短介绍。"><link rel="icon" href="/images/Bi.ico"><script defer src="https://umami.biss.click/script.js" data-website-id="3d97b310-b241-4fc6-bc9c-68e317fc7d42"></script><script>window.SITE_CONFIG = {"site":{"url":"https://blog.biss.click","name":"Bi's Blog","description":"Personal blog by biss.","language":"zh-CN","domain":"blog.biss.click","slogan":"好奇心转化为代码的空间。","startTime":"2025-01-01T00:00:00+08:00","copyrightStartYear":2025,"license":"内容采用 CC BY-NC-SA 4.0 协议"},"author":{"name":"biss","email":"bishsh2006@gmail.com","github":"https://github.com/bishshi","avatar":"https://free.picui.cn/free/2025/08/10/689845496a283.png"},"comments":{"envId":"https://comment.biss.click","region":"","script":"https://cdn.jsdelivr.net/npm/twikoo@1.7.7/dist/twikoo.min.js"},"analytics":{"umami":{"script":"https://umami.biss.click/script.js","websiteId":"3d97b310-b241-4fc6-bc9c-68e317fc7d42","statsEndpoint":"https://blogumami.biss.click"}},"talks":{"apiUrl":"https://mm.biss.click/api/echo/page","pageSize":30,"homeLimit":6,"cacheKey":"talksCache","cacheTimeKey":"talksCacheTime","cacheDurationMs":1800000,"fallbackAvatar":"https://free.picui.cn/free/2025/08/10/689845496a283.png"},"search":{"apiKey":"2uxQzk7eD2GBCljdSmIiuU3ause7UK9n","server":{"host":"typesense.biss.click","port":"443","protocol":"https"},"indexName":"blogs","searchParams":{"query_by":"title,content","highlight_full_fields":"title,content","per_page":8,"num_typos":1,"typo_tokens_threshold":1,"prefix":true},"ui":{"maxRetries":10,"retryDelay":100,"animationDuration":300,"maxInitRetries":30,"placeholder":"输入关键词寻找故事..."}},"externalLinks":{"waitSeconds":10,"whitelist":["blog.biss.click","biss.click","github.com","localhost","127.0.0.1"]}};</script><script>
|
||||
(() => {
|
||||
const storageKey = 'site-theme';
|
||||
const savedTheme = localStorage.getItem(storageKey);
|
||||
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
||||
document.documentElement.dataset.theme = savedTheme || systemTheme;
|
||||
})();
|
||||
</script><link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/instantsearch.css/themes/reset-min.css"><link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.css"><link rel="stylesheet" href="https://cdn.jsdmirror.com/npm/@fortawesome/fontawesome-free@6.7.2/css/all.min.css"><title>关于 | Bi's Blog</title><link rel="stylesheet" href="/_astro/BaseLayout.D7kFxpxP.css"></head> <body> <header class="site-header"> <nav class="nav"> <a class="brand" href="/">Bi's Blog</a> <button class="nav-menu-toggle" type="button" aria-label="打开菜单" aria-expanded="false" data-nav-toggle> <i class="fa-solid fa-bars nav-menu-open" aria-hidden="true"></i> <i class="fa-solid fa-xmark nav-menu-close" aria-hidden="true"></i> </button> <div class="nav-menu" data-nav-menu> <div class="nav-links nav-center"> <a href="/archives/"><i class="fa-solid fa-box-archive nav-icon" aria-hidden="true"></i><span>归档</span></a><a href="/categories/"><i class="fa-solid fa-folder-open nav-icon" aria-hidden="true"></i><span>分类</span></a><a href="/tags/"><i class="fa-solid fa-tags nav-icon" aria-hidden="true"></i><span>标签</span></a><a href="/shuoshuo/"><i class="fa-regular fa-comments nav-icon" aria-hidden="true"></i><span>说说</span></a><a href="/about/"><i class="fa-solid fa-heart nav-icon" aria-hidden="true"></i><span>关于</span></a><a href="/link/"><i class="fa-solid fa-link nav-icon" aria-hidden="true"></i><span>友链</span></a> </div> <div class="nav-links nav-actions"> <button class="nav-random" type="button" onclick="randomPost()" aria-label="前往随机文章" title="前往随机文章"> <i class="fa-solid fa-shuffle nav-icon" aria-hidden="true"></i> <span>随机文章</span> </button> <button class="nav-search search-typesense-trigger" type="button" aria-label="搜索" title="搜索"> <i class="fa-solid fa-magnifying-glass nav-icon" aria-hidden="true"></i> <span>搜索</span> </button> <button class="theme-toggle" type="button" aria-label="切换夜间模式" title="切换夜间模式" data-theme-toggle> <i class="fa-solid fa-sun theme-toggle-sun nav-icon" aria-hidden="true"></i> <i class="fa-solid fa-moon theme-toggle-moon nav-icon" aria-hidden="true"></i> </button> </div> </div> </nav> </header> <main> <section class="content-wrap narrow page-with-card native-page"> <header class="page-header-card"> <p class="page-header-eyebrow">Bi's Blog</p> <h1>关于</h1> <p class="page-header-subtitle">这里记录折腾、学习和一些普通日子的回声。</p> </header> </section> <article class="article page-article native-page-article"> <div class="prose"> <p>
|
||||
你好,我是 Bi。这个博客主要用来保存技术实践、生活片段和那些一时半会儿不想让它们散掉的想法。
|
||||
</p> <div class="native-feature-grid"> <section> <i class="fa-solid fa-code" aria-hidden="true"></i> <h2>技术笔记</h2> <p>记录服务器、网络、开发环境、图像处理和一些实际踩坑过程。</p> </section> <section> <i class="fa-regular fa-comments" aria-hidden="true"></i> <h2>日常碎片</h2> <p>把普通的一天、突然冒出来的灵感和一点点情绪留在这里。</p> </section> <section> <i class="fa-solid fa-seedling" aria-hidden="true"></i> <h2>持续生长</h2> <p>网站本身也在慢慢迁移和重写,新的页面会逐步变成原生实现。</p> </section> </div> <h2>联系</h2> <p>
|
||||
如果你想交流文章内容、友链或网站相关问题,可以通过
|
||||
<a href="mailto:bishsh2006@gmail.com">bishsh2006@gmail.com</a>
|
||||
联系我,也可以去
|
||||
<a href="https://github.com/bishshi" target="_blank" rel="noreferrer">GitHub</a>
|
||||
找到我。
|
||||
</p> </div> </article> </main> <footer class="site-footer" aria-label="站点页脚"> <div class="footer-inner"> <section class="footer-top" aria-label="站点信息"> <a class="footer-brand" href="/" aria-label="Bi's Blog 首页"> <img src="/images/Bi.ico" alt="" loading="lazy"> <span>Bi's Blog</span> </a> <p class="footer-slogan">好奇心转化为代码的空间。</p> </section> <section class="footer-contact" aria-label="联系方式"> <p>联系方式</p> <div class="footer-socials"> <a href="mailto:bishsh2006@gmail.com" aria-label="发送邮件" title="发送邮件"> <i class="fa-solid fa-envelope" aria-hidden="true"></i> </a><a href="/rss.xml" aria-label="订阅 RSS" title="订阅 RSS"> <i class="fa-solid fa-rss" aria-hidden="true"></i> </a><a href="https://github.com/bishshi" target="_blank" rel="noreferrer" aria-label="GitHub" title="GitHub"> <i class="fa-brands fa-github" aria-hidden="true"></i> </a> </div> <nav class="footer-contact-links" aria-label="页脚链接"> <a href="/archives/">发展历程</a> <span aria-hidden="true">|</span><a href="/privacy/">隐私政策</a> </nav> </section> <section class="footer-bottom" aria-label="版权信息"> <div> <p>© 2025 - 2026 Bi's Blog</p> <p>blog.biss.click | 内容采用 CC BY-NC-SA 4.0 协议</p> </div> <div class="footer-meta"> <p>本站已运行:<span id="site-runtime">计算中...</span></p> <p> <a href="https://fastly.com/" target="_blank" rel="noreferrer">Fastly</a> <span aria-hidden="true">|</span><a href="https://astro.build/" target="_blank" rel="noreferrer">ASTRO</a> </p> </div> </section> </div> </footer> <aside class="hitokoto-card" aria-label="一言" data-hitokoto-card data-astro-cid-4cgfuthx> <div class="hitokoto-card__head" data-astro-cid-4cgfuthx> <button class="hitokoto-card__toggle" type="button" aria-label="展开一言" aria-expanded="true" title="一言" data-hitokoto-toggle data-astro-cid-4cgfuthx> <i class="fa-solid fa-quote-left" aria-hidden="true" data-astro-cid-4cgfuthx></i> <span data-astro-cid-4cgfuthx>一言</span> </button> <div class="hitokoto-card__actions" data-astro-cid-4cgfuthx> <button class="hitokoto-card__refresh" type="button" aria-label="换一句" title="换一句" data-hitokoto-refresh data-astro-cid-4cgfuthx> <i class="fa-solid fa-rotate" aria-hidden="true" data-astro-cid-4cgfuthx></i> </button> <button class="hitokoto-card__collapse" type="button" aria-label="收起一言" title="收起" data-hitokoto-collapse data-astro-cid-4cgfuthx> <i class="fa-solid fa-chevron-down" aria-hidden="true" data-astro-cid-4cgfuthx></i> </button> </div> </div> <a class="hitokoto-card__text" href="https://hitokoto.cn/" target="_blank" rel="noreferrer" data-hitokoto-text data-astro-cid-4cgfuthx>
|
||||
获取中...
|
||||
</a> <p class="hitokoto-card__from" data-hitokoto-from data-astro-cid-4cgfuthx>来自 Hitokoto</p> </aside> <script type="module">(()=>{const o=document.querySelector("[data-hitokoto-card]"),s=o?.querySelector("[data-hitokoto-toggle]"),r=o?.querySelector("[data-hitokoto-text]"),l=o?.querySelector("[data-hitokoto-from]"),k=o?.querySelector("[data-hitokoto-refresh]"),m=o?.querySelector("[data-hitokoto-collapse]");if(!(o instanceof HTMLElement)||!(s instanceof HTMLButtonElement)||!(r instanceof HTMLAnchorElement)||!(l instanceof HTMLElement))return;const g="https://yiyan.biss.click/api?encode=json",u="hitokoto-card-cache",y=360*60*1e3,d={sentence:"生活明朗,万物可爱。",source:"本地缓存",url:"https://hitokoto.cn/"},L=["/","/index.html"].includes(window.location.pathname);function c(t){o.classList.toggle("is-collapsed",!t),s.setAttribute("aria-expanded",String(t)),s.setAttribute("aria-label",t?"收起一言":"展开一言")}function f(){try{const t=localStorage.getItem(u);if(!t)return null;const e=JSON.parse(t);return!e||typeof e.expiresAt!="number"||e.expiresAt<=Date.now()?null:e.data}catch{return null}}function x(t){try{localStorage.setItem(u,JSON.stringify({data:t,expiresAt:Date.now()+y}))}catch{}}function i(t){r.textContent=t.sentence,r.href=t.url||"https://hitokoto.cn/",l.textContent=t.source?`出自 ${t.source}`:"来自 Hitokoto"}async function h({force:t=!1}={}){if(!t){const e=f();if(e){i(e);return}}o.classList.add("is-loading"),r.textContent="获取中...";try{const e=await fetch(g);if(!e.ok)throw new Error(`Hitokoto request failed: ${e.status}`);const n=await e.json(),a=n.hitokoto||n.content||n.sentence||n.text,S=typeof a=="string"&&a.trim()?a.trim():d.sentence,E=typeof n.from=="string"&&n.from.trim()?n.from.trim():"Hitokoto",w=n.uuid?`https://hitokoto.cn/?uuid=${encodeURIComponent(n.uuid)}`:"https://hitokoto.cn/",p={sentence:S,source:E,url:w};x(p),i(p)}catch(e){console.error(e),i(f()||d)}finally{o.classList.remove("is-loading")}}c(L),s.addEventListener("click",()=>{c(o.classList.contains("is-collapsed"))}),k?.addEventListener("click",t=>{t.stopPropagation(),c(!0),h({force:!0})}),m?.addEventListener("click",t=>{t.stopPropagation(),c(!1)}),o.addEventListener("click",t=>{o.classList.contains("is-collapsed")&&(t.target instanceof Element&&t.target.closest("a, button")||c(!0))}),h()})();</script> <div class="custom-context-menu" data-context-menu role="menu" aria-hidden="true"> <div class="context-menu-nav" aria-label="页面导航"> <button type="button" data-context-action="back" aria-label="后退上一页" title="后退上一页"> <i class="fa-solid fa-arrow-left" aria-hidden="true"></i> </button> <button type="button" data-context-action="forward" aria-label="前进下一页" title="前进下一页"> <i class="fa-solid fa-arrow-right" aria-hidden="true"></i> </button> <button type="button" data-context-action="reload" aria-label="刷新页面" title="刷新页面"> <i class="fa-solid fa-rotate-right" aria-hidden="true"></i> </button> <a href="/" aria-label="返回首页" title="返回首页"> <i class="fa-solid fa-house" aria-hidden="true"></i> </a> </div> <div class="context-menu-group" data-selection-group hidden> <button type="button" data-context-action="copy-selection" data-selection-item> <i class="fa-regular fa-copy" aria-hidden="true"></i> <span>复制选中文字</span> </button> <button type="button" data-context-action="search-selection" data-selection-item> <i class="fa-brands fa-microsoft" aria-hidden="true"></i> <span>用 Bing 搜索</span> </button> <button type="button" data-context-action="quote-selection" data-selection-item data-comments-item> <i class="fa-regular fa-comment-dots" aria-hidden="true"></i> <span>引用到评论区</span> </button> </div> <div class="context-menu-group" data-image-group hidden> <button type="button" data-context-action="copy-image"> <i class="fa-regular fa-image" aria-hidden="true"></i> <span>复制图片</span> </button> <button type="button" data-context-action="open-image"> <i class="fa-solid fa-up-right-from-square" aria-hidden="true"></i> <span>新页面打开图片</span> </button> <button type="button" data-context-action="copy-image-url"> <i class="fa-solid fa-link" aria-hidden="true"></i> <span>复制图片地址</span> </button> </div> <div class="context-menu-group"> <a href="/archives/"> <i class="fa-solid fa-box-archive" aria-hidden="true"></i> <span>时间线</span> </a> <a href="/categories/"> <i class="fa-solid fa-folder" aria-hidden="true"></i> <span>分类</span> </a> <a href="/tags/"> <i class="fa-solid fa-hashtag" aria-hidden="true"></i> <span>标签</span> </a> <button type="button" data-context-action="comments" data-comments-item> <i class="fa-regular fa-comment-dots" aria-hidden="true"></i> <span>跳转评论区</span> </button> <button type="button" data-context-action="print"> <i class="fa-solid fa-print" aria-hidden="true"></i> <span>打印页面</span> </button> <a href="/cc/"> <i class="fa-solid fa-circle-infoLine truncated
|
||||
(() => {
|
||||
const menu = document.querySelector('[data-context-menu]');
|
||||
if (!menu) return;
|
||||
|
||||
const selectionItems = [...menu.querySelectorAll('[data-selection-item]')];
|
||||
const selectionGroup = menu.querySelector('[data-selection-group]');
|
||||
const commentsItems = [...menu.querySelectorAll('[data-comments-item]')];
|
||||
const imageGroup = menu.querySelector('[data-image-group]');
|
||||
const focusableSelector = 'a[href], button:not([disabled])';
|
||||
let lastSelectionText = '';
|
||||
let lastImage = null;
|
||||
|
||||
const isNativeContextTarget = (target) =>
|
||||
target instanceof Element &&
|
||||
Boolean(target.closest('input, textarea, select, [contenteditable="true"], [contenteditable=""]'));
|
||||
|
||||
const getCommentsTarget = () =>
|
||||
document.querySelector('.twikoo-comments, #twikoo-wrap, #twikoo, .tk-comments-container');
|
||||
|
||||
const getSelectionText = () => String(window.getSelection?.() || '').trim();
|
||||
|
||||
const getImageTarget = (target) => {
|
||||
if (!(target instanceof Element)) return null;
|
||||
const image = target.closest('img');
|
||||
return image instanceof HTMLImageElement ? image : null;
|
||||
};
|
||||
|
||||
const getImageUrl = () => {
|
||||
if (!lastImage) return '';
|
||||
return lastImage.currentSrc || lastImage.src || lastImage.getAttribute('src') || '';
|
||||
};
|
||||
|
||||
const copyText = async (text) => {
|
||||
if (navigator.clipboard?.writeText) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return;
|
||||
}
|
||||
|
||||
const textarea = document.createElement('textarea');
|
||||
textarea.value = text;
|
||||
textarea.setAttribute('readonly', '');
|
||||
textarea.style.position = 'fixed';
|
||||
textarea.style.inset = '0 auto auto -9999px';
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
document.execCommand('copy');
|
||||
textarea.remove();
|
||||
};
|
||||
|
||||
const setMenuState = () => {
|
||||
const hasSelection = lastSelectionText.length > 0;
|
||||
const hasComments = Boolean(getCommentsTarget());
|
||||
const hasImage = Boolean(getImageUrl());
|
||||
|
||||
selectionItems.forEach((item) => {
|
||||
item.hidden = !hasSelection;
|
||||
});
|
||||
if (selectionGroup) selectionGroup.hidden = !hasSelection;
|
||||
|
||||
commentsItems.forEach((item) => {
|
||||
item.hidden = !hasComments || (item.hasAttribute('data-selection-item') && !hasSelection);
|
||||
});
|
||||
|
||||
if (imageGroup) imageGroup.hidden = !hasImage;
|
||||
};
|
||||
|
||||
const closeMenu = () => {
|
||||
menu.classList.remove('is-open');
|
||||
menu.setAttribute('aria-hidden', 'true');
|
||||
};
|
||||
|
||||
const openMenu = (x, y) => {
|
||||
setMenuState();
|
||||
menu.classList.add('is-open');
|
||||
menu.setAttribute('aria-hidden', 'false');
|
||||
|
||||
const rect = menu.getBoundingClientRect();
|
||||
const gap = 10;
|
||||
const left = Math.min(Math.max(gap, x), window.innerWidth - rect.width - gap);
|
||||
const top = Math.min(Math.max(gap, y), window.innerHeight - rect.height - gap);
|
||||
|
||||
menu.style.left = `${left}px`;
|
||||
menu.style.top = `${top}px`;
|
||||
};
|
||||
|
||||
const jumpToComments = () => {
|
||||
const target = getCommentsTarget();
|
||||
target?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
};
|
||||
|
||||
const quoteToComments = () => {
|
||||
jumpToComments();
|
||||
window.setTimeout(() => {
|
||||
const textarea = document.querySelector('#twikoo textarea, .twikoo-comments textarea, .tk-input textarea');
|
||||
if (!(textarea instanceof HTMLTextAreaElement) || !lastSelectionText) return;
|
||||
|
||||
const quote = lastSelectionText
|
||||
.split(/\r?\n/)
|
||||
.map((line) => `> ${line}`)
|
||||
.join('\n');
|
||||
const current = textarea.value.trim();
|
||||
textarea.value = current ? `${current}\n\n${quote}\n` : `${quote}\n`;
|
||||
textarea.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
textarea.focus();
|
||||
}, 500);
|
||||
};
|
||||
|
||||
const searchSelection = () => {
|
||||
if (!lastSelectionText) return;
|
||||
const url = `https://www.bing.com/search?q=${encodeURIComponent(lastSelectionText)}`;
|
||||
window.open(url, '_blank', 'noopener,noreferrer');
|
||||
};
|
||||
|
||||
const copyImage = async () => {
|
||||
const imageUrl = getImageUrl();
|
||||
if (!imageUrl) return;
|
||||
|
||||
try {
|
||||
if (!navigator.clipboard?.write || typeof ClipboardItem === 'undefined') {
|
||||
throw new Error('Image clipboard is not available.');
|
||||
}
|
||||
|
||||
const response = await fetch(imageUrl, { mode: 'cors' });
|
||||
const blob = await response.blob();
|
||||
await navigator.clipboard.write([
|
||||
new ClipboardItem({ [blob.type || 'image/png']: blob }),
|
||||
]);
|
||||
} catch {
|
||||
await copyText(new URL(imageUrl, window.location.href).toString());
|
||||
}
|
||||
};
|
||||
|
||||
const openImage = () => {
|
||||
const imageUrl = getImageUrl();
|
||||
if (!imageUrl) return;
|
||||
window.open(new URL(imageUrl, window.location.href).toString(), '_blank', 'noopener,noreferrer');
|
||||
};
|
||||
|
||||
document.addEventListener('contextmenu', (event) => {
|
||||
if (isNativeContextTarget(event.target)) return;
|
||||
|
||||
lastSelectionText = getSelectionText();
|
||||
lastImage = getImageTarget(event.target);
|
||||
event.preventDefault();
|
||||
openMenu(event.clientX, event.clientY);
|
||||
});
|
||||
|
||||
document.addEventListener('click', (event) => {
|
||||
const actionTarget = event.target instanceof Element ? event.target.closest('[data-context-action]') : null;
|
||||
if (!actionTarget || !menu.contains(actionTarget)) {
|
||||
closeMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
const action = actionTarget.dataset.contextAction;
|
||||
closeMenu();
|
||||
|
||||
if (action === 'back') history.back();
|
||||
if (action === 'forward') history.forward();
|
||||
if (action === 'reload') location.reload();
|
||||
if (action === 'copy-selection' && lastSelectionText) copyText(lastSelectionText);
|
||||
if (action === 'search-selection') searchSelection();
|
||||
if (action === 'quote-selection') quoteToComments();
|
||||
if (action === 'copy-image') copyImage();
|
||||
if (action === 'open-image') openImage();
|
||||
if (action === 'copy-image-url') copyText(new URL(getImageUrl(), window.location.href).toString());
|
||||
if (action === 'comments') jumpToComments();
|
||||
if (action === 'print') window.print();
|
||||
});
|
||||
|
||||
document.addEventListener('keydown', (event) => {
|
||||
if (event.key === 'Escape') closeMenu();
|
||||
if (event.key === 'Tab' && menu.classList.contains('is-open')) {
|
||||
const items = [...menu.querySelectorAll(focusableSelector)].filter((item) => !item.closest('[hidden]'));
|
||||
if (items.length === 0) return;
|
||||
const first = items[0];
|
||||
const last = items[items.length - 1];
|
||||
|
||||
if (event.shiftKey && document.activeElement === first) {
|
||||
event.preventDefault();
|
||||
last.focus();
|
||||
} else if (!event.shiftKey && document.activeElement === last) {
|
||||
event.preventDefault();
|
||||
first.focus();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('scroll', closeMenu, { passive: true });
|
||||
window.addEventListener('resize', closeMenu);
|
||||
})();
|
||||
</script> <script src="https://cdn.jsdmirror.com/npm/instantsearch.js@4.56.0"></script> <script src="https://cdn.jsdmirror.com/npm/typesense-instantsearch-adapter@2.7.0/dist/typesense-instantsearch-adapter.min.js"></script> <script src="https://cdn.jsdmirror.com/npm/@fancyapps/ui@5.0/dist/fancybox/fancybox.umd.js"></script> <script src="/js/random.js"></script> <script src="/js/search/typesense-search.js"></script> <script src="/js/external-links.js"></script> <script>
|
||||
(() => {
|
||||
const nav = document.querySelector('.nav');
|
||||
const toggle = document.querySelector('[data-nav-toggle]');
|
||||
const menu = document.querySelector('[data-nav-menu]');
|
||||
if (!nav || !toggle || !menu) return;
|
||||
|
||||
function setMenu(open) {
|
||||
nav.classList.toggle('is-open', open);
|
||||
toggle.setAttribute('aria-expanded', String(open));
|
||||
toggle.setAttribute('aria-label', open ? '关闭菜单' : '打开菜单');
|
||||
}
|
||||
|
||||
toggle.addEventListener('click', () => {
|
||||
setMenu(!nav.classList.contains('is-open'));
|
||||
});
|
||||
|
||||
menu.addEventListener('click', (event) => {
|
||||
if (event.target instanceof Element && event.target.closest('a')) setMenu(false);
|
||||
});
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
if (window.innerWidth > 720) setMenu(false);
|
||||
});
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const storageKey = 'site-theme';
|
||||
const root = document.documentElement;
|
||||
const button = document.querySelector('[data-theme-toggle]');
|
||||
const media = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
const getSystemTheme = () => (media.matches ? 'dark' : 'light');
|
||||
const getTheme = () => localStorage.getItem(storageKey) || getSystemTheme();
|
||||
|
||||
function applyTheme(theme) {
|
||||
root.dataset.theme = theme;
|
||||
button?.setAttribute('aria-label', theme === 'dark' ? '切换到日间模式' : '切换到夜间模式');
|
||||
button?.setAttribute('title', theme === 'dark' ? '切换到日间模式' : '切换到夜间模式');
|
||||
}
|
||||
|
||||
applyTheme(getTheme());
|
||||
|
||||
button?.addEventListener('click', () => {
|
||||
const nextTheme = root.dataset.theme === 'dark' ? 'light' : 'dark';
|
||||
localStorage.setItem(storageKey, nextTheme);
|
||||
applyTheme(nextTheme);
|
||||
});
|
||||
|
||||
media.addEventListener('change', () => {
|
||||
if (!localStorage.getItem(storageKey)) applyTheme(getSystemTheme());
|
||||
});
|
||||
})();
|
||||
|
||||
(() => {
|
||||
const runtime = document.getElementById('site-runtime');
|
||||
if (!runtime) return;
|
||||
|
||||
const start = new Date(window.SITE_CONFIG.site.startTime).getTime();
|
||||
const pad = (value) => String(value).padStart(2, '0');
|
||||
|
||||
function updateRuntime() {
|
||||
const diff = Math.max(0, Date.now() - start);
|
||||
const days = Math.floor(diff / 86400000);
|
||||
const hours = Math.floor((diff / 3600000) % 24);
|
||||
const minutes = Math.floor((diff / 60000) % 60);
|
||||
const seconds = Math.floor((diff / 1000) % 60);
|
||||
runtime.textContent = `${days} 天 ${pad(hours)} 时 ${pad(minutes)} 分 ${pad(seconds)} 秒`;
|
||||
}
|
||||
|
||||
updateRuntime();
|
||||
window.setInterval(updateRuntime, 1000);
|
||||
})();
|
||||
</script> </body> </html>
|
||||
@@ -0,0 +1 @@
|
||||
[{"title":"用 Umami 分享链接给网站信息卡提供统计数据","href":"/posts/4c91a8f2/"},{"title":"把普通的一天过成自己的节奏","href":"/posts/efe1e805/"},{"title":"GPT Image2 初试","href":"/posts/3f8de22/"},{"title":"电子价签玩法","href":"/posts/8712baaa/"},{"title":"OpenGL- Cohen-Sutherland 编码裁剪算法","href":"/posts/9b2ef00a/"},{"title":"OpenGL-直线的扫描转换","href":"/posts/7207243b/"},{"title":"OpenGL-基础程序","href":"/posts/437a5198/"},{"title":"配置OpenGL环境","href":"/posts/c4477b0c/"},{"title":"opencv应用-算术运算","href":"/posts/b559997d/"},{"title":"opencv应用-基础操作","href":"/posts/e8f95ead/"},{"title":"配置opencv","href":"/posts/6e3332b/"},{"title":"自建bitwarden服务","href":"/posts/7baa41fc/"},{"title":"自建renovate-bot","href":"/posts/56f57c0b/"},{"title":"新年快乐!","href":"/posts/5785bd01/"},{"title":"添加网站左上角菜单","href":"/posts/7e921903/"},{"title":"将博客仓库转移到gitea","href":"/posts/d2c8521/"},{"title":"安装gitea","href":"/posts/34725d47/"},{"title":"添加typesense搜索","href":"/posts/f287c563/"},{"title":"自定义字体","href":"/posts/b5601a7e/"},{"title":"在侧边栏添加日历和倒计时","href":"/posts/5ed2f1e6/"},{"title":"和朋友们的故事","href":"/posts/a31d95d9/"},{"title":"Adguard和Openclash共存","href":"/posts/66e66374/"},{"title":"Adguard规则分享","href":"/posts/69b16001/"},{"title":"在Openwrt上安装AdguardHome","href":"/posts/b57500e9/"},{"title":"在Openwrt中安装OpenClash","href":"/posts/2b2fb1a7/"},{"title":"Cudy TR3000刷入Openwrt系统","href":"/posts/8802e397/"},{"title":"搭建Owncloud并集成Onlyoffice","href":"/posts/59c8572a/"},{"title":"为博客添加CMS系统","href":"/posts/3a26a97a/"},{"title":"为1Panel添加自己想要的应用","href":"/posts/bb18d851/"},{"title":"使用GitHub推送Hexo到服务器","href":"/posts/ce1ec3fe/"},{"title":"C# 基本语法","href":"/posts/e9a8e898/"},{"title":"C# 入门","href":"/posts/bc56f789/"},{"title":"自定义页脚(新)","href":"/posts/c6143ad3/"},{"title":"自定义分类条","href":"/posts/33249733/"},{"title":"自定义导航栏","href":"/posts/3e61a389/"},{"title":"利用 SiteMap 随机访问站内页面","href":"/posts/b5866b9e/"},{"title":"博客添加AI总结","href":"/posts/41b9aff7/"},{"title":"利用插件自定义页脚菜单","href":"/posts/a6ab0925/"},{"title":"英语文章分享-去奋力生活吧,就好像死亡近在咫尺","href":"/posts/f0a1a1f4/"},{"title":"自定义右键菜单","href":"/posts/8bdb35fb/"},{"title":"在侧边栏中添加欢迎信息","href":"/posts/da17d00/"},{"title":"配置说说页面","href":"/posts/ad244066/"},{"title":"部署历程","href":"/posts/6e5f5039/"}]
|
||||
Loaded 3 of 100 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user