更新 更新了部分方案,不在原 css/js 上直接修改,而是引入自定义 css/js 来确保更新主题样式不会丢失。
前置 Solitude 确实有些不能满足我日益增长的需求,于是动手对其进行初步修改。
注意 请做好备份工作!魔改不规范,恢复两行泪!
1、修改文章链接格式 如果你的文章标题有中文,那么链接就会包含中文,复制下来直接一团乱麻(尤其是分享的时候)。 我们使用hexo-abbrlink
来解决这个问题。 注意应用完成后可能需要修改主题的配置文件(置顶文章链接等),不然会404。 还有评论,可能得去你的数据库手动链接一下评论到新的文章链接。如果你评论数量多的话,那估计比较麻烦(
安装插件 终端定位到博客根目录,输入:
1 npm install hexo-abbrlink --save
修改配置 打开_config.yml
,将permalink: :year/:month/:day/:title/
替换为:
1 2 3 4 permalink: post/:abbrlink.html abbrlink: alg: crc32 rep: hex
一键三连 后就完成了,效果如图:
2.字体更换 知周所众,默认字体看久了是会疲劳的。作为自己的博客,换字体肯定是必要的。
获得字体 废话,没字体怎么继续!
注意 请注意字体版权,在使用字体前,请确保其可以免费使用或者获得授权!
压缩与裁剪字体 显然一个字体文件大小几十MB,肯定是会拖慢网站加载速度的,所以速度和美观只能二选一。
但是有解决方案,可以使用在线工具或者离线工具。
离线剪裁与压缩字体:
1 2 3 4 brew install ripgrep brew install fonttools brotli pyftsubset fonts/{字体名称}.ttf --text=$(rg -e '[\w\d]' -oN --no-filename|sort |uniq |tr -d '\n' ) --no-hinting fonttools ttLib.woff2 compress -o fonts/{字体名称}.woff2 fonts/{字体名称}.ttf
参考:
这是一个外部链接,不能保证安全性。
中文字体压缩的那些事
hsingko.github.io
提示 反正我是没成功过,还是用在线工具吧。经过测试压缩为.woff2
是最好的。我这直接给它压到1MB不到。
应用 首先在/source下创建fonts
文件夹,然后把字体扔进去。
然后新建/themes/solitude/source/css/custom.css
,内容如下:
1 2 3 4 5 @font-face { font-family : "{字体名称}" ; src : url ("../fonts/{字体名称}.woff2" ) format ("truetype" ); font-weight : 300 ; }
提示 请自行调整 font-weight。
附:各种字体格式类型对照:
字体格式
字体类型
.ttf
truetype
.otf
opentype
.woff
woff
.woff2
woff2
.svg
svg
.eot
embedded-opentype
接着,在_comfig.solitudfe.yml
配置文件中head
下引入该CSS:
1 2 3 extends: head: - <link rel="stylesheet" href="/css/custom.css">
继续修改主题配置文件,应用字体,填入刚才的font-family
名称即可:
1 2 3 4 5 font: font-size: 16px code-font-size: 16px font-family: "{字体名称}" code-font-family: '"monospace", monospace'
最后一键三连 就能看到效果了。
3.修改代码高亮样式 个人觉得默认的代码高亮样式有点太亮了,因此对其样式进行修改。
在/themes/solitude/css/custom.css
中加入:
1 2 3 4 code :not ([class*='language-' ] ) { color : var (--efu-red) !important ; background : var (--efu-background) !important ; }
这样可以覆盖原来的样式。 接着修改color var
和background var
的值即可。/themes/solitude/css/_mode/index.styl
中存储了所有预设颜色,填入你需要的颜色即可。 例如:color var(--efu-red)
,即可将其代码高亮修改为红色(#ff3842)
。
自定义颜色 注意到该index.styl
的格式为:
text
同时可以看到data-theme=dark
和data-theme=light
,这意味着可以分别自定义深色和浅色的颜色。
举个栗子: 在/themes/solitude/css/custom.css
中加入:
1 2 3 4 5 6 7 8 9 [data-theme="dark" ] { --efu-code-background : #2c2c2c ; --efu-code-text : #f47466 ; } [data-theme="light" ] { --efu-code-background : #f3f4f4 ; --efu-code-text : #f47466 ; }
接着继续加入:
1 2 3 4 code :not ([class*='language-' ] ) { color : var (--efu-code-text) !important ; background : var (--efu-code-background) !important ; }
深色效果: 浅色效果:
4.修改引用块颜色 个人观点,默认的样式有点太淡了。 在/themes/solitude/css/custom.css
中加入:
1 2 3 4 blockquote { background-color : var (--efu-secondbg); color : var (--efu-secondtext) }
修改两个颜色值即可。 颜色预设依然在/themes/solitude/css/_mode/index.styl
注意 无论什么情况,请不要修改预设颜色,可能造成无法预料的后果!
例如,将引用块颜色与主题色同步:
1 2 3 4 blockquote { background-color : var (--efu-theme); color : var (--efu-white) }
提示 因为我两种颜色都适合白字,所以直接用–efu-white了,因为懒。
附:找到要修改元素对应文件的小技巧 例如找到代码高亮的元素
: 首先用万能的F12大法
打开开发者工具,左上角抓取对应的元素,找到Styles。 点击右上角的index.css
,可以看到文件的大概结构。 可以确定是css,那么直接定位到/themes/solitude/css/
。 接下来,关键词搜索,可以找到该条目对应的原始css文件,即例子中的的article-container.styl
。 找到对应配置,直接修改即可。
5.右键菜单拓展 添加复制当前页面链接 新建/themes/solitude/js/copylink.js
,内容如下:
1 2 3 4 5 6 7 8 9 10 function copyPostLink ( ) { const postLink = window .location .href ; navigator.clipboard .writeText (postLink).then (() => { utils.snackbarShow ("当前页面链接已复制到剪贴板" , false , 2000 ); }).catch (err => { console .error ("无法复制链接" , err); utils.snackbarShow ("复制失败,请重试" , false , 2000 ); }); }
修改_config.solitude.yml
,引入js:
1 2 3 extends: body: - <script src="/js/copylink.js" async></script>
然后右键菜单添加该项即可:
1 2 3 4 5 6 7 right_menu: custom_list: - name: 复制链接 click: copyPostLink() id: menu-copyPostLink class: icon: fas fa-link
6.边栏添加倒计时 此条目参考了: 梦爱吃鱼
的方案给主题侧边栏添加倒计时 - 梦爱吃鱼 新建/themes/solitude/layout/includes/aside/card_countdown.pug
:
1 2 3 4 5 6 7 8 9 if theme.aside.card_countdown.enable .card-widget.card-countdown .item-content .cd-count-left#countLeft span.cd-text 距离 span.cd-name#eventName!= theme.aside.card_countdown.event_name span.cd-time#daysUntil span.cd-date#eventDate!= theme.aside.card_countdown.event_date .cd-count-right#countRight
新建/themes/solitude/source/js/countdown.js
:
提示 若需要自动切换进度条内字体颜色,请将 .cd-many 后面 color 的值改为 –efu-fontcolor 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 const CountdownTimer = (() => { const config = { units : { day : { text : "今日" , divider : 1 , unit : "小时" }, week : { text : "本周" , divider : 24 , unit : "天" }, month : { text : "本月" , divider : 24 , unit : "天" }, year : { text : "本年" , divider : 24 , unit : "天" } } }; function getTimeUnit (unit ) { const now = new Date (); const start = new Date (now.setHours (0 , 0 , 0 , 0 )); const end = new Date (now.setHours (23 , 59 , 59 , 999 )); if (unit === 'day' ) { const currentHour = new Date ().getHours (); const remaining = 24 - currentHour; const percentage = (currentHour / 24 ) * 100 ; return { name : config.units [unit].text , remaining : remaining, percentage : percentage.toFixed (2 ), unit : config.units [unit].unit }; } const ranges = { week : () => { start.setDate (start.getDate () - start.getDay ()); end.setDate (end.getDate () - end.getDay () + 6 ); }, month : () => { start.setDate (1 ); end.setMonth (end.getMonth () + 1 , 0 ); }, year : () => { start.setMonth (0 , 1 ); end.setMonth (11 , 31 ); } }; ranges[unit]?.(); const total = unit === "day" ? 24 : Math .floor ((end - start) / 86400000 ) + 1 ; const passed = Math .floor ((now - start) / (3600000 * config.units [unit].divider )); const percentage = (passed / total) * 100 ; return { name : config.units [unit].text , remaining : total - passed, percentage : percentage.toFixed (2 ), unit : config.units [unit].unit }; } function updateCountdown ( ) { const elements = ['eventName' , 'eventDate' , 'daysUntil' , 'countRight' ] .map (id => document .getElementById (id)); if (elements.some (el => !el)) return ; const [eventName, eventDate, daysUntil, countRight] = elements; const timeData = Object .keys (config.units ).reduce ((acc, unit ) => ({ ...acc, [unit]: getTimeUnit (unit) }), {}); const daysRemaining = Math .round ((new Date (eventDate.textContent ) - new Date ().setHours (0 , 0 , 0 , 0 )) / 86400000 ); daysUntil.textContent = daysRemaining; countRight.innerHTML = Object .entries (timeData) .map (([_, item] ) => ` <div class="cd-count-item"> <div class="cd-item-name">${item.name} </div> <div class="cd-item-progress"> <div class="cd-progress-bar" style="width: ${item.percentage} %; opacity: ${item.percentage / 100 } "></div> <span class="cd-percentage ${item.percentage >= 46 ? 'cd-many' : '' } ">${item.percentage} %</span> <span class="cd-remaining ${item.percentage >= 60 ? 'cd-many' : '' } "> <span class="cd-tip">还剩</span>${item.remaining} <span class="cd-tip">${item.unit} </span> </span> </div> </div> ` ).join ('' ); } function injectStyles ( ) { const styles = ` .card-countdown .item-content { display: flex; } .cd-count-left { position: relative; display: flex; flex-direction: column; margin-right: 0.8rem; line-height: 1.5; align-items: center; justify-content: center; } .cd-count-left .cd-text { font-size: 14px; } .cd-count-left .cd-name { font-weight: bold; font-size: 18px; } .cd-count-left .cd-time { font-size: 30px; font-weight: bold; color: var(--efu-fontcolor); } .cd-count-left .cd-date { font-size: 12px; opacity: 0.6; } .cd-count-left::after { content: ""; position: absolute; right: -0.8rem; width: 2px; height: 80%; background-color: var(--efu-fontcolor); opacity: 0.5; } .cd-count-right { flex: 1; margin-left: .8rem; display: flex; flex-direction: column; justify-content: space-between; } .cd-count-item { display: flex; flex-direction: row; align-items: center; height: 24px; } .cd-item-name { font-size: 14px; margin-right: 0.8rem; white-space: nowrap; } .cd-item-progress { position: relative; display: flex; flex-direction: row; align-items: center; justify-content: space-between; height: 100%; width: 100%; border-radius: 8px; background-color: var(--efu-background); overflow: hidden; } .cd-progress-bar { height: 100%; border-radius: 8px; background-color: var(--efu-theme); } .cd-percentage, .cd-remaining { position: absolute; font-size: 12px; margin: 0 6px; transition: opacity 0.3s ease-in-out, transform 0.3s ease-in-out; } .cd-many { color: var(--efu-white); } .cd-remaining { opacity: 0; transform: translateX(10px); } .card-countdown .item-content:hover .cd-remaining { transform: translateX(0); opacity: 1; } .card-countdown .item-content:hover .cd-percentage { transform: translateX(-10px); opacity: 0; } ` ; const styleSheet = document .createElement ("style" ); styleSheet.textContent = styles; document .head .appendChild (styleSheet); } let timer; const start = ( ) => { injectStyles (); updateCountdown (); timer = setInterval (updateCountdown, 600000 ); }; ['pjax:complete' , 'DOMContentLoaded' ].forEach (event => document .addEventListener (event, () => { clearInterval (timer); start (); })); document .addEventListener ('pjax:send' , () => timer && clearInterval (timer)); return { start, stop : () => timer && clearInterval (timer) }; })();
修改/themes/solitude/layout/includes/widgets/aside/asideSwitch.pug
,加入:
1 2 3 case item when 'countdown' include ./card_countdown.pug
在_config.solitude.yml
中引入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 aside: home: noSticky: "about,countdown" Sticky: "newestPost,allInfo" post: noSticky: "about,countdown" Sticky: "newestPost" page: noSticky: "about,countdown" Sticky: "newestPost,allInfo" card_countdown: enable: true event_date: '2025-01-29' event_name: 春节
最后引入js即可:
1 2 3 extends: body: - <script defer pjax src="/js/countdown.js"></script>
7.边栏添加访客卡片 此条目参考了青桔
的方案。Solitude添加来访者卡片 - 青桔气球 在 奶思猫API 申请你的API,用于 IPv4/IPv6 信息查询。
奶思猫API
新建/source/aside.yml
,内容如下:
1 2 3 4 5 6 7 8 9 10 - name: visinfo title: 访客信息 class: card-welcome id: icon: fas fa-location-dot content_id: welcome-info content_css: 'height:160px;overflow:hidden' content_html: '<div class="welcome_swiper-container" id="welcome-container" style="width: 100%;height: 100%;margin-top: 6px"> <div id="welcome_container_wrapper" class="swiper-wrapper"></div> </div>'
新建/themes/solitude/source/js/visinfo.js
,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 let ipLocation; fetch ('https://api.nsmao.net/api/ip/query?key={apikey}' ) .then (response => { if (!response.ok ) {throw new Error ('Network response was not ok' );} return response.json ();}) .then (data => { ipLocation = data; if (isHomePage ()) {showWelcome ();} }) .catch (error => console .error ('Error:' , error)); 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 ( ) {if (!ipLocation || !ipLocation.data ) {console .error ('ipLocation data is not available.' );return ;} let dist = getDistance (-33.89083 , -151.199167 , ipLocation.data .lng , ipLocation.data .lat ); let pos = ipLocation.data .country ; let ip = ipLocation.ip ; let posdesc; switch (ipLocation.data .country ) { 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.data .prov + " " + ipLocation.data .city + " " + ipLocation.data .district ; switch (ipLocation.data .prov ) { case "北京市" : posdesc = "北——京——欢迎你~~~" ; break ; case "上海市" : posdesc = "走在外滩,感受历史与现代的交融。" ; break ; case "广东省" : switch (ipLocation.data .city ) { case "广州市" : posdesc = "看小蛮腰,喝早茶了嘛~" ; break ; case "深圳市" : posdesc = "今天你逛商场了嘛~" ; break ; default : posdesc = "带你感受广东的热情与美食!" ; break ; } break ; case "浙江省" : switch (ipLocation.data .city ) { case "杭州市" : posdesc = "西湖美景,三月天~" ; break ; case "宁波市" : posdesc = "来宁波,感受大海的气息。" ; break ; default : posdesc = "这里是浙江,充满江南的韵味!" ; break ; } break ; case "四川省" : switch (ipLocation.data .city ) { case "成都市" : posdesc = "宽窄巷子,成都慢生活。" ; break ; case "绵阳市" : posdesc = "享受科技城的宁静与创新。" ; break ; default : posdesc = "来四川,品麻辣火锅,赏壮丽山河。" ; break ; } break ; case "福建省" : switch (ipLocation.data .city ) { case "厦门市" : posdesc = "鼓浪屿听海,厦门美食让人流连忘返。" ; break ; case "福州市" : posdesc = "有福之州,来此感受千年古城。" ; break ; default : posdesc = "福建山水如画,美景无处不在。" ; break ; } break ; case "山东省" : switch (ipLocation.data .city ) { case "青岛市" : posdesc = "来青岛喝啤酒,看大海吧!" ; break ; case "济南市" : posdesc = "泉城济南,四面荷花三面柳。" ; break ; default : posdesc = "山东好客,欢迎来感受齐鲁文化!" ; break ; } break ; case "江苏省" : switch (ipLocation.data .city ) { case "南京市" : posdesc = "六朝古都南京,历史与现代的碰撞。" ; break ; case "苏州市" : posdesc = "来苏州,感受园林之美。" ; break ; default : posdesc = "水乡泽国,江南佳丽地。" ; break ; } break ; case "河北省" : posdesc = "燕赵大地,英雄辈出的河北,等你探索!" ; break ; case "河南省" : switch (ipLocation.data .city ) { case "郑州市" : posdesc = "中原大地,郑州是交通枢纽与历史重镇。" ; break ; case "洛阳市" : posdesc = "千年古都洛阳,牡丹花开的城市。" ; break ; default : posdesc = "这里是河南,历史悠久文化灿烂。" ; break ; } break ; case "湖南省" : switch (ipLocation.data .city ) { case "长沙市" : posdesc = "热辣长沙,吃小龙虾逛黄兴路步行街。" ; break ; default : posdesc = "湖南,烟雨迷蒙的湘江流过这片土地。" ; break ; } break ; case "湖北省" : switch (ipLocation.data .city ) { case "武汉市" : posdesc = "来大武汉,过长江大桥,吃热干面!" ; break ; default : posdesc = "湖北,长江中游的明珠,风景秀丽。" ; break ; } break ; case "安徽省" : switch (ipLocation.data .city ) { case "合肥市" : posdesc = "创新之城合肥,科教文化汇聚地。" ; break ; default : posdesc = "安徽山水,黄山、九华山欢迎你。" ; break ; } break ; case "广西壮族自治区" : switch (ipLocation.data .city ) { case "桂林市" : posdesc = "桂林山水甲天下,风景如画。" ; break ; case "南宁市" : posdesc = "绿城南宁,宜居宜游。" ; break ; default : posdesc = "广西山清水秀,民俗风情浓郁。" ; break ; } break ; case "贵州省" : posdesc = "来贵州,品茅台,赏黄果树瀑布。" ; break ; case "云南省" : switch (ipLocation.data .city ) { case "昆明市" : posdesc = "春城昆明,四季如春,风景秀丽。" ; break ; case "大理市" : posdesc = "苍山洱海,大理古城,你来了就不想走。" ; break ; default : posdesc = "云南风景独特,风情万种。" ; break ; } break ; case "西藏自治区" : posdesc = "世界屋脊西藏,神秘而纯净。" ; break ; case "新疆维吾尔自治区" : posdesc = "辽阔新疆,民族风情与壮丽景观并存。" ; break ; case "内蒙古自治区" : posdesc = "草原辽阔的内蒙古,等你来策马奔腾。" ; break ; case "宁夏回族自治区" : posdesc = "宁夏,塞上江南,黄河流经的美丽地方。" ; break ; case "海南省" : posdesc = "阳光、沙滩、椰风海韵,欢迎来海南度假。" ; break ; default : posdesc = "带我去你的城市逛逛吧!" ; break ; } break ; default : posdesc = "带我去你的国家逛逛吧" ; break ; } let welcomeInfoElement = document .getElementById ("welcome-info" ); if (welcomeInfoElement) { welcomeInfoElement.innerHTML = `欢迎来自 <b><span style="color: var(--efu-main)">${pos} </span></b> 的朋友!💖<br>当前位置距我约 <b><span style="color: var(--efu-main)">${dist.toFixed(2 )} </span></b> 公里!<br>我这(?)还蛮大的(bushi),欢迎来我这玩~<br>Tip:<b><span style="font-size: 15px;">${posdesc} </span></b>` ; } } function handlePjaxComplete ( ) { if (isHomePage ()) { showWelcome (); } } function isHomePage ( ) { return window .location .pathname === '/' || window .location .pathname === '/index.html' ; } window .onload = function ( ) { if (isHomePage ()) { showWelcome (); } document .addEventListener ("pjax:complete" , handlePjaxComplete); }
修改_config.solitude.yml
,home 的边栏添加刚才的 visinfo:
1 2 3 4 aside: home: noSticky: "about,visinfo" Sticky: "newestPost,allInfo"
最后引入js即可:
1 2 3 extends: body: - <script defer pjax src="/js/visinfo.js"></script>
8.底部添加自定义图片 此条目由青桔
的方案修改而来。
给你的博客底部添加一排宠物 - 青桔气球
在/themes/solitude/layout/includes/footer.pug
加入:
1 2 3 4 5 6 7 8 div#footer-image img.image.entered.loaded( src="/img/sample.png" // 修改为你图片的地址 onerror="this.onerror=null;this.src='/img/404.jpg';" data-lazy-src="/img/sample.png" // 修改为你图片的地址 alt="Photo" data-ll-status="loaded" )
在/themes/solitude/source/css/custom.css
中加入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #footer-image { position : relative; width : 100% ; } @media screen and (max-width : 1023px ) { #footer-image img .image { position : absolute; bottom : 0 ; left : 0 ; width : 100% ; max-width : 100% ; height : auto; margin : 0 auto; display : block; opacity : 0.9 ; object-fit : cover; } } @media screen and (min-width : 1024px ) { #footer-image img .image { position : absolute; bottom : 0 ; left : 50% ; transform : translateX (-50% ); width : 30% ; max-width : 100% ; height : auto; opacity : 0.9 ; } } #footer-bar { margin-top : 0 !important ; }
9.导航栏模糊效果 在/themes/solitude/source/css/custom.css
中加入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 [data-theme=light] #nav .menus_items .menus_item .menus_item_child { background-color : #ffffff4f !important ; backdrop-filter : blur (7px )!important ; -webkit-backdrop-filter : blur (7px )!important } [data-theme=dark] #nav .menus_items .menus_item .menus_item_child { background-color : #1d1e224f !important ; backdrop-filter : blur (7px )!important ; -webkit-backdrop-filter : blur (7px )!important } [data-theme=dark] #page-header .nav-fixed #nav { background : #0000006f !important } [data-theme=light] #page-header .nav-fixed #nav { background : #ffffff4f !important ; } #page-header .nav-fixed #nav { outline : 1px #7c7c7c43 solid!important ; backdrop-filter : blur (7px )!important ; -webkit-backdrop-filter : blur (7px )!important } @media screen and (max-width : 768px ) { #nav { background :#fff0 !important } } @media screen and (max-width : 768px ) { body [data-type=post] #page-header #nav { --font-color :#fff } } @media screen and (max-width : 768px ) { #page-header .nav-fixed #nav { --font-color : var (--efu-fontcolor)!important ; } } [data-theme=dark] #page-header .nav-fixed #nav { background : #1d1e224f !important ; backdrop-filter : blur (7px )!important ; -webkit-backdrop-filter : blur (7px )!important }
10.自定义鼠标指针 新建/themes/solitude/source/cur
文件夹,然后把你的鼠标指针图片放进去。(cur or png) 在/themes/solitude/source/css/custom.css
中加入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 html , body { cursor : url ('/cur/nor.cur' ), auto !important ; } a , button , .clickable { cursor : url ('/cur/link_select.cur' ), pointer !important ; } textarea , input , select { cursor : url ('/cur/text_select.cur' ), text !important ; } * { cursor : inherit !important ; }
在/themes/solitude/source/js/custom.js
中加入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 document .addEventListener ('DOMContentLoaded' , function ( ) { document .body .style .cursor = 'url("/cur/nor.cur"), auto' ; document .querySelectorAll ('a, button, .clickable' ).forEach (element => { element.addEventListener ('mouseenter' , function ( ) { document .body .style .cursor = 'url("/cur/link_select.cur"), pointer' ; }); element.addEventListener ('mouseleave' , function ( ) { document .body .style .cursor = 'url("/cur/nor.cur"), auto' ; }); }); document .querySelectorAll ('textarea, input, select' ).forEach (element => { element.addEventListener ('mouseenter' , function ( ) { document .body .style .cursor = 'url("/cur/text_select.cur"), text' ; }); element.addEventListener ('mouseleave' , function ( ) { document .body .style .cursor = 'url("/cur/nor.cur"), auto' ; }); }); });
注意 请自行修改鼠标指针的名称。当然你要是指针名字一样当我没说。
引入js:
1 2 3 extends: body: - <script src="/js/custom.js"></script>
11.修改纯色背景 即当background: false
时的全局背景。 在/themes/solitude/source/css/custom.css
中加入:
1 2 3 4 5 [data-theme="dark" ] { --efu-background : #342024 ; --efu-card-bg : #342024 ; --efu-secondbg : #342024 ; }
这样会将预设中的背景色覆盖, 效果并不如本站所示。(滑稽)
12.修改页面/操作提示词 与以下文件有关:/themes/solitude/languages/default.yml
/themes/solitude/languages/zh-CN.yml
/themes/solitude/languages/en.yml
/themes/solitude/source/tw_cn.js
13.链接卡
注意 进行此修改会导致 Fancybox 图片灯箱无法正常使用。
链接卡样式参考了Ariasakaの小窝
:Ariasakaの小窝
在/themes/solitude/source/css/custom.css
中加入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 .efu-link { display : grid; margin : 10px ; background : var (--efu-hltools-bg); border-radius : 10px ; grid-template-rows : 28px min-content; grid-template-columns : 80px calc (100% - 80px ); height : 100px ; padding : 5px ; transition : .2s ; -webkit-transition : .3s ; -moz-transition : .3s ; -ms-transition : .3s ; -o-transition : .3s ; position : relative } .efu-link :after { content : "" ; top : 50% ; position : absolute; right : 15px ; width : 16px ; height : 16px ; background-color : var (--efu-fontcolor); -webkit-mask-image : url (data:image/svg+xml;charset=utf-8;base64,PHN2ZyB0PSIxNzI1Mjk1MDA0Njc5IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjE2NTciIGlkPSJteF9uXzE3MjUyOTUwMDQ2NzkiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTgxNi42NTMwOTMgNDY5LjU0NDA0OWMtMS40OTUwNS0xLjQ5NTA1LTMuMDYwNzA5LTIuODc0NDY3LTQuNjc2NTA5LTQuMTU5NzRMNDI4LjQ3NTE5IDc5Ljg5NTY1NWMtMjEuMzUxMjg0LTIxLjM1MDI2MS01NS45Njc2ODYtMjEuMzUwMjYxLTc3LjMxNzk0NiAwLTIxLjM1MDI2MSAyMS4zNTEyODQtMjEuMzUwMjYxIDU1Ljk2NjY2MyAwIDc3LjMxNzk0NmwzNDkuMjU5NTIyIDM1MS4yNDc4MDZMMzQzLjY1NjQwOSA4NjQuODgzMDQ5Yy0yMS4zNTAyNjEgMjEuMzUxMjg0LTIxLjM1MDI2MSA1NS45NjY2NjMgMCA3Ny4zMTg5NyAyMS4zNTAyNjEgMjEuMzUwMjYxIDU1Ljk2NjY2MyAyMS4zNTAyNjEgNzcuMzE3OTQ2IDBsMzkwLjk5ODEzNS0zOTAuNjYxNDY4YzEuNjE2ODI0LTEuMjg2Mjk2IDMuMTgzNTA2LTIuNjY0Njg5IDQuNjc5NTc5LTQuMTYwNzYzIDEwLjc0MDYyMi0xMC43NDA2MjIgMTYuMDczMDctMjQuODM5NzM1IDE2LjAwNjU1Ni0zOC45MTczNThDODMyLjcyNjE2NCA0OTQuMzgyNzYgODI3LjM5MzcxNSA0ODAuMjg0NjcxIDgxNi42NTMwOTMgNDY5LjU0NDA0OXoiIGZpbGw9InZhcigtLWFyaWEtZm9udGNvbG9yKSIgcC1pZD0iMTY1OCI+PC9wYXRoPjwvc3ZnPg== ); mask-image : url (data:image/svg+xml;charset=utf-8;base64,PHN2ZyB0PSIxNzI1Mjk1MDA0Njc5IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjE2NTciIGlkPSJteF9uXzE3MjUyOTUwMDQ2NzkiIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiI+PHBhdGggZD0iTTgxNi42NTMwOTMgNDY5LjU0NDA0OWMtMS40OTUwNS0xLjQ5NTA1LTMuMDYwNzA5LTIuODc0NDY3LTQuNjc2NTA5LTQuMTU5NzRMNDI4LjQ3NTE5IDc5Ljg5NTY1NWMtMjEuMzUxMjg0LTIxLjM1MDI2MS01NS45Njc2ODYtMjEuMzUwMjYxLTc3LjMxNzk0NiAwLTIxLjM1MDI2MSAyMS4zNTEyODQtMjEuMzUwMjYxIDU1Ljk2NjY2MyAwIDc3LjMxNzk0NmwzNDkuMjU5NTIyIDM1MS4yNDc4MDZMMzQzLjY1NjQwOSA4NjQuODgzMDQ5Yy0yMS4zNTAyNjEgMjEuMzUxMjg0LTIxLjM1MDI2MSA1NS45NjY2NjMgMCA3Ny4zMTg5NyAyMS4zNTAyNjEgMjEuMzUwMjYxIDU1Ljk2NjY2MyAyMS4zNTAyNjEgNzcuMzE3OTQ2IDBsMzkwLjk5ODEzNS0zOTAuNjYxNDY4YzEuNjE2ODI0LTEuMjg2Mjk2IDMuMTgzNTA2LTIuNjY0Njg5IDQuNjc5NTc5LTQuMTYwNzYzIDEwLjc0MDYyMi0xMC43NDA2MjIgMTYuMDczMDctMjQuODM5NzM1IDE2LjAwNjU1Ni0zOC45MTczNThDODMyLjcyNjE2NCA0OTQuMzgyNzYgODI3LjM5MzcxNSA0ODAuMjg0NjcxIDgxNi42NTMwOTMgNDY5LjU0NDA0OXoiIGZpbGw9InZhcigtLWFyaWEtZm9udGNvbG9yKSIgcC1pZD0iMTY1OCI+PC9wYXRoPjwvc3ZnPg== ) } .efu-link-tip { grid-column-start : 1 ; grid-column-end : 3 ; grid-row : 1 ; display : inline-flex; white-space : nowrap; font-size : 12px ; line-height : 1.5 ; color : var (--efu-fontcolor); margin : 0 15px ; padding-top : 5px ; border-bottom : var (--efu-code-background) } .efu-link-subtitle { grid-column : 2 ; grid-row : 3 } .efu-link-img { grid-column : 1 ; grid-row-start : 2 ; grid-row-end : 4 ; margin : auto; border-radius : 50% ; width : 60px ; height : 60px ; object-fit : cover } .efu-link-title { white-space : nowrap; overflow : hidden; text-overflow : ellipsis; } .efu-link-subtitle { font-size : 12px ; color : var (--efu-fontcolor) } .efu-link :hover { background-color : var (--efu-theme); box-shadow : 0 0 8px var (--efu-theme); border : 1px solid var (--efu-theme) } .efu-link :hover * { color : #fff } .efu-link :hover :after { background-color : #fff } .article-container img :not (.post_bg ) { border-radius : 12px ; object-fit : cover; display : block; margin : auto; max-width : 90% ; max-height : 450px ; }
新建/themes/solitude/source/js/link-decorator.js
,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 function decorateLinks ( ) { const postContainer = document .querySelector ('.post-content' ); if (!postContainer) return ; const links = postContainer.querySelectorAll ('a[href]' ); links.forEach (link => { const href = link.getAttribute ('href' ); const title = link.innerText .trim (); if (href.startsWith ('http' ) && !href.includes (window .location .hostname )) { const card = document .createElement ('div' ); card.classList .add ('efu-link' ); card.style .cursor = 'pointer' ; const url = new URL (href); const domain = url.hostname .replace (/^www\./ , '' ); card.innerHTML = ` <div class="efu-link-img"> <img src="https://s1.imagehub.cc/images/2024/12/02/632726f0a6dadcc20df6371b774148db.png" alt="Link Thumbnail"> </div> <div class="efu-link-tip">这是一个外部链接,不能保证安全性。</div> <div class="efu-link-title">${title} </div> <div class="efu-link-subtitle">${domain} </div> ` ; card.addEventListener ('click' , () => { window .open (href, '_blank' ); }); link.replaceWith (card); } }); } setTimeout (() => { document .addEventListener ('pjax:complete' , decorateLinks); }, 1000 ); document .addEventListener ('DOMContentLoaded' , function ( ) { decorateLinks (); document .addEventListener ('pjax:complete' , decorateLinks); });
最后引入一下 js 就大功告成!
1 2 3 extends: body: - <script defer pjax src="/js/link-decorator.js"></script>
14.加个聊天气泡 在Hexo 根目录
下新建一个scripts
文件夹,里面存放chat.js
,内容如下:
1 2 3 4 5 6 7 8 9 10 hexo.extend .tag .register ('chat' , function (args, content ) { const [role, nickname] = args; const text = hexo.render .renderSync ({ text : content, engine : 'markdown' }); return ` <div class="chat-item ${role} "> <div class="chat-nickname">${nickname} </div> <div class="chat-bubble">${text} </div> </div> ` ; }, {ends : true });
在/themes/solitude/source/css/custom.css
中加入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 [data-theme="dark" ] { --efu-chat-background : #4b3539 ; --efu-chat-a-background : #2b3a5c ; } [data-theme="light" ] { --efu-chat-background : #332c36 ; --efu-chat-a-background : #f7f9fe ; } .article-post-content-chat-container { margin : 0 ; } .chat-item { display : flex; margin-bottom : 0rem ; position : relative; } .chat-item .user { justify-content : flex-end; margin-bottom : 0rem } .chat-item .assistant { justify-content : flex-start; margin-bottom : 0rem } .chat-bubble { padding : 0px 12px ; border-radius : 10px ; max-width : 70% ; max-height : 50% ; word-wrap : break-word; word-break : break-word; box-shadow : 0 2px 4px rgba (0 , 0 , 0 , 0.1 ); } .chat-item .user .chat-bubble { background-color : var (--efu-chat-background); text-align : left; color : #ffffff ; margin-top : 15px ; } .chat-item .assistant .chat-bubble { background-color : var (--efu-chat-a-background); text-align : left; color : var (--efu-fontcolor); margin-top : 15px ; } .chat-item .user .chat-nickname { position : absolute; top : -18px ; right : 0 ; font-size : 12px ; font-weight : bold; color : var (--efu-fontcolor); background-color : var (--efu-background); padding : 2px 5px ; margin-top : 15px ; border-radius : 5px ; box-shadow : 0 0 2px rgba (0 , 0 , 0 , 0.1 ); } .chat-item .assistant .chat-nickname { position : absolute; top : -18px ; left : 0 ; font-size : 12px ; font-weight : bold; color : var (--efu-fontcolor); background-color : var (--efu-background); padding : 2px 5px ; margin-top : 15px ; border-radius : 5px ; box-shadow : 0 0 2px rgba (0 , 0 , 0 , 0.1 ); }
这样就完成了,如果需要在Markdown
中引用,这么写就可以:
1 2 3 4 5 6 7 {% chat assistant "English" %} Hello, world! {% endchat %} {% chat user "简体中文" %} 你好,世界! {% endchat %}
效果:
15.安卓样式加载条 找到/themes/solitude/source/css/layout/pace.styl
,直接全部替换:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 if hexo-config ('loading.pace' ) .pace pointer-events : none user-select : none z-index : 2000 position : fixed top : 55px left : 0 right : 0 height : 4px background : var (--efu-loader) overflow : hidden &.pace-inactive opacity : 0 transition : .3s .pace-progress opacity : 0 transition : .3s ease-in .pace-progress box-sizing : border-box transform : translate3d (0 , 0 , 0 ) z-index : 2000 display : block position : absolute top : 0 left : 0 height : 100% width : 0 background : var (--efu-theme) animation : android-loader 2s ease infinite background-size : 200% @keyframes android-loader 0% { width : 0 ; } 50% { width : 50% ; } 100% { width : 100% ; }
Troubleshoot 如果遇到样式不生效 ,不正常 ,不显示 的问题,一般可以通过清除浏览器缓存解决。 如果还是不行,那就检查一下修改有没有问题,或者有没有保存
吧…
先更到这吧,如果还想改什么就接着更新…