您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Hi, Element Plus Component Dashboard
当前为
- // ==UserScript==
- // @name Hi, Element Plus Component Dashboard🚀
- // @namespace https://github.com/xianghongai/Tampermonkey-UserScript
- // @version 1.0.2
- // @description Hi, Element Plus Component Dashboard
- // @author Nicholas Hsiang
- // @match *://element-plus.org/*
- // @icon https://element-plus.org/images/element-plus-logo-small.svg
- // @grant GM_addStyle
- // @grant GM_info
- // @run-at document-end
- // @grant unsafeWindow
- // @license MIT
- // ==/UserScript==
- (function () {
- 'use strict';
- console.log(GM_info.script.name);
- const logoSelector = '.logo-container img.logo';
- const menuSelector = '.sidebar';
- let wrapperEl = null;
- main();
- /**
- * Main function to execute when the script is loaded.
- */
- function main() {
- ready(() => {
- poll(menuSelector, handler, 500);
- });
- }
- /**
- * Toggle the target element.
- */
- function handler() {
- const closeSpan = document.createElement('span');
- closeSpan.className = 'x-toggle';
- closeSpan.innerHTML = icon();
- closeSpan.addEventListener('click', (event) => {
- // hold shift key to reset
- if (event.shiftKey) {
- wrapperEl.removeAttribute('id');
- wrapperEl.style.display = 'block';
- return;
- }
- // init
- if (!wrapperEl || wrapperEl.id !== 'x-menu-wrapper') {
- wrapperEl = dashboard();
- // add component item click event listener
- componentItemClickEventListener(wrapperEl, '.link');
- handleComponentPageClass(wrapperEl);
- return;
- }
- wrapperEl.style.display = wrapperEl.style.display === 'none' ? 'grid' : 'none';
- });
- document.body.appendChild(closeSpan);
- navClickEventListener(wrapperEl);
- }
- /**
- * Click the navbar menu element, handle the component page.
- * @param {Element} wrapperEl - The wrapper element
- */
- function navClickEventListener(wrapperEl) {
- const navSelector = '.navbar-menu';
- const navEl = document.querySelector(navSelector);
- if (navEl) {
- navEl.addEventListener('click', () => {
- handleComponentPageClass(wrapperEl);
- });
- }
- }
- function handleComponentPageClass(wrapperEl) {
- if (window.location.href.includes('component')) {
- wrapperEl.classList.add('x-dashboard-component');
- } else {
- wrapperEl.classList.remove('x-dashboard-component');
- }
- }
- /**
- * Click the target element.
- * @param {Element} currentElement - The target element
- * @param {string} selector - The selector of the target element
- */
- function componentItemClickEventListener(currentElement, selector) {
- currentElement.addEventListener('click', (event) => {
- if (matches(event.target, selector)) {
- currentElement.style.display = 'none';
- }
- });
- }
- /**
- * Create the dashboard element.
- * @returns {Element} - The dashboard element
- */
- function dashboard() {
- wrapperEl = document.querySelector(menuSelector);
- wrapperEl.setAttribute('id', 'x-menu-wrapper');
- // 获取所有 sidebar-group 元素(排除第一个)
- const groupSelector = '.sidebar-group:not(:first-child)';
- const groupEl = Array.from(wrapperEl.querySelectorAll(groupSelector));
- const lengths = [];
- groupEl.forEach((item) => {
- const itemSelector = 'a.link';
- const itemEl = Array.from(item.querySelectorAll(itemSelector));
- const length = itemEl.length;
- const titleSelector = '.sidebar-group__title';
- const titleEl = item.querySelector(titleSelector);
- const title = titleEl.textContent;
- titleEl.textContent = `${title} (${length})`;
- lengths.push(length);
- });
- const sum = lengths.reduce((acc, curr) => acc + curr, 0);
- const sumText = `🚀 共有组件 ${sum} 个`;
- const logoEl = document.querySelector(logoSelector);
- if (logoEl) {
- logoEl.title = sumText;
- }
- console.log(sumText);
- return wrapperEl;
- }
- /**
- * Execute a function when the document is ready.
- * @param {function} eventHandler - Function to execute when the document is ready
- */
- function ready(eventHandler) {
- if (document.readyState !== 'loading') {
- eventHandler();
- } else {
- document.addEventListener('DOMContentLoaded', eventHandler);
- }
- }
- /**
- * Wait for an element to be found on the page using polling.
- * @param {string} selector - CSS selector for the element to wait for
- * @param {function} callback - Function to execute when the element is found
- * @param {number} maxAttempts - Maximum number of attempts to find the element
- * @returns {number} intervalId - ID of the interval used to poll for the element
- */
- function poll(selector, callback, maxAttempts = 10) {
- let attempts = 0;
- const intervalId = setInterval(() => {
- attempts++;
- const element = document.querySelector(selector);
- if (element) {
- clearInterval(intervalId);
- if (callback && typeof callback === 'function') {
- callback(element);
- }
- } else if (attempts >= maxAttempts) {
- clearInterval(intervalId);
- console.log(`Element ${selector} not found after ${maxAttempts} attempts.`);
- }
- }, 1000);
- return intervalId;
- }
- /**
- * Check if an element matches a CSS selector.
- * @param {Element} currentElement - The element to check for a match
- * @param {string} selector - CSS selector to match against
- * @returns {boolean} - True if the selector matches, false otherwise
- */
- function matches(currentElement, selector) {
- while (currentElement !== null && currentElement !== document.body) {
- if (currentElement.matches(selector)) {
- return true;
- }
- currentElement = currentElement.parentElement;
- }
- // 检查 body 元素
- return document.body.matches(selector);
- }
- function icon() {
- return `<?xml version="1.0" encoding="UTF-8"?><svg width="18" height="18" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M18 4H6C4.89543 4 4 4.89543 4 6V18C4 19.1046 4.89543 20 6 20H18C19.1046 20 20 19.1046 20 18V6C20 4.89543 19.1046 4 18 4Z" fill="#2F88FF" stroke="#333" stroke-width="3" stroke-linejoin="round"/><path d="M18 28H6C4.89543 28 4 28.8954 4 30V42C4 43.1046 4.89543 44 6 44H18C19.1046 44 20 43.1046 20 42V30C20 28.8954 19.1046 28 18 28Z" fill="#2F88FF" stroke="#333" stroke-width="3" stroke-linejoin="round"/><path d="M42 4H30C28.8954 4 28 4.89543 28 6V18C28 19.1046 28.8954 20 30 20H42C43.1046 20 44 19.1046 44 18V6C44 4.89543 43.1046 4 42 4Z" fill="#2F88FF" stroke="#333" stroke-width="3" stroke-linejoin="round"/><path d="M28 28H44" stroke="#333" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M36 36H44" stroke="#333" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M28 44H44" stroke="#333" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
- }
- const style = `
- .x-toggle {
- position: fixed;
- top: 18px;
- right: 16px;
- z-index: 99999;
- cursor: pointer;
- opacity: 0.8;
- transition: opacity 0.3s ease-in-out;
- }
- .x-toggle:hover {
- opacity: 1;
- }
- #x-menu-wrapper {
- position: fixed !important;
- top: 55px !important;
- right: 0 !important;
- bottom: 0 !important;
- left: 0 !important;
- z-index: 9999 !important;
- max-width: 100% !important;
- width: 100% !important;
- max-height: calc(100vh - 55px) !important;
- padding: 0 !important;
- background: #fff !important;
- /* border-block-start: 1px solid rgba(5, 5, 5, 0.06) !important; */
- }
- #x-menu-wrapper .sidebar-groups {
- display: grid !important;
- grid-auto-flow: column !important;
- grid-auto-columns: 220px !important;
- max-width: max-content !important;
- gap: 16px !important;
- overflow: auto;
- margin-inline: auto !important;
- border-inline-end: none !important;
- }
- #x-menu-wrapper .doc-content-side {
- display: none !important;
- }
- #x-menu-wrapper .sidebar-group__title {
- font-size: 12px !important;
- margin-block-end: 4px !important;
- }
- #x-menu-wrapper.x-dashboard-component .sidebar-group:nth-child(1) {
- display: none !important;
- }
- #x-menu-wrapper .sidebar-group {
- padding-block-start: 16px !important;
- }
- #x-menu-wrapper .sidebar-group .link {
- padding: 6px 0 !important;
- }
- #x-menu-wrapper .sidebar-group .link-text {
- font-size: 12px !important;
- font-weight: 400 !important;
- }
- `;
- GM_addStyle(style);
- })();