您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
A Tampermonkey script to darken the AP Polytechnic student portal interface.
// ==UserScript== // @name AP Poly Dark Mode // @icon https://github.com/Tori0833/AP-Poly-Dark-Mode/blob/main/resources/icon.png?raw=true // @namespace https://github.com/Tori0833/AP-Poly-Dark-Mode // @version 1.1.0 // @author tori.toriko (discord) & Claude.ai // @match https://ap.poly.edu.vn/* // @match https://feid.fpt.edu.vn/* // @license MIT // @run-at document-start // @description A Tampermonkey script to darken the AP Polytechnic student portal interface. // ==/UserScript== (function() { 'use strict'; // Inject CSS immediately to prevent flash const darkModeCSS = ` /* === ANTI-FLASH PROTECTION === */ html { background-color: #121212 !important; color: #eeeeee !important; } body { background-color: #121212 !important; color: #eeeeee !important; transition: none !important; } /* Prevent any white flash during page transitions */ * { background-color: inherit !important; color: inherit !important; } /* Override any inline styles that might cause flash */ [style*="background-color: white"], [style*="background-color: #fff"], [style*="background-color: #ffffff"], [style*="background: white"], [style*="background: #fff"], [style*="background: #ffffff"] { background-color: #121212 !important; } /* === GLOBAL DARK THEME === */ body.kt-page--loading.kt-header--fixed.kt-subheader--enabled.kt-aside--fixed { background-color: #121212 !important; } /* === HEADER DARK MODE === */ #kt_header, .kt-header { background-color: #1e1e1e !important; border-bottom: 1px solid #333 !important; } .kt-header__topbar { background-color: #1e1e1e !important; } .kt-header__topbar-item, .kt-header__topbar-user { color: #eeeeee !important; } .kt-header__topbar-item a, .kt-header__topbar-user a { color: #eeeeee !important; } /* === SIDEBAR DARK MODE === */ #kt_aside, .kt-aside { background-color: #1e1e1e !important; border-right: 1px solid #333 !important; } .kt-aside__brand { background-color: #1e1e1e !important; border-bottom: 1px solid #333 !important; } .kt-aside__menu-wrapper { background-color: #1e1e1e !important; } .kt-menu__nav { background-color: #1e1e1e !important; } .kt-menu__item { border-bottom: 1px solid #2c2c2c !important; } .kt-menu__link { color: #eeeeee !important; background-color: transparent !important; } .kt-menu__link:hover { background-color: #2c2c2c !important; color: #80b3ff !important; } .kt-menu__link-text { color: #eeeeee !important; } .kt-menu__link-icon { color: #eeeeee !important; } /* Active menu items */ .kt-menu__item--active .kt-menu__link { background-color: #2c2c2c !important; color: #80b3ff !important; } /* === MAIN CONTENT AREA === */ #kt_wrapper, .kt-wrapper { background-color: #121212 !important; } .kt-grid__item--fluid { background-color: #121212 !important; } .kt-content { background-color: #121212 !important; } /* === DROPDOWNS === */ .dropdown-menu { background-color: #2c2c2c !important; border: 1px solid #444 !important; color: #eeeeee !important; } .dropdown-item { color: #eeeeee !important; background-color: transparent !important; } .dropdown-item:hover, .dropdown-item:focus { background-color: #444 !important; color: #80b3ff !important; } /* === MODALS & POPUPS === */ .modal-content { background-color: #2c2c2c !important; border: 1px solid #444 !important; color: #eeeeee !important; } .modal-header { background-color: #2c2c2c !important; border-bottom: 1px solid #444 !important; } .modal-body { background-color: #2c2c2c !important; color: #eeeeee !important; } .modal-footer { background-color: #2c2c2c !important; border-top: 1px solid #444 !important; } /* === FORMS === */ .form-container { background-color: #2c2c2c !important; color: #eeeeee !important; } .form-group { color: #eeeeee !important; } .form-control { background-color: #1e1e1e !important; border: 1px solid #555 !important; color: #eeeeee !important; } .form-control:focus { background-color: #1e1e1e !important; border-color: #80b3ff !important; color: #eeeeee !important; box-shadow: 0 0 0 0.2rem rgba(128, 179, 255, 0.25) !important; } .form-control::placeholder { color: #999 !important; } .custom-control { color: #eeeeee !important; } .custom-control-input:checked ~ .custom-control-label::before { background-color: #80b3ff !important; border-color: #80b3ff !important; } /* === BUTTONS === */ .btn { border: 1px solid #555 !important; } .btn-primary { background-color: #0d6efd !important; border-color: #0d6efd !important; color: #ffffff !important; } .btn-secondary { background-color: #2c2c2c !important; border-color: #555 !important; color: #eeeeee !important; } .btn:hover { opacity: 0.8 !important; } /* === TABLES === */ .table { background-color: #2c2c2c !important; color: #eeeeee !important; } .table th, .table td { border-color: #444 !important; color: #eeeeee !important; } .table-striped tbody tr:nth-of-type(odd) { background-color: rgba(255, 255, 255, 0.05) !important; } /* === NOTIFICATIONS === */ .kt-notification { background-color: #2c2c2c !important; border: 1px solid #444 !important; color: #eeeeee !important; } .kt-user-card { background-color: #2c2c2c !important; color: #eeeeee !important; } /* === LINKS === */ a { color: #80b3ff !important; } a:hover { color: #66a3ff !important; } /* === CARDS & PANELS === */ .card { background-color: #2c2c2c !important; border: 1px solid #444 !important; color: #eeeeee !important; } .card-header { background-color: #1e1e1e !important; border-bottom: 1px solid #444 !important; color: #eeeeee !important; } .card-body { background-color: #2c2c2c !important; color: #eeeeee !important; } /* === SCROLLBARS === */ ::-webkit-scrollbar { width: 8px !important; height: 8px !important; } ::-webkit-scrollbar-track { background: #1e1e1e !important; } ::-webkit-scrollbar-thumb { background: #555 !important; border-radius: 4px !important; } ::-webkit-scrollbar-thumb:hover { background: #777 !important; } /* === TEXT INPUTS & SELECTS === */ input, textarea, select { background-color: #1e1e1e !important; border: 1px solid #555 !important; color: #eeeeee !important; } input:focus, textarea:focus, select:focus { border-color: #80b3ff !important; box-shadow: 0 0 0 0.2rem rgba(128, 179, 255, 0.25) !important; } /* === BREADCRUMBS === */ .breadcrumb { background-color: #2c2c2c !important; } .breadcrumb-item a { color: #80b3ff !important; } .breadcrumb-item.active { color: #eeeeee !important; } /* === ALERTS === */ .alert { border: 1px solid #444 !important; color: #eeeeee !important; } .alert-info { background-color: #1a4a6b !important; border-color: #1e5f7d !important; } .alert-warning { background-color: #6b4a1a !important; border-color: #7d5f1e !important; } .alert-danger { background-color: #6b1a1a !important; border-color: #7d1e1e !important; } .alert-success { background-color: #1a6b1a !important; border-color: #1e7d1e !important; } /* === NAVIGATION TABS === */ .nav-tabs { background-color: #1e1e1e !important; border-color: #333 !important; } .nav-link { background-color: transparent !important; color: #aaa !important; border-color: #444 !important; } .nav-link.active { background-color: #2a2a2a !important; color: #fff !important; border-color: #444 #444 #2a2a2a !important; } /* === GENERAL OVERRIDES === */ * { scrollbar-width: thin !important; scrollbar-color: #555 #1e1e1e !important; } /* Force dark backgrounds on common elements */ div, span, section, article, main, aside, header, footer, nav, .container, .container-fluid, .row, .col { background-color: transparent !important; } /* Ensure text remains readable */ p, h1, h2, h3, h4, h5, h6, span, div, td, th, li, label { color: #eeeeee !important; } /* === FEID FPT SPECIFIC STYLES === */ /* Login page */ .login-container, .login-form, .auth-container { background-color: #2c2c2c !important; color: #eeeeee !important; } /* Dashboard cards */ .dashboard-card, .info-card, .stats-card { background-color: #2c2c2c !important; border: 1px solid #444 !important; color: #eeeeee !important; } /* Course content */ .course-content, .lesson-content, .assignment-content { background-color: #121212 !important; color: #eeeeee !important; } /* Progress bars */ .progress { background-color: #1e1e1e !important; } .progress-bar { background-color: #80b3ff !important; } /* === PAGE TRANSITION PROTECTION === */ body { visibility: visible !important; opacity: 1 !important; } /* Prevent flash during AJAX loads */ .loading, .spinner, .loader { background-color: #121212 !important; } /* Common content wrappers */ .content-wrapper, .main-content, .page-content, .content-area { background-color: #121212 !important; color: #eeeeee !important; } `; // Create initial style element immediately const preloadStyle = document.createElement('style'); preloadStyle.type = 'text/css'; preloadStyle.id = 'darkmode-preload'; preloadStyle.innerHTML = ` html, body { background-color: #121212 !important; color: #eeeeee !important; transition: none !important; } * { background-color: inherit !important; color: inherit !important; } `; // Inject preload styles immediately if (document.documentElement) { document.documentElement.appendChild(preloadStyle); } // Function to inject full CSS function injectCSS() { // Remove any existing dark mode styles const existingStyle = document.getElementById('darkmode-ap-poly'); if (existingStyle) { existingStyle.remove(); } const style = document.createElement('style'); style.type = 'text/css'; style.id = 'darkmode-ap-poly'; style.innerHTML = darkModeCSS; // Inject into head with high priority if (document.head) { document.head.appendChild(style); } else { // Fallback: create head if it doesn't exist const head = document.createElement('head'); head.appendChild(style); document.documentElement.insertBefore(head, document.documentElement.firstChild); } console.log('AP Poly Dark Mode Enhanced: CSS injected successfully'); } // Function to handle page changes (for SPA navigation) function handlePageChange() { // Reapply styles immediately on page change setTimeout(injectCSS, 0); setTimeout(injectCSS, 50); setTimeout(injectCSS, 100); } // Inject CSS immediately injectCSS(); // Handle different document ready states if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', injectCSS); } else { // Document is already loaded setTimeout(injectCSS, 0); } // Also inject after short delays to override any late-loading styles setTimeout(injectCSS, 100); setTimeout(injectCSS, 300); setTimeout(injectCSS, 500); setTimeout(injectCSS, 1000); // Watch for URL changes (SPA navigation) let currentUrl = location.href; const urlObserver = new MutationObserver(() => { if (location.href !== currentUrl) { currentUrl = location.href; handlePageChange(); } }); // Watch for dynamically loaded content const contentObserver = new MutationObserver(function(mutations) { let shouldReapply = false; mutations.forEach(function(mutation) { if (mutation.addedNodes.length > 0) { mutation.addedNodes.forEach(function(node) { if (node.nodeType === 1) { // Element node // Check if new content needs immediate dark mode application if (node.classList && ( node.classList.contains('modal-content') || node.classList.contains('dropdown-menu') || node.classList.contains('form-control') || node.classList.contains('card') || node.classList.contains('content-wrapper') || node.classList.contains('main-content') )) { shouldReapply = true; } // Check for common white background inline styles if (node.style && ( node.style.backgroundColor === 'white' || node.style.backgroundColor === '#fff' || node.style.backgroundColor === '#ffffff' )) { node.style.backgroundColor = '#121212'; node.style.color = '#eeeeee'; } } }); } }); if (shouldReapply) { setTimeout(injectCSS, 10); } }); // Start observing when DOM is ready function startObserving() { if (document.body) { contentObserver.observe(document.body, { childList: true, subtree: true }); urlObserver.observe(document.body, { childList: true, subtree: true }); } } if (document.body) { startObserving(); } else { document.addEventListener('DOMContentLoaded', startObserving); } // Listen for history changes (back/forward buttons) window.addEventListener('popstate', handlePageChange); // Override common navigation methods const originalPushState = history.pushState; const originalReplaceState = history.replaceState; history.pushState = function(...args) { originalPushState.apply(this, args); handlePageChange(); }; history.replaceState = function(...args) { originalReplaceState.apply(this, args); handlePageChange(); }; // Handle hash changes window.addEventListener('hashchange', handlePageChange); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址