Vue API 看板 (^2.0.0)

更方便的查看 Vue API

  1. // ==UserScript==
  2. // @name:zh-CN Vue API 看板 (^2.0.0)
  3. // @name Vue API Dashboard (^2.0.0)
  4. // @namespace https://github.com/xianghongai/Vue-API-Dashboard
  5. // @version 0.0.3
  6. // @description:zh-CN 更方便的查看 Vue API
  7. // @description Better view for Vue API
  8. // @author Nicholas Hsiang / 山茶树和葡萄树
  9. // @icon https://xinlu.ink/favicon.ico
  10. // @match https://v2.cn.vuejs.org/v2/api/*
  11. // @match https://v2.vuejs.org/v2/api/*
  12. // @grant none
  13. // ==/UserScript==
  14. (() => {
  15. "use strict";
  16.  
  17. const titleText = "Vue API Dashboard";
  18.  
  19. const gridSelector = ".sidebar-inner .menu-root";
  20. const girdIsList = false; // 如果提取的是一个 Node 数组
  21. const columnSelector = ".menu-root>li";
  22. const columnTitleSelector = ".menu-root>li>a.section-link";
  23. const menuListSelector = ".menu-sub";
  24. const menuItemSelector = ".menu-sub li";
  25.  
  26. const menuItemActionSelector = null;
  27.  
  28. const helpEnable = false;
  29. const helpSelector = "";
  30.  
  31. // 使用本扩展的样式风格,将会替换原站点的菜单风格
  32. const customStyleEnable = true; // Dark & Light
  33. const cloneNodeEnable = true; // 保留原 DOM 节点?
  34.  
  35. const compactColumnEnable = true; // 紧凑模式,将会合并一些少的列
  36. const compactColumnLimit = 13; // 多列数据组合上限
  37.  
  38. function initialExtraStyle() {
  39. return `
  40. .hs-dashboard__toggle {
  41. top: 5px;
  42. }
  43. `;
  44. }
  45.  
  46. /* ------------------------------------------------------------------------- */
  47.  
  48. let wrapperEle = null;
  49. let themeSwitchEle = null;
  50. let themeSwitchForm = null;
  51.  
  52. const bodyContainer = document.querySelector("body");
  53.  
  54. function initialDashboard() {
  55. initialToggle();
  56. initialStyle(initialExtraStyle);
  57. initialMenu(cloneNodeEnable);
  58. initialHelp();
  59. handleEvent();
  60. handleTheme(true);
  61. }
  62.  
  63. let interval = null;
  64.  
  65. function ready() {
  66. const originEle = document.querySelector(gridSelector);
  67.  
  68. if (originEle) {
  69. clearInterval(interval);
  70. // Dashboard
  71. initialDashboard();
  72. // Other
  73. }
  74. }
  75.  
  76. interval = setInterval(ready, 1000);
  77.  
  78. // #region MENU
  79. /** 生成 Menu */
  80. function initialMenu(clone) {
  81. // Wrapper
  82. wrapperEle = document.createElement("section");
  83. wrapperEle.classList.add("hs-dashboard__wrapper", "hs-hide");
  84.  
  85. if (customStyleEnable) {
  86. wrapperEle.setAttribute("id", "hs-dashboard");
  87. }
  88.  
  89. // Header
  90. const headerEle = document.createElement("header");
  91. headerEle.classList.add("hs-dashboard__header");
  92.  
  93. // Title → Header
  94. const titleEle = document.createElement("h1");
  95. titleEle.classList.add("hs-dashboard__title");
  96. titleEle.innerText = titleText || "";
  97. headerEle.appendChild(titleEle);
  98.  
  99. // Theme → Header
  100. if (customStyleEnable) {
  101. const themeEle = document.createElement("div");
  102. themeEle.classList.add("hs-theme-switch");
  103. themeEle.innerHTML = initialThemeTpl();
  104. headerEle.appendChild(themeEle);
  105. }
  106.  
  107. // Menu
  108. const containerEle = document.createElement("div");
  109. containerEle.classList.add("hs-dashboard__container");
  110.  
  111. // 1. 先从页面上获取 DOM 生成 gird
  112. let gridEle = null;
  113. let nodeTemp = null;
  114.  
  115. if (girdIsList) {
  116. gridEle = document.createElement("div");
  117. const gridListEle = document.querySelectorAll(gridSelector);
  118. gridListEle &&
  119. gridListEle.forEach((element) => {
  120. nodeTemp = clone ? element.cloneNode(true) : element;
  121. gridEle.appendChild(nodeTemp);
  122. });
  123. } else {
  124. nodeTemp = document.querySelector(gridSelector);
  125. gridEle = clone ? nodeTemp.cloneNode(true) : nodeTemp;
  126. gridEle && nodeTemp.removeAttribute("id");
  127. }
  128.  
  129. gridEle.classList.add("hs-dashboard__grid"); // 追加新的样式
  130.  
  131. // Menu → Container
  132. containerEle.appendChild(gridEle);
  133.  
  134. // 2. 内部元素追加新的样式
  135. // 2.1 column
  136. const columnEle = containerEle.querySelectorAll(columnSelector);
  137. columnEle.forEach((element) => {
  138. element.classList.add("hs-dashboard__column");
  139. });
  140.  
  141. // 2.2 title
  142. const columnTitleEle = containerEle.querySelectorAll(columnTitleSelector);
  143. columnTitleEle.forEach((element) => {
  144. element.classList.add("hs-dashboard__title");
  145. });
  146.  
  147. // 2.3 menu list
  148. const menuListEle = containerEle.querySelectorAll(menuListSelector);
  149. menuListEle.forEach((element) => {
  150. element.classList.add("hs-dashboard__list");
  151. });
  152.  
  153. // 2.4 menu item
  154. const menuItemEle = containerEle.querySelectorAll(menuItemSelector);
  155. menuItemEle.forEach((element) => {
  156. element.classList.add("hs-dashboard__item");
  157. });
  158.  
  159. // 2.5 menu item action
  160. if (menuItemActionSelector) {
  161. const actionEle = containerEle.querySelector(menuItemActionSelector);
  162. const menuItemTemp = getParents(actionEle, menuItemSelector);
  163. menuItemTemp.classList.add("hs-active");
  164. }
  165.  
  166. if (compactColumnEnable) {
  167. const { columns, layout } = compactColumn(containerEle, compactColumnLimit);
  168.  
  169. const ul = document.createElement("ul");
  170. ul.classList.add("hs-dashboard__grid");
  171.  
  172. Array.isArray(layout) &&
  173. layout.forEach((item) => {
  174. const li = document.createElement("li");
  175. li.classList.add("hs-dashboard__column");
  176.  
  177. if (Array.isArray(item)) {
  178. item.forEach((index) => {
  179. const columnItem = columns[index];
  180. const title = columnItem.querySelector(".hs-dashboard__title");
  181. const list = columnItem.querySelector(".hs-dashboard__list");
  182. title && li.appendChild(title);
  183. list && li.appendChild(list);
  184. });
  185. } else {
  186. const columnItem = columns[item];
  187. const title = columnItem.querySelector(".hs-dashboard__title");
  188. const list = columnItem.querySelector(".hs-dashboard__list");
  189. title && li.appendChild(title);
  190. list && li.appendChild(list);
  191. }
  192.  
  193. ul.appendChild(li);
  194. });
  195.  
  196. containerEle.removeChild(gridEle);
  197. containerEle.appendChild(ul);
  198. }
  199.  
  200. // header,container → wrapper
  201. wrapperEle.appendChild(headerEle);
  202. wrapperEle.appendChild(containerEle);
  203.  
  204. // wrapper → body
  205. bodyContainer.appendChild(wrapperEle);
  206. }
  207.  
  208. function compactColumn(containerEle, limit) {
  209. // 只能按列去查,有的列里面是没有 list 的
  210. let columns = containerEle.querySelectorAll(".hs-dashboard__column");
  211. let columnCount = []; // 相邻的数相加不超过指定值,就合并到一个新数组,将组成新的 column
  212. let layout = []; // 计算出来的新的数据布局方式
  213.  
  214. if (columns && columns.length) {
  215. columns.forEach((element) => {
  216. const listItem = element.querySelectorAll(".hs-dashboard__item");
  217. columnCount.push(listItem.length);
  218. });
  219.  
  220. /**
  221. * DESIGN NOTES
  222. *
  223. * 相邻的数相加
  224. *
  225. * 1. 将相邻的坐标存放在 arr
  226. * 2. 计算 arr 中坐标的数据量是否超过指定值
  227. * 3. 没超过,继续往 arr 推坐标
  228. * 4. 原先没超过,新的一进来就超过了,说明原先的已经到了阈值,原先的可以合并了推到布局中,但新的要记录下来,参与下一轮计算
  229. * 5. 下一个本身已经超过了阈值,看原先是否有参与计算的,然后各自推到布局中
  230. */
  231.  
  232. limit = limit || 12;
  233.  
  234. let arr = []; // 待合并的对象
  235. let acc = 0; // 累加判断是否临界
  236. const length = columnCount.length; // 是否到最后
  237.  
  238. columnCount.forEach((item, index) => {
  239. // 1. 新的值临界
  240. if (item > limit) {
  241. // 原先的是一个待合并的集合,还是只是一个单独的值
  242. if (arr.length > 1) {
  243. layout.push(arr);
  244. } else if (arr.length === 1) {
  245. layout.push(arr[0]);
  246. }
  247.  
  248. layout.push(index);
  249.  
  250. arr = [];
  251. acc = 0;
  252. } else {
  253. // 计算总的数据量
  254. acc += item;
  255.  
  256. // 总数据量临界
  257. if (acc > limit) {
  258. if (arr.length) {
  259. if (arr.length > 1) {
  260. layout.push(arr);
  261. } else {
  262. layout.push(arr[0]);
  263. }
  264. }
  265.  
  266. // 新的值参与下一次计算
  267. arr = [index];
  268. acc = item;
  269. } else {
  270. // 新的值没有临界
  271. arr.push(index);
  272. }
  273. }
  274.  
  275. if (index === length - 1 && arr.length) {
  276. layout.push(arr);
  277. }
  278. });
  279. }
  280.  
  281. return { columns, layout };
  282. }
  283. // #endregion MENU
  284.  
  285. // #region Event
  286. /** 注册(不可用)事件 */
  287. function handleEvent() {
  288. if (!wrapperEle) {
  289. wrapperEle = document.querySelector(".hs-dashboard__wrapper");
  290. }
  291.  
  292. if (!themeSwitchEle) {
  293. themeSwitchEle = document.querySelector(".hs-theme-switch");
  294. }
  295.  
  296. if (!themeSwitchForm) {
  297. themeSwitchForm = document.querySelector(".hs-theme-switch__form-control");
  298. }
  299.  
  300. bodyContainer.addEventListener("click", (event) => {
  301. const targetEle = event.target;
  302.  
  303. const itemEle = getParents(targetEle, ".hs-dashboard__item");
  304.  
  305. const isItem = hasClass(targetEle, "hs-dashboard__item");
  306.  
  307. const isItemWrapper = getParents(targetEle, ".hs-dashboard__column") && getParents(targetEle, ".hs-dashboard__list");
  308.  
  309. const isToggle = getParents(targetEle, ".hs-dashboard__toggle-menu") || hasClass(targetEle, "hs-dashboard__toggle-menu");
  310.  
  311. const isHelp = getParents(targetEle, ".hs-dashboard__toggle-help") || hasClass(targetEle, "hs-dashboard__toggle-help");
  312.  
  313. const isTheme = getParents(targetEle, ".hs-theme-switch") || hasClass(targetEle, "hs-theme-switch");
  314.  
  315. if (itemEle || isItem || isItemWrapper) {
  316. window.setTimeout(() => {
  317. clearStyle(wrapperEle);
  318. }, 300);
  319.  
  320. handleItemClick(itemEle, isItem, targetEle);
  321. } else if (isToggle) {
  322. wrapperEle.classList.toggle("hs-hide");
  323. bodyContainer.classList.toggle("hs-body-overflow_hide");
  324. } else if (isHelp) {
  325. clearStyle(wrapperEle);
  326. handleHelp();
  327. } else if (isTheme) {
  328. handleTheme();
  329. }
  330. });
  331. }
  332.  
  333. /** 导航点击 */
  334. function handleItemClick(itemEle, isItem, targetEle) {
  335. let itemTemp = null;
  336.  
  337. if (itemEle) {
  338. itemTemp = itemEle;
  339. } else if (isItem) {
  340. itemTemp = targetEle;
  341. }
  342.  
  343. if (itemTemp) {
  344. const items = wrapperEle.querySelectorAll(".hs-dashboard__item");
  345. items.forEach((element) => {
  346. element.classList.remove("hs-active");
  347. element.querySelector("a").classList.remove("active");
  348. });
  349. itemTemp.classList.add("hs-active");
  350. }
  351. }
  352.  
  353. /** 退出预览 */
  354. function clearStyle(wrapperEle) {
  355. wrapperEle.classList.add("hs-hide");
  356. bodyContainer.classList.remove("hs-body-overflow_hide");
  357. }
  358. // #endregion Event
  359.  
  360. // #region HELP
  361. /** 是否启用‘页面滚动至指定位置’ */
  362. function initialHelp() {
  363. if (!helpEnable) {
  364. const ele = document.querySelector(".hs-dashboard__toggle-help");
  365. ele.classList.add("hs-hide");
  366. }
  367. }
  368.  
  369. /** 页面滚动至指定位置 */
  370. function handleHelp() {
  371. if (!helpSelector) {
  372. return false;
  373. }
  374.  
  375. const helpEle = document.querySelector(helpSelector);
  376. const top = helpEle.getBoundingClientRect().top + window.pageYOffset;
  377.  
  378. window.scrollTo({
  379. top,
  380. behavior: "smooth",
  381. });
  382. }
  383. // #endregion HELP
  384.  
  385. // #region STYLE
  386. /** 添加样式 */
  387. function initialStyle(param) {
  388. let tpl = initialStyleTpl();
  389. const headEle = document.head || document.getElementsByTagName("head")[0];
  390. const styleEle = document.createElement("style");
  391.  
  392. let str = null;
  393.  
  394. if (typeof param === "function") {
  395. str = param();
  396. } else if (typeof param === "string") {
  397. str = param;
  398. }
  399.  
  400. if (typeof str === "string") {
  401. tpl += str;
  402. }
  403.  
  404. styleEle.type = "text/css";
  405.  
  406. if (styleEle.styleSheet) {
  407. styleEle.styleSheet.cssText = tpl;
  408. } else {
  409. styleEle.appendChild(document.createTextNode(tpl));
  410. }
  411.  
  412. headEle.appendChild(styleEle);
  413. }
  414.  
  415. /** 样式表 */
  416. function initialStyleTpl() {
  417. return `
  418.  
  419. :root {
  420. --item-height: 36px;
  421. --hs-font-size-base: 15px;
  422. --hs-global-spacing: 1rem;
  423. --hs-color-primary: #1890ff;
  424. --hs-spacing-horizontal: var(--hs-global-spacing);
  425.  
  426. --hs-color-white: #fff;
  427. --hs-color-black: #000;
  428. --hs-color-gray-0: var(--hs-color-white);
  429. --hs-color-gray-100: #f5f6f7;
  430. --hs-color-gray-200: #ebedf0;
  431. --hs-color-gray-300: #dadde1;
  432. --hs-color-gray-400: #ccd0d5;
  433. --hs-color-gray-500: #bec3c9;
  434. --hs-color-gray-600: #8d949e;
  435. --hs-color-gray-700: #606770;
  436. --hs-color-gray-800: #444950;
  437. --hs-color-gray-900: #1c1e21;
  438. --hs-color-gray-1000: var(--hs-color-black);
  439. --hs-color-emphasis-0: var(--hs-color-gray-0);
  440. --hs-color-emphasis-100: var(--hs-color-gray-100);
  441. --hs-color-emphasis-200: var(--hs-color-gray-200);
  442. --hs-color-emphasis-300: var(--hs-color-gray-300);
  443. --hs-color-emphasis-400: var(--hs-color-gray-400);
  444. --hs-color-emphasis-500: var(--hs-color-gray-500);
  445. --hs-color-emphasis-600: var(--hs-color-gray-600);
  446. --hs-color-emphasis-700: var(--hs-color-gray-700);
  447. --hs-color-emphasis-800: var(--hs-color-gray-800);
  448. --hs-color-emphasis-900: var(--hs-color-gray-900);
  449. --hs-color-emphasis-1000: var(--hs-color-gray-1000);
  450. }
  451. .hs-hide {
  452. display: none !important;
  453. }
  454.  
  455. .hs-body-overflow_hide {
  456. height: 100% !important;
  457. overflow: hidden !important;
  458. }
  459.  
  460. /* #region toggle */
  461. .hs-dashboard__toggle {
  462. position: fixed;
  463. z-index: 99999;
  464. top: 15px;
  465. right: 5px;
  466. }
  467.  
  468. .hs-dashboard__toggle-item {
  469. position: relative;
  470. width: 28px;
  471. height: 28px;
  472. margin-top: 10px;
  473. margin-bottom: 10px;
  474. overflow: hidden;
  475. line-height: 1 !important;
  476. border-radius: 50%;
  477. border: 1px solid #ccc;
  478. text-align: center;
  479. color: #555;
  480. background-color: #fff;
  481. cursor: pointer;
  482. transition: all 0.2s;
  483. }
  484.  
  485. .hs-dashboard__toggle-item:hover {
  486. border-color: #aaa;
  487. color: #111;
  488. }
  489.  
  490. .hs-dashboard__toggle-icon svg{
  491. position: absolute;
  492. top: 50%;
  493. left: 50%;
  494. z-index: 9;
  495. transform: translate(-50%, -50%);
  496. font-style: normal !important;
  497. }
  498. /* #endregion toggle */
  499.  
  500. /* #region wrapper */
  501. .hs-dashboard__wrapper {
  502. position: fixed;
  503. top: 0;
  504. right: 0;
  505. bottom: 0;
  506. left: 0;
  507. z-index: 99998;
  508. overflow-y: auto;
  509. background-color: #fff;
  510. font-size: var(--hs-font-size-base);
  511. }
  512.  
  513. .hs-dashboard__wrapper::-webkit-scrollbar {
  514. width: 8px;
  515. height: 6px;
  516. background: rgba(0, 0, 0, 0.1);
  517. }
  518.  
  519. .hs-dashboard__wrapper::-webkit-scrollbar-thumb {
  520. background: rgba(0, 0, 0, 0.3);
  521. }
  522.  
  523. .hs-dashboard__wrapper::-webkit-scrollbar-track {
  524. background: rgba(0, 0, 0, 0.1);
  525. }
  526. /* #endregion wrapper */
  527.  
  528. .hs-dashboard__header {
  529. position: relative;
  530. padding-top: 10px;
  531. text-align: center;
  532. }
  533.  
  534. .hs-dashboard__header .hs-dashboard__title {
  535. margin: 0;
  536. padding-top: 10px;
  537. padding-bottom: 10px;
  538. font-size: 1em;
  539. font-weight: normal;
  540. }
  541.  
  542. /* #region theme */
  543. .hs-theme-switch {
  544. display: flex;
  545. touch-action: pan-x;
  546. position: relative;
  547. background-color: #fff;
  548. border: 0;
  549. margin: 0;
  550. padding: 0;
  551. user-select: none;
  552. -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  553. -webkit-tap-highlight-color: transparent;
  554. cursor: pointer;
  555. }
  556.  
  557. .hs-theme-switch {
  558. width: 50px;
  559. height: 24px;
  560. padding: 0;
  561. border-radius: 30px;
  562. background-color: #4d4d4d;
  563. transition: all 0.2s ease;
  564. }
  565.  
  566. .hs-dashboard__header .hs-theme-switch {
  567. position: absolute;
  568. top: 10px;
  569. left: 10px;
  570. }
  571.  
  572. .hs-theme-switch__style {
  573. position: relative;
  574. width: 24px;
  575. height: 24px;
  576. line-height: 1;
  577. font-size: 20px;
  578. text-align: center;
  579. }
  580.  
  581. .hs-theme-switch__icon svg {
  582. position: absolute;
  583. top: 50%;
  584. left: 50%;
  585. transform: translate(-50%, -50%);
  586. }
  587.  
  588. .hs-theme-switch__thumb {
  589. position: absolute;
  590. top: 1px;
  591. left: 1px;
  592. width: 22px;
  593. height: 22px;
  594. border: 1px solid #ff7938;
  595. border-radius: 50%;
  596. background-color: #fafafa;
  597. box-sizing: border-box;
  598. transition: all 0.25s ease;
  599. }
  600.  
  601. .hs-theme-switch_checked .hs-theme-switch__thumb {
  602. left: 27px;
  603. border-color: #4d4d4d;
  604. }
  605.  
  606. .hs-toggle-screenreader-only {
  607. border: 0;
  608. clip: rect(0 0 0 0);
  609. height: 1px;
  610. margin: -1px;
  611. overflow: hidden;
  612. padding: 0;
  613. position: absolute;
  614. width: 1px;
  615. }
  616. /* #endregion theme */
  617.  
  618. /* #region grid */
  619. .hs-dashboard__grid {
  620. display: flex;
  621. justify-content: space-around;
  622. margin: 0;
  623. padding: 0 40px;
  624. list-style: none;
  625. }
  626.  
  627. .hs-dashboard__column {
  628. padding-right: 10px;
  629. padding-left: 10px;
  630. }
  631.  
  632. .hs-dashboard__column a {
  633. display: block;
  634. padding-left: 20px !important;
  635. padding-right: 40px !important;
  636. text-decoration: none;
  637. }
  638.  
  639. .hs-dashboard__container ul:not(.hs-dashboard__grid) {
  640. padding: 0;
  641. }
  642.  
  643. .hs-dashboard__container li {
  644. padding-left: 0 !important;
  645. list-style: none;
  646. }
  647.  
  648. .hs-dashboard__column .hs-dashboard__title {
  649. display: block;
  650. padding-left: var(--hs-spacing-horizontal) !important;
  651. padding-right: calc(var(--hs-spacing-horizontal) * 2) !important;
  652. text-align: left;
  653. margin-top: 10px !important;
  654. }
  655.  
  656. .hs-dashboard__column .hs-dashboard__list {
  657. margin-top: 10px !important;
  658. }
  659.  
  660. .hs-dashboard__column .hs-dashboard__list+.hs-dashboard__title {
  661. margin-top: var(--hs-global-spacing);
  662. padding-top: var(--hs-global-spacing);
  663. }
  664.  
  665. .hs-dashboard__column .hs-dashboard__list .hs-dashboard__item {
  666. margin: 0 !important;
  667. padding-left: 0 !important;
  668. padding-right: 0 !important;
  669. height: var(--item-height);
  670. line-height: var(--item-height);
  671. }
  672. /* #endregion grid */
  673.  
  674. /* #region custom */
  675. #hs-dashboard.hs-dashboard__wrapper {
  676. transition: all 0.2s ease;
  677. }
  678.  
  679. #hs-dashboard .hs-dashboard__column .hs-dashboard__title {
  680. font-size: 14px;
  681. line-height: 1.5715;
  682. color: rgba(0, 0, 0, 0.45);
  683. }
  684.  
  685. #hs-dashboard a {
  686. overflow: hidden;
  687. white-space: nowrap;
  688. font-size: 14px;
  689. text-overflow: ellipsis;
  690. text-decoration: none;
  691. color: rgba(0, 0, 0, 0.85);
  692. transition: color 0.3s ease;
  693. }
  694.  
  695. #hs-dashboard a:hover {
  696. color: var(--hs-color-primary);
  697. text-decoration: none;
  698. outline: 0;
  699. }
  700.  
  701. /* light */
  702. #hs-dashboard.hs-dashboard__wrapper_light {
  703. color: #161616;
  704. background-color: #fff;
  705. }
  706.  
  707. #hs-dashboard.hs-dashboard__wrapper_light .hs-dashboard__list+.hs-dashboard__title {
  708. border-top: 1px solid var(--hs-color-gray-300);
  709. }
  710.  
  711. /* dark */
  712. #hs-dashboard.hs-dashboard__wrapper_dark {
  713. color: #fff;
  714. background-color: #161616;
  715. }
  716.  
  717. #hs-dashboard.hs-dashboard__wrapper_dark .hs-dashboard__list+.hs-dashboard__title {
  718. border-top: 1px solid var(--hs-color-gray-600);
  719. }
  720.  
  721. #hs-dashboard.hs-dashboard__wrapper_dark .hs-dashboard__title {
  722. font-weight: bold;
  723. color: #fff;
  724. }
  725.  
  726. #hs-dashboard.hs-dashboard__wrapper_dark a {
  727. color: #fff;
  728. }
  729.  
  730. #hs-dashboard.hs-dashboard__wrapper_dark a:hover {
  731. color: var(--hs-color-primary);
  732. }
  733.  
  734. #hs-dashboard .hs-dashboard__item.active,
  735. #hs-dashboard .hs-dashboard__item.active a,
  736. #hs-dashboard .hs-dashboard__item .active,
  737. #hs-dashboard .hs-dashboard__item.hs-active,
  738. #hs-dashboard .hs-dashboard__item.hs-active a {
  739. color: var(--hs-color-primary);
  740. }
  741.  
  742. #hs-dashboard .hs-dashboard__item.hs-active {
  743. background-color: #e6f7ff;
  744. }
  745.  
  746. #hs-dashboard .hs-dashboard__item {
  747. position: relative;
  748. }
  749.  
  750. #hs-dashboard .hs-dashboard__item::after {
  751. content: ' ';
  752. position: absolute;
  753. top: 0;
  754. right: 0;
  755. bottom: 0;
  756. border-right: 3px solid var(--hs-color-primary);
  757. transform: scaleY(0.0001);
  758. transition: transform 0.15s cubic-bezier(0.215, 0.61, 0.355, 1),
  759. opacity 0.15s cubic-bezier(0.215, 0.61, 0.355, 1),
  760. -webkit-transform 0.15s cubic-bezier(0.215, 0.61, 0.355, 1);
  761. opacity: 0;
  762. }
  763.  
  764. #hs-dashboard .hs-dashboard__item.hs-active::after {
  765. transform: scaleY(1);
  766. opacity: 1;
  767. transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
  768. opacity 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
  769. -webkit-transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1);
  770. }
  771. /* #endregion custom */
  772.  
  773. `;
  774. }
  775. // #endregion STYLE
  776.  
  777. // #region TOGGLE
  778. /** 生成 Dashboard 开关 */
  779. function initialToggle() {
  780. const tpl = initialToggleTpl();
  781. const ele = document.createElement("section");
  782. // ele.className = 'hs-dashboard__toggle';
  783. // ele.setAttribute("class", "hs-dashboard__toggle");
  784. ele.classList.add("hs-dashboard__toggle");
  785. ele.innerHTML = tpl;
  786.  
  787. // toggle → body
  788. bodyContainer.appendChild(ele);
  789. }
  790. /** Dashboard 开关 DOM */
  791. function initialToggleTpl() {
  792. return `
  793. <!-- menu -->
  794. <div class="hs-dashboard__toggle-item hs-dashboard__toggle-menu">
  795. <i class="hs-dashboard__toggle-icon">
  796. <svg
  797. viewBox="64 64 896 896"
  798. focusable="false"
  799. data-icon="appstore"
  800. width="1em"
  801. height="1em"
  802. fill="currentColor"
  803. aria-hidden="true"
  804. >
  805. <path
  806. d="M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"
  807. ></path>
  808. </svg>
  809. </i>
  810. </div>
  811. <!-- api -->
  812. <div class="hs-dashboard__toggle-item hs-dashboard__toggle-help">
  813. <i class="hs-dashboard__toggle-icon">
  814. <svg
  815. viewBox="64 64 896 896"
  816. focusable="false"
  817. class=""
  818. data-icon="bulb"
  819. width="1em"
  820. height="1em"
  821. fill="currentColor"
  822. aria-hidden="true"
  823. >
  824. <path
  825. d="M632 888H392c-4.4 0-8 3.6-8 8v32c0 17.7 14.3 32 32 32h192c17.7 0 32-14.3 32-32v-32c0-4.4-3.6-8-8-8zM512 64c-181.1 0-328 146.9-328 328 0 121.4 66 227.4 164 284.1V792c0 17.7 14.3 32 32 32h264c17.7 0 32-14.3 32-32V676.1c98-56.7 164-162.7 164-284.1 0-181.1-146.9-328-328-328zm127.9 549.8L604 634.6V752H420V634.6l-35.9-20.8C305.4 568.3 256 484.5 256 392c0-141.4 114.6-256 256-256s256 114.6 256 256c0 92.5-49.4 176.3-128.1 221.8z"
  826. ></path>
  827. </svg>
  828. </i>
  829. </div>
  830. `;
  831. }
  832. // #endregion TOGGLE
  833.  
  834. // #region THEME
  835. function handleTheme(isInit) {
  836. if (isInit) {
  837. const theme = localStorage.getItem("hs_dashboard_theme");
  838.  
  839. if (theme && theme === "dark") {
  840. themeSwitchForm.checked = true;
  841. } else {
  842. themeSwitchForm.checked = false;
  843. }
  844. } else {
  845. themeSwitchForm.click();
  846. }
  847.  
  848. const checked = themeSwitchForm.checked;
  849.  
  850. if (checked) {
  851. localStorage.setItem("hs_dashboard_theme", "dark");
  852. wrapperEle.classList.add("hs-dashboard__wrapper_dark");
  853. wrapperEle.classList.remove("hs-dashboard__wrapper_light");
  854. themeSwitchEle.classList.add("hs-theme-switch_checked");
  855. } else {
  856. localStorage.setItem("hs_dashboard_theme", "light");
  857. wrapperEle.classList.add("hs-dashboard__wrapper_light");
  858. wrapperEle.classList.remove("hs-dashboard__wrapper_dark");
  859. themeSwitchEle.classList.remove("hs-theme-switch_checked");
  860. }
  861. }
  862.  
  863. function initialThemeTpl() {
  864. return `
  865. <input type="checkbox" class="hs-toggle-screenreader-only hs-theme-switch__form-control" title="Dark mode" />
  866. <div class="hs-theme-switch__style hs-theme-switch__style_dark">
  867. <i class="hs-theme-switch__icon">
  868. <svg
  869. t="1588325093630"
  870. class="icon"
  871. viewBox="0 0 1024 1024"
  872. version="1.1"
  873. xmlns="http://www.w3.org/2000/svg"
  874. p-id="11008"
  875. width="1em"
  876. height="1em"
  877. >
  878. <path
  879. d="M483.555556 964.266667c-164.977778 0-315.733333-85.333333-398.222223-224.711111 19.911111 2.844444 39.822222 2.844444 56.888889 2.844444 275.911111 0 500.622222-224.711111 500.622222-500.622222 0-68.266667-14.222222-133.688889-39.822222-193.422222 201.955556 54.044444 347.022222 238.933333 347.022222 449.422222 0 256-210.488889 466.488889-466.488888 466.488889z"
  880. fill="#F7FF53"
  881. p-id="11009"
  882. ></path>
  883. <path
  884. d="M631.466667 73.955556c179.2 62.577778 301.511111 230.4 301.511111 423.822222 0 247.466667-201.955556 449.422222-449.422222 449.422222-147.911111 0-281.6-71.111111-364.088889-187.733333H142.222222c284.444444 0 517.688889-233.244444 517.688889-517.688889 0-56.888889-8.533333-113.777778-28.444444-167.822222M571.733333 22.755556C605.866667 88.177778 625.777778 162.133333 625.777778 241.777778c0 267.377778-216.177778 483.555556-483.555556 483.555555-31.288889 0-59.733333-2.844444-88.177778-8.533333 79.644444 156.444444 241.777778 264.533333 429.511112 264.533333 267.377778 0 483.555556-216.177778 483.555555-483.555555C967.111111 261.688889 796.444444 65.422222 571.733333 22.755556z"
  885. fill="#303133"
  886. p-id="11010"
  887. ></path>
  888. <path
  889. d="M787.911111 455.111111c-5.688889-2.844444-8.533333-8.533333-5.688889-14.222222 5.688889-17.066667-2.844444-42.666667-19.911111-48.355556-17.066667-5.688889-39.822222 8.533333-45.511111 22.755556-2.844444 5.688889-8.533333 8.533333-14.222222 5.688889-5.688889-2.844444-8.533333-8.533333-5.688889-14.222222 8.533333-25.6 42.666667-45.511111 73.955555-34.133334 28.444444 11.377778 39.822222 48.355556 31.288889 73.955556-2.844444 5.688889-8.533333 8.533333-14.222222 8.533333"
  890. fill="#303133"
  891. p-id="11011"
  892. ></path>
  893. <path
  894. d="M608.711111 620.088889c-14.222222 0-28.444444-2.844444-39.822222-11.377778-31.288889-22.755556-31.288889-65.422222-31.288889-68.266667 0-8.533333 8.533333-17.066667 17.066667-17.066666s17.066667 8.533333 17.066666 17.066666 2.844444 31.288889 17.066667 39.822223c11.377778 8.533333 25.6 8.533333 45.511111 0 8.533333-2.844444 19.911111 2.844444 22.755556 11.377777 2.844444 8.533333-2.844444 19.911111-11.377778 22.755556-14.222222 2.844444-25.6 5.688889-36.977778 5.688889zM571.733333 540.444444z"
  895. fill="#FF2929"
  896. p-id="11012"
  897. ></path>
  898. <path
  899. d="M810.666667 588.8c-5.688889 19.911111-36.977778 28.444444-68.266667 19.911111-31.288889-8.533333-54.044444-34.133333-48.355556-54.044444 5.688889-19.911111 36.977778-28.444444 68.266667-19.911111 34.133333 11.377778 54.044444 34.133333 48.355556 54.044444"
  900. fill="#FFA450"
  901. p-id="11013"
  902. ></path>
  903. <path
  904. d="M864.711111 270.222222c14.222222 42.666667 19.911111 91.022222 19.911111 136.533334 0 258.844444-213.333333 466.488889-477.866666 466.488888-96.711111 0-187.733333-28.444444-264.533334-76.8 82.488889 93.866667 204.8 156.444444 344.177778 156.444445C736.711111 952.888889 938.666667 756.622222 938.666667 512c0-88.177778-28.444444-173.511111-73.955556-241.777778z"
  905. fill="#FF7938"
  906. p-id="11014"
  907. ></path>
  908. </svg>
  909. </i>
  910. </div>
  911. <div class="hs-theme-switch__style hs-theme-switch__style_light">
  912. <i class="hs-theme-switch__icon">
  913. <svg
  914. t="1588324703446"
  915. class="icon"
  916. viewBox="0 0 1024 1024"
  917. version="1.1"
  918. xmlns="http://www.w3.org/2000/svg"
  919. p-id="6232"
  920. width="1em"
  921. height="1em"
  922. >
  923. <path
  924. d="M792.35 835.94l-128.09-30.32c-17.73-4.2-36.12 3.66-45.34 19.37l-66.64 113.52c-15.83 26.97-54.67 27.4-71.1 0.79l-69.14-112.02c-9.57-15.5-28.13-22.95-45.76-18.36l-127.39 33.15c-30.26 7.88-58.03-19.29-50.83-49.72l30.32-128.09c4.2-17.73-3.66-36.12-19.37-45.34L85.49 552.28c-26.97-15.83-27.4-54.67-0.79-71.1l112.02-69.14c15.5-9.57 22.95-28.13 18.36-45.76l-33.15-127.39c-7.88-30.26 19.29-58.03 49.72-50.83l128.09 30.32c17.73 4.2 36.12-3.66 45.34-19.37l66.64-113.52c15.83-26.97 54.67-27.4 71.1-0.79l69.14 112.02c9.57 15.5 28.13 22.95 45.76 18.36l127.39-33.15c30.26-7.88 58.03 19.29 50.83 49.72l-30.32 128.09c-4.2 17.73 3.66 36.12 19.37 45.34l113.52 66.64c26.97 15.83 27.4 54.67 0.79 71.1l-112.02 69.14c-15.5 9.57-22.95 28.13-18.36 45.76l33.15 127.39c7.88 30.26-19.29 58.03-49.72 50.83z"
  925. fill="#FF7938"
  926. p-id="6233"
  927. ></path>
  928. <path
  929. d="M512 512m-207.66 0a207.66 207.66 0 1 0 415.32 0 207.66 207.66 0 1 0-415.32 0Z"
  930. fill="#F7FF53"
  931. p-id="6234"
  932. ></path>
  933. <path
  934. d="M442.78 468.74m-25.96 0a25.96 25.96 0 1 0 51.92 0 25.96 25.96 0 1 0-51.92 0Z"
  935. fill="#303133"
  936. p-id="6235"
  937. ></path>
  938. <path
  939. d="M581.22 468.74m-25.96 0a25.96 25.96 0 1 0 51.92 0 25.96 25.96 0 1 0-51.92 0Z"
  940. fill="#303133"
  941. p-id="6236"
  942. ></path>
  943. <path
  944. d="M442.78 582.02s17.31 48.31 69.22 48.31 69.22-48.31 69.22-48.31H442.78z"
  945. fill="#FF2929"
  946. p-id="6237"
  947. ></path>
  948. </svg>
  949. </i>
  950. </div>
  951. <div class="hs-theme-switch__thumb"></div>
  952. `;
  953. }
  954. // #endregion THEME
  955.  
  956. // #region COMMON
  957. function hasClass(el, className) {
  958. if (el.classList) {
  959. return el.classList.contains(className);
  960. } else {
  961. return !!el.className.match(new RegExp("(\\s|^)" + className + "(\\s|$)"));
  962. }
  963. }
  964.  
  965. function getParents(elem, selector) {
  966. // Element.matches() polyfill
  967. if (!Element.prototype.matches) {
  968. Element.prototype.matches =
  969. Element.prototype.matchesSelector ||
  970. Element.prototype.mozMatchesSelector ||
  971. Element.prototype.msMatchesSelector ||
  972. Element.prototype.oMatchesSelector ||
  973. Element.prototype.webkitMatchesSelector ||
  974. function (s) {
  975. var matches = (this.document || this.ownerDocument).querySelectorAll(s),
  976. i = matches.length;
  977. while (--i >= 0 && matches.item(i) !== this) {}
  978. return i > -1;
  979. };
  980. }
  981.  
  982. // Get the closest matching element
  983. for (; elem && elem !== document; elem = elem.parentNode) {
  984. if (elem.matches(selector)) return elem;
  985. }
  986. return null;
  987. }
  988.  
  989. function queryDirectChildren(parent, selector) {
  990. const nodes = parent.querySelectorAll(selector);
  991. const filteredNodes = [].slice.call(nodes).filter((item) => item.parentNode.closest(selector) === parent.closest(selector));
  992. return filteredNodes;
  993. }
  994. // #endregion
  995. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址