PTT預設字型使用微軟正黑體

PTT字型用微軟正黑體,設定選單改為深色風格

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         PTT預設字型使用微軟正黑體
// @namespace    https://github.com/livinginpurple
// @version      2025.11.27.21
// @description  PTT字型用微軟正黑體,設定選單改為深色風格
// @license      WTFPL
// @author       livinginpurple
// @match        *://*.ptt.cc/*
// @match        *://disp.cc/b/*
// @match        *://disp.cc/m/*
// @match        *://disp.cc/ptt/*
// @match        *://www.pttweb.cc/*
// @run-at       document-end
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// ==/UserScript==

(() => {
    'use strict';
    console.log(`${GM_info.script.name} is loading.`);

    // 修改處:將選單樣式改為深色系 (Dark Mode)
    GM_addStyle(`
        #font-setting-container {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            padding: 20px;
            border-radius: 10px;
            background-color: #2b2b2b; /* 背景改深灰 */
            border: 1px solid #444;     /* 增加深色邊框 */
            box-shadow: 0px 4px 15px rgba(0, 0, 0, 0.7); /* 加深陰影 */
            z-index: 9999;
            color: #e0e0e0;             /* 文字改淺灰 */
            width: 300px;
            box-sizing: border-box;
            font-family: "Microsoft JhengHei", sans-serif; /* 確保選單本身字型清晰 */
        }
        #font-setting-container label {
            display: block; 
            margin-bottom: 8px; 
            font-size: 14px; 
            font-weight: bold;
            color: #fff; /* 標籤文字全白 */
        }
        #font-setting-container select {
            margin-bottom: 15px;
            width: 100%;
            height: 35px;
            border: 1px solid #555;
            border-radius: 5px;
            background-color: #3d3d3d; /* 下拉選單背景深色 */
            font-size: 14px;
            color: #fff;               /* 下拉選單文字白色 */
            padding: 5px;
            box-sizing: border-box;
            outline: none;
        }
        #font-setting-container select:focus {
            border-color: #007bff;
        }
        #font-setting-container button {
            height: 32px; 
            border: none; 
            border-radius: 5px; 
            color: #fff; 
            font-size: 14px; 
            cursor: pointer;
            width: 48%;
            box-sizing: border-box;
            transition: background-color 0.2s;
        }
        #font-setting-container .btn-save {
            background-color: #007bff;
            margin-right: 4%;
        }
        #font-setting-container .btn-save:hover {
            background-color: #0056b3;
        }
        #font-setting-container .btn-cancel {
            background-color: #555; /* 取消按鈕改深灰 */
        }
        #font-setting-container .btn-cancel:hover {
            background-color: #444;
        }
    `);

    const fontSetting = 'fontSetting';
    const options = [
        { label: '微軟正黑體', value: 'Microsoft JhengHei' },
        { label: '微軟雅黑體', value: 'Microsoft YaHei' },
        { label: 'LINE Seed TW Regular', value: 'LINE Seed TW_OTF Regular' },
        { label: 'Noto Sans CJK TC Regular', value: 'Noto Sans CJK TC Regular' },
        { label: 'Noto Sans Mono CJK TC Regular', value: 'Noto Sans Mono CJK TC Regular' },
        { label: '更紗黑體 TC', value: 'Sarasa Gothic TC' },
        { label: '更紗等距黑體 TC', value: 'Sarasa Mono TC' },
        { label: 'Noto Sans TC', value: 'Noto Sans TC' },
        { label: 'Noto Serif TC', value: 'Noto Serif TC' },
        { label: 'MiSans', value: 'MiSans' },
        { label: 'MiSans TC', value: 'MiSans TC' }
    ];

    const savedFont = GM_getValue(fontSetting, options[0].value);
    changeFont(savedFont); // 預設使用儲存的選項
    GM_registerMenuCommand('字型設定', openOptionsMenu);
    let container;

    function openOptionsMenu() {
        // 防止重複開啟
        if (document.getElementById('font-setting-container')) return;

        const originalFont = GM_getValue(fontSetting, options[0].value);
        container = createContainer();

        const label = createLabel('請選擇字型:');
        const select = createSelect(options);
        select.value = originalFont; // 設定下拉選單的值

        select.addEventListener('change', () => {
            changeFont(select.value);
        });

        const saveButton = createButton('儲存', () => {
            const selectedOption = container.querySelector('select').value;
            GM_setValue(fontSetting, selectedOption);
            container.remove();
        }, 'btn-save');

        const cancelButton = createButton('取消', () => {
            changeFont(originalFont);
            container.remove();
        }, 'btn-cancel');

        appendChildren(container, [label, select, saveButton, cancelButton]);
        document.body.appendChild(container);
    }

    function changeFont(font) {
        switch (location.hostname) {
            case 'www.pttweb.cc':
                document.querySelectorAll('.application').forEach(el => {
                    el.style.fontFamily = font;
                });
                break;
            case 'disp.cc':
                document.body.style.fontFamily = font;
                break;
            default:
                document.querySelectorAll('.bbs-content').forEach(el => {
                    el.style.fontFamily = font;
                });
                break;
        }
        console.log(`字型已切換成:${font}`);
    }

    function createContainer() {
        const container = document.createElement('div');
        container.id = 'font-setting-container';
        return container;
    }

    function createLabel(text) {
        const label = document.createElement('label');
        label.textContent = text;
        return label;
    }

    function createSelect(options) {
        const select = document.createElement('select');

        options.forEach(option => {
            const optionElement = document.createElement('option');
            Object.assign(optionElement, {
                value: option.value,
                textContent: option.label,
            });
            select.appendChild(optionElement);
        });

        return select;
    }

    function createButton(text, clickHandler, className) {
        const button = document.createElement('button');
        button.textContent = text;
        button.className = className;
        button.addEventListener('click', clickHandler);
        return button;
    }

    function appendChildren(parent, children) {
        children.forEach(child => parent.appendChild(child));
    }

    console.log(`${GM_info.script.name} is running.`);
})();