// ==UserScript==
// @name 輕小說文庫 wenku8 字型+大小調整
// @namespace http://tampermonkey.net/
// @version 1.5
// @description 即時調整 Wenku8 內容區字型與大小
// @author shanlan(ChatGPT o3-mini)
// @match http*://www.wenku8.net/modules/article/reader.php*cid=*
// @match http*://www.wenku8.cc/modules/article/reader.php*cid=*
// @grant none
// @run-at document-end
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const uiStyle = document.createElement('style');
uiStyle.textContent = `
.tm-ui-btn, .tm-ui-panel {
all: unset;
box-sizing: border-box;
font-family: sans-serif;
}
.tm-ui-btn {
position: fixed;
right: 12px;
top: 12px;
width: 32px;
height: 32px;
background: #333 !important;
color: #f1f1f1 !important;
border: 1px solid #555 !important;
border-radius: 50% !important;
box-shadow: 0 2px 8px rgba(0,0,0,0.5) !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
font-weight: bold !important;
font-size: 18px !important;
cursor: pointer !important;
z-index: 9999 !important;
user-select: none !important;
}
.tm-ui-panel {
position: fixed;
right: 12px;
top: 56px;
background: #222 !important;
color: #f1f1f1 !important;
border: 1px solid #555 !important;
border-radius: 12px !important;
box-shadow: 0 2px 12px rgba(0,0,0,0.6) !important;
padding: 18px 20px !important;
font-size: 21px !important;
display: none;
z-index: 9999 !important;
transform: scale(1.0);// 介面大小倍率
transform-origin: top right;
min-width: 320px;
}
.tm-ui-panel select,
.tm-ui-panel input,
.tm-ui-panel button {
background: #333 !important;
color: #f1f1f1 !important;
border: 1px solid #555 !important;
border-radius: 6px !important;
padding: 4px 8px !important;
font-size: 20px !important;
margin-right: 8px;
}
.tm-ui-panel button {
cursor: pointer !important;
min-width: 36px;
min-height: 36px;
}
.tm-ui-panel label,
.tm-ui-panel span {
color: #f1f1f1 !important;
font-size: 21px !important;
}
.tm-ui-panel input[type="text"] {
width: 60px !important;
text-align: center;
}
`;
document.head.appendChild(uiStyle);
const fonts = [
['', '預設'],
['"Noto Sans TC", "思源黑體", "Microsoft JhengHei", "微軟正黑體", sans-serif', '思源黑體'],
['"Noto Serif TC", "思源宋體", "PMingLiU", "新細明體", serif', '思源宋體'],
['"Microsoft JhengHei", "微軟正黑體", sans-serif', '微軟正黑體'],
['"Microsoft JhengHei UI", "微軟正黑體 UI", sans-serif', '微軟正黑體 UI'],
['"PMingLiU", "新細明體", serif', '新細明體'],
['"MingLiU", "細明體", serif', '細明體'],
['"DFKai-SB", "標楷體", serif', '標楷體'],
['"SimSun", "宋體", serif', '宋體'],
['"Microsoft YaHei", "微軟雅黑", sans-serif', '微軟雅黑'],
['Arial, Helvetica, sans-serif', 'Arial'],
['serif', 'Serif']
];
let font = localStorage.getItem('wenku8_font') || '';
let size = parseInt(localStorage.getItem('wenku8_fontsize')) || 18;
function updateStyle() {
let s = document.getElementById('wenku8-style');
if (!s) {
s = document.createElement('style');
s.id = 'wenku8-style';
document.head.appendChild(s);
}
s.textContent = `#content, #content * { font-family: ${font || 'inherit'} !important; font-size: ${size}px !important; }`;
}
updateStyle();
const mainBtn = document.createElement('div');
mainBtn.textContent = '字';
mainBtn.classList.add('tm-ui-btn');
const panel = document.createElement('div');
panel.classList.add('tm-ui-panel');
const fontLabel = document.createElement('label');
fontLabel.textContent = '字型:';
fontLabel.style.marginRight = '8px';
const fontSel = document.createElement('select');
fonts.forEach(([v, n]) => {
const opt = new Option(n, v);
if (v === font) opt.selected = true;
fontSel.add(opt);
});
fontSel.style.marginRight = '20px';
const sizeContainer = document.createElement('span');
sizeContainer.style.display = 'inline-flex';
sizeContainer.style.alignItems = 'center';
const sizeLabel = document.createElement('span');
sizeLabel.textContent = '大小:';
sizeLabel.style.marginRight = '8px';
const btnMinus = document.createElement('button');
btnMinus.textContent = '-';
Object.assign(btnMinus.style, {
width: '36px',
height: '36px',
fontSize: '22px',
marginRight: '8px'
});
const sizeInput = document.createElement('input');
Object.assign(sizeInput, { type: 'text', value: size });
sizeInput.style.width = '60px';
sizeInput.style.textAlign = 'center';
sizeInput.style.marginRight = '8px';
const btnPlus = document.createElement('button');
btnPlus.textContent = '+';
Object.assign(btnPlus.style, {
width: '36px',
height: '36px',
fontSize: '22px'
});
sizeContainer.append(sizeLabel, btnMinus, sizeInput, btnPlus);
panel.append(fontLabel, fontSel, sizeContainer);
function updateAll() {
font = fontSel.value;
if (sizeInput.value.trim() === "") return;
let num = parseInt(sizeInput.value, 10);
if (num <= 0) num = 18;
size = num;
sizeInput.value = size;
localStorage.setItem('wenku8_font', font);
localStorage.setItem('wenku8_fontsize', size);
updateStyle();
}
fontSel.addEventListener('change', updateAll);
sizeInput.addEventListener('input', updateAll);
btnMinus.addEventListener('click', () => {
size = Math.max(1, size - 2);
sizeInput.value = size;
updateAll();
});
btnPlus.addEventListener('click', () => {
size = size + 2;
sizeInput.value = size;
updateAll();
});
mainBtn.addEventListener('click', () => {
panel.style.display = panel.style.display === 'none' ? 'block' : 'none';
});
document.body.append(mainBtn, panel);
document.addEventListener('mousedown', (e) => {
if (!panel.contains(e.target) && e.target !== mainBtn) {
panel.style.display = 'none';
}
});
})();