Vant 组件看板 (2.x)

更方便的查看 Vant 组件

  1. // ==UserScript==
  2. // @name:zh-CN Vant 组件看板 (2.x)
  3. // @name Vant Components Dashboard (2.x)
  4. // @namespace https://github.com/xianghongai/Tampermonkey-UserScript
  5. // @version 0.0.2
  6. // @description:zh-CN 更方便的查看 Vant 组件
  7. // @description Better view for Vant Component
  8. // @author Nicholas Hsiang / 山茶树和葡萄树
  9. // @icon https://xinlu.ink/favicon.ico
  10. // @match https://youzan.github.io/vant/*
  11. // @match https://vant-contrib.gitee.io/vant/*
  12. // @grant none
  13. // ==/UserScript==
  14. (function () {
  15. "use strict";
  16.  
  17. const titleText = "Vant";
  18.  
  19. const gridSelector = ".van-doc-nav__group+.van-doc-nav__group";
  20. const girdIsList = true; // 如果提取的是一个 Node 数组
  21. // 基于 gridSelector 做 querySelectorAll,添加 hs-dashboard__column 样式名
  22. const columnSelector = ".van-doc-nav__group";
  23. // 基于 gridSelector 做 querySelectorAll,添加 hs-dashboard__item-title 样式名
  24. const columnTitleSelector = ".van-doc-nav__title";
  25. // 基于 gridSelector 做 querySelectorAll,添加 hs-dashboard__list 样式名
  26. const menuListSelector = ".van-doc-nav__group";
  27. // 基于 gridSelector 做 querySelectorAll,添加 hs-dashboard__item 样式名,这一层尽量在 li 标签上
  28. const menuItemSelector = ".van-doc-nav__item";
  29.  
  30. const menuItemActionSelector = ".van-doc-nav__item .active";
  31.  
  32. const helpEnable = true;
  33. const helpSelector = "#api";
  34.  
  35. // 使用本扩展的样式风格,将会替换原站点的菜单风格
  36. const customStyleEnable = true; // Dark & Light
  37. const cloneNodeEnable = true; // 保留原 DOM 节点?
  38.  
  39. function initialExtraStyle() {
  40. return `
  41. .hs-dashboard__list .hs-dashboard__title { margin-left: 2px; }
  42. .hs-dashboard__toggle { top: 5px; right: 20px; }
  43. .hs-dashboard__grid { justify-content: space-around; /* center | space-evenly | space-between */ }
  44. `;
  45. }
  46.  
  47. /* ------------------------------------------------------------------------- */
  48.  
  49. let wrapperEle = null;
  50. let themeSwitchEle = null;
  51. let themeSwitchForm = null;
  52.  
  53. const bodyContainer = document.querySelector("body");
  54.  
  55. function initialDashboard() {
  56. initialToggle();
  57. initialStyle(initialExtraStyle);
  58. initialMenu(cloneNodeEnable);
  59. initialHelp();
  60. handleEvent();
  61. handleTheme(true);
  62. }
  63.  
  64. let interval = null;
  65.  
  66. function ready() {
  67. const originEle = document.querySelector(gridSelector);
  68.  
  69. if (originEle) {
  70. clearInterval(interval);
  71. // Dashboard
  72. initialDashboard();
  73. // Other
  74. }
  75. }
  76.  
  77. interval = setInterval(ready, 1000);
  78.  
  79. // #region MENU
  80. /** 生成 Menu */
  81. function initialMenu(clone) {
  82. // Wrapper
  83. wrapperEle = document.createElement("section");
  84. wrapperEle.classList.add("hs-dashboard__wrapper", "hs-hide");
  85.  
  86. if (customStyleEnable) {
  87. wrapperEle.setAttribute("id", "hs-dashboard");
  88. }
  89.  
  90. // Header
  91. const headerEle = document.createElement("header");
  92. headerEle.classList.add("hs-dashboard__header");
  93.  
  94. // Title → Header
  95. const titleEle = document.createElement("h1");
  96. titleEle.classList.add("hs-dashboard__title");
  97. titleEle.innerText = titleText || "";
  98. headerEle.appendChild(titleEle);
  99.  
  100. // Theme → Header
  101. if (customStyleEnable) {
  102. const themeEle = document.createElement("div");
  103. themeEle.classList.add("hs-theme-switch");
  104. themeEle.innerHTML = initialThemeTpl();
  105. headerEle.appendChild(themeEle);
  106. }
  107.  
  108. // Menu
  109. const containerEle = document.createElement("div");
  110. containerEle.classList.add("hs-dashboard__container");
  111.  
  112. // 1. 先从页面上获取 DOM 生成 gird
  113. let gridEle = null;
  114. let nodeTemp = null;
  115.  
  116. if (girdIsList) {
  117. gridEle = document.createElement("div");
  118. const gridListEle = document.querySelectorAll(gridSelector);
  119. gridListEle &&
  120. gridListEle.forEach((element) => {
  121. nodeTemp = clone ? element.cloneNode(true) : element;
  122. gridEle.appendChild(nodeTemp);
  123. });
  124. } else {
  125. nodeTemp = document.querySelector(gridSelector);
  126. gridEle = clone ? nodeTemp.cloneNode(true) : nodeTemp;
  127. gridEle && nodeTemp.removeAttribute("id");
  128. }
  129.  
  130. gridEle.classList.add("hs-dashboard__grid"); // 追加新的样式
  131.  
  132. // Menu → Container
  133. containerEle.appendChild(gridEle);
  134.  
  135. // 2. 内部元素追加新的样式
  136. // 2.1 column
  137. const columnEle = containerEle.querySelectorAll(columnSelector);
  138. columnEle.forEach((element) => {
  139. element.classList.add("hs-dashboard__column");
  140. });
  141.  
  142. // 2.2 title
  143. const columnTitleEle = containerEle.querySelectorAll(columnTitleSelector);
  144. columnTitleEle.forEach((element) => {
  145. element.classList.add("hs-dashboard__title");
  146. });
  147.  
  148. // 2.3 menu list
  149. const menuListEle = containerEle.querySelectorAll(menuListSelector);
  150. menuListEle.forEach((element) => {
  151. element.classList.add("hs-dashboard__list");
  152. });
  153.  
  154. // 2.4 menu item
  155. const menuItemEle = containerEle.querySelectorAll(menuItemSelector);
  156. menuItemEle.forEach((element) => {
  157. element.classList.add("hs-dashboard__item");
  158. });
  159.  
  160. // 2.5 menu item action
  161. const actionEle = containerEle.querySelector(menuItemActionSelector);
  162. if (actionEle) {
  163. const menuItemTemp = getParents(actionEle, menuItemSelector);
  164. menuItemTemp.classList.add("hs-active");
  165. }
  166.  
  167. // header,container → wrapper
  168. wrapperEle.appendChild(headerEle);
  169. wrapperEle.appendChild(containerEle);
  170.  
  171. // wrapper → body
  172. bodyContainer.appendChild(wrapperEle);
  173. }
  174. // #endregion MENU
  175.  
  176. // #region Event
  177. /** 注册事件 */
  178. function handleEvent() {
  179. if (!wrapperEle) {
  180. wrapperEle = document.querySelector(".hs-dashboard__wrapper");
  181. }
  182.  
  183. if (!themeSwitchEle) {
  184. themeSwitchEle = document.querySelector(".hs-theme-switch");
  185. }
  186.  
  187. if (!themeSwitchForm) {
  188. themeSwitchForm = document.querySelector(".hs-theme-switch__form-control");
  189. }
  190.  
  191.  
  192. const toggleMenuBtn = document.querySelector('.hs-dashboard__toggle-menu');
  193. const toggleHelpBtn = document.querySelector('.hs-dashboard__toggle-help');
  194.  
  195. function handler(event) {
  196. const targetEle = event.target;
  197.  
  198. const itemEle = getParents(targetEle, ".hs-dashboard__item");
  199.  
  200. const isItem = hasClass(targetEle, "hs-dashboard__item");
  201.  
  202. const isItemWrapper = getParents(targetEle, ".hs-dashboard__column") && getParents(targetEle, ".hs-dashboard__list");
  203.  
  204. const isToggle = getParents(targetEle, ".hs-dashboard__toggle-menu") || hasClass(targetEle, "hs-dashboard__toggle-menu");
  205.  
  206. const isHelp = getParents(targetEle, ".hs-dashboard__toggle-help") || hasClass(targetEle, "hs-dashboard__toggle-help");
  207.  
  208. const isTheme = getParents(targetEle, ".hs-theme-switch") || hasClass(targetEle, "hs-theme-switch");
  209.  
  210. if (itemEle || isItem || isItemWrapper) {
  211. window.setTimeout(() => {
  212. clearStyle(wrapperEle);
  213. }, 300);
  214.  
  215. handleItemClick(itemEle, isItem, targetEle);
  216. } else if (isToggle) {
  217. wrapperEle.classList.toggle("hs-hide");
  218. bodyContainer.classList.toggle("hs-body-overflow_hide");
  219. } else if (isHelp) {
  220. clearStyle(wrapperEle);
  221. handleHelp();
  222. } else if (isTheme) {
  223. handleTheme();
  224. }
  225. }
  226.  
  227. bodyContainer.addEventListener("click", handler);
  228.  
  229. document.addEventListener('keydown', function (event) {
  230. if (event.key === 'Tab' || event.code === 'Tab') {
  231. event.preventDefault();
  232. event.stopPropagation();
  233. toggleMenuBtn.click();
  234. }
  235. // else if (event.key === 'Escape' || event.code === 'Escape') {
  236. // toggleMenuBtn.click();
  237. // }
  238. else if (event.key === 'F1' || event.code === 'F1') {
  239. event.preventDefault();
  240. event.stopPropagation();
  241. toggleHelpBtn.click();
  242. }
  243. });
  244. }
  245.  
  246. /** 导航点击 */
  247. function handleItemClick(itemEle, isItem, targetEle) {
  248. let itemTemp = null;
  249.  
  250. if (itemEle) {
  251. itemTemp = itemEle;
  252. } else if (isItem) {
  253. itemTemp = targetEle;
  254. }
  255.  
  256. if (itemTemp) {
  257. const items = wrapperEle.querySelectorAll(".hs-dashboard__item");
  258. items.forEach((element) => {
  259. element.classList.remove("hs-active");
  260. element.querySelector("a").classList.remove("active");
  261. });
  262. itemTemp.classList.add("hs-active");
  263. }
  264. }
  265.  
  266. /** 退出预览 */
  267. function clearStyle(wrapperEle) {
  268. wrapperEle.classList.add("hs-hide");
  269. bodyContainer.classList.remove("hs-body-overflow_hide");
  270. }
  271. // #endregion Event
  272.  
  273. // #region HELP
  274. /** 是否启用‘页面滚动至指定位置’ */
  275. function initialHelp() {
  276. if (!helpEnable) {
  277. const ele = document.querySelector(".hs-dashboard__toggle-help");
  278. ele.classList.add("hs-hide");
  279. }
  280. }
  281.  
  282. /** 页面滚动至指定位置 */
  283. function handleHelp() {
  284. if (!helpSelector) {
  285. return false;
  286. }
  287.  
  288. const helpEle = document.querySelector(helpSelector);
  289.  
  290. if (!helpEle) {
  291. return false;
  292. }
  293.  
  294. const top = helpEle.getBoundingClientRect().top + window.pageYOffset;
  295.  
  296. window.scrollTo({
  297. top,
  298. behavior: "smooth",
  299. });
  300. }
  301. // #endregion HELP
  302.  
  303. // #region STYLE
  304. /** 添加样式 */
  305. function initialStyle(param) {
  306. let tpl = initialStyleTpl();
  307. const headEle = document.head || document.getElementsByTagName("head")[0];
  308. const styleEle = document.createElement("style");
  309.  
  310. let str = null;
  311.  
  312. if (typeof param === "function") {
  313. str = param();
  314. } else if (typeof param === "string") {
  315. str = param;
  316. }
  317.  
  318. if (typeof str === "string") {
  319. tpl += str;
  320. }
  321.  
  322. styleEle.type = "text/css";
  323.  
  324. if (styleEle.styleSheet) {
  325. styleEle.styleSheet.cssText = tpl;
  326. } else {
  327. styleEle.appendChild(document.createTextNode(tpl));
  328. }
  329.  
  330. headEle.appendChild(styleEle);
  331. }
  332.  
  333. /** 样式表 */
  334. function initialStyleTpl() {
  335. return `
  336.  
  337. :root {
  338. --item-height: 36px;
  339. --hs-font-size-base: 15px;
  340. --hs-global-spacing: 1rem;
  341. --hs-color-primary: #1890ff;
  342. --hs-spacing-horizontal: var(--hs-global-spacing);
  343. }
  344. .hs-hide {
  345. display: none !important;
  346. }
  347.  
  348. .hs-body-overflow_hide {
  349. height: 100% !important;
  350. overflow: hidden !important;
  351. }
  352.  
  353. /* #region toggle */
  354. .hs-dashboard__toggle {
  355. position: fixed;
  356. z-index: 99999;
  357. top: 15px;
  358. right: 5px;
  359. }
  360.  
  361. .hs-dashboard__toggle-item {
  362. position: relative;
  363. width: 28px;
  364. height: 28px;
  365. margin-top: 10px;
  366. margin-bottom: 10px;
  367. overflow: hidden;
  368. line-height: 1 !important;
  369. border-radius: 50%;
  370. border: 1px solid #ccc;
  371. text-align: center;
  372. color: #555;
  373. background-color: #fff;
  374. cursor: pointer;
  375. transition: all 0.2s;
  376. }
  377.  
  378. .hs-dashboard__toggle-item:hover {
  379. border-color: #aaa;
  380. color: #111;
  381. }
  382.  
  383. .hs-dashboard__toggle-icon svg{
  384. position: absolute;
  385. top: 50%;
  386. left: 50%;
  387. z-index: 9;
  388. transform: translate(-50%, -50%);
  389. font-style: normal !important;
  390. }
  391. /* #endregion toggle */
  392.  
  393. /* #region wrapper */
  394. .hs-dashboard__wrapper {
  395. position: fixed;
  396. top: 0;
  397. right: 0;
  398. bottom: 0;
  399. left: 0;
  400. z-index: 99998;
  401. overflow-y: auto;
  402. background-color: #fff;
  403. font-size: var(--hs-font-size-base);
  404. }
  405.  
  406. .hs-dashboard__wrapper::-webkit-scrollbar {
  407. width: 8px;
  408. height: 6px;
  409. background: rgba(0, 0, 0, 0.1);
  410. }
  411.  
  412. .hs-dashboard__wrapper::-webkit-scrollbar-thumb {
  413. background: rgba(0, 0, 0, 0.3);
  414. }
  415.  
  416. .hs-dashboard__wrapper::-webkit-scrollbar-track {
  417. background: rgba(0, 0, 0, 0.1);
  418. }
  419. /* #endregion wrapper */
  420.  
  421. .hs-dashboard__header {
  422. position: relative;
  423. padding-top: 10px;
  424. text-align: center;
  425. }
  426.  
  427. .hs-dashboard__header .hs-dashboard__title {
  428. margin: 0;
  429. padding-top: 10px;
  430. padding-bottom: 10px;
  431. font-size: 1em;
  432. font-weight: normal;
  433. }
  434.  
  435. /* #region theme */
  436. .hs-theme-switch {
  437. display: flex;
  438. touch-action: pan-x;
  439. position: relative;
  440. background-color: #fff;
  441. border: 0;
  442. margin: 0;
  443. padding: 0;
  444. user-select: none;
  445. -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
  446. -webkit-tap-highlight-color: transparent;
  447. cursor: pointer;
  448. }
  449.  
  450. .hs-theme-switch {
  451. width: 50px;
  452. height: 24px;
  453. padding: 0;
  454. border-radius: 30px;
  455. background-color: #4d4d4d;
  456. transition: all 0.2s ease;
  457. }
  458.  
  459. .hs-dashboard__header .hs-theme-switch {
  460. position: absolute;
  461. top: 10px;
  462. left: 10px;
  463. }
  464.  
  465. .hs-theme-switch__style {
  466. position: relative;
  467. width: 24px;
  468. height: 24px;
  469. line-height: 1;
  470. font-size: 20px;
  471. text-align: center;
  472. }
  473.  
  474. .hs-theme-switch__icon svg {
  475. position: absolute;
  476. top: 50%;
  477. left: 50%;
  478. transform: translate(-50%, -50%);
  479. }
  480.  
  481. .hs-theme-switch__thumb {
  482. position: absolute;
  483. top: 1px;
  484. left: 1px;
  485. width: 22px;
  486. height: 22px;
  487. border: 1px solid #ff7938;
  488. border-radius: 50%;
  489. background-color: #fafafa;
  490. box-sizing: border-box;
  491. transition: all 0.25s ease;
  492. }
  493.  
  494. .hs-theme-switch_checked .hs-theme-switch__thumb {
  495. left: 27px;
  496. border-color: #4d4d4d;
  497. }
  498.  
  499. .hs-toggle-screenreader-only {
  500. border: 0;
  501. clip: rect(0 0 0 0);
  502. height: 1px;
  503. margin: -1px;
  504. overflow: hidden;
  505. padding: 0;
  506. position: absolute;
  507. width: 1px;
  508. }
  509. /* #endregion theme */
  510.  
  511. /* #region grid */
  512. .hs-dashboard__grid {
  513. display: flex;
  514. justify-content: space-evenly;
  515. margin: 0;
  516. padding: 0;
  517. list-style: none;
  518. }
  519.  
  520. .hs-dashboard__column {
  521. padding-right: 10px;
  522. padding-left: 10px;
  523. }
  524.  
  525. .hs-dashboard__column a {
  526. display: block;
  527. padding-left: 20px !important;
  528. padding-right: 40px !important;
  529. text-decoration: none;
  530. }
  531.  
  532. .hs-dashboard__container ul {
  533. padding: 0;
  534. }
  535.  
  536. .hs-dashboard__container li {
  537. padding-left: 0 !important;
  538. list-style: none;
  539. }
  540.  
  541. .hs-dashboard__column .hs-dashboard__title {
  542. display: block;
  543. padding-left: var(--hs-spacing-horizontal) !important;
  544. padding-right: calc(var(--hs-spacing-horizontal) * 2) !important;
  545. text-align: left;
  546. margin-top: 10px !important;
  547. }
  548.  
  549. .hs-dashboard__column .hs-dashboard__list {
  550. margin-top: 10px !important;
  551. }
  552.  
  553. .hs-dashboard__column .hs-dashboard__list .hs-dashboard__item {
  554. margin: 0 !important;
  555. padding-left: 0 !important;
  556. padding-right: 0 !important;
  557. height: var(--item-height);
  558. line-height: var(--item-height);
  559. }
  560. /* #endregion grid */
  561.  
  562. /* #region custom */
  563. #hs-dashboard.hs-dashboard__wrapper {
  564. transition: all 0.2s ease;
  565. }
  566.  
  567. #hs-dashboard .hs-dashboard__column .hs-dashboard__title {
  568. font-size: 14px;
  569. line-height: 1.5715;
  570. color: rgba(0, 0, 0, 0.45);
  571. }
  572.  
  573. #hs-dashboard a {
  574. overflow: hidden;
  575. white-space: nowrap;
  576. font-size: 14px;
  577. text-overflow: ellipsis;
  578. text-decoration: none;
  579. color: rgba(0, 0, 0, 0.85);
  580. transition: color 0.3s ease;
  581. }
  582.  
  583. #hs-dashboard a:hover {
  584. color: var(--hs-color-primary);
  585. text-decoration: none;
  586. outline: 0;
  587. }
  588.  
  589. /* light */
  590. #hs-dashboard.hs-dashboard__wrapper_light {
  591. color: #161616;
  592. background-color: #fff;
  593. }
  594.  
  595. /* dark */
  596. #hs-dashboard.hs-dashboard__wrapper_dark {
  597. color: #fff;
  598. background-color: #161616;
  599. }
  600.  
  601. #hs-dashboard.hs-dashboard__wrapper_dark .hs-dashboard__title {
  602. font-weight: bold;
  603. color: #fff;
  604. }
  605.  
  606. #hs-dashboard.hs-dashboard__wrapper_dark a {
  607. color: #fff;
  608. }
  609.  
  610. #hs-dashboard.hs-dashboard__wrapper_dark a:hover {
  611. color: var(--hs-color-primary);
  612. }
  613.  
  614. #hs-dashboard .hs-dashboard__item.active,
  615. #hs-dashboard .hs-dashboard__item.active a,
  616. #hs-dashboard .hs-dashboard__item .active,
  617. #hs-dashboard .hs-dashboard__item.hs-active,
  618. #hs-dashboard .hs-dashboard__item.hs-active a {
  619. color: var(--hs-color-primary);
  620. }
  621.  
  622. #hs-dashboard .hs-dashboard__item.hs-active {
  623. background-color: #e6f7ff;
  624. }
  625.  
  626. #hs-dashboard .hs-dashboard__item {
  627. position: relative;
  628. }
  629.  
  630. #hs-dashboard .hs-dashboard__item::after {
  631. content: ' ';
  632. position: absolute;
  633. top: 0;
  634. right: 0;
  635. bottom: 0;
  636. border-right: 3px solid var(--hs-color-primary);
  637. transform: scaleY(0.0001);
  638. transition: transform 0.15s cubic-bezier(0.215, 0.61, 0.355, 1),
  639. opacity 0.15s cubic-bezier(0.215, 0.61, 0.355, 1),
  640. -webkit-transform 0.15s cubic-bezier(0.215, 0.61, 0.355, 1);
  641. opacity: 0;
  642. }
  643.  
  644. #hs-dashboard .hs-dashboard__item.hs-active::after {
  645. transform: scaleY(1);
  646. opacity: 1;
  647. transition: transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
  648. opacity 0.15s cubic-bezier(0.645, 0.045, 0.355, 1),
  649. -webkit-transform 0.15s cubic-bezier(0.645, 0.045, 0.355, 1);
  650. }
  651. /* #endregion custom */
  652.  
  653. `;
  654. }
  655. // #endregion STYLE
  656.  
  657. // #region TOGGLE
  658. /** 生成 Dashboard 开关 */
  659. function initialToggle() {
  660. const tpl = initialToggleTpl();
  661. const ele = document.createElement("section");
  662. // ele.className = 'hs-dashboard__toggle';
  663. // ele.setAttribute("class", "hs-dashboard__toggle");
  664. ele.classList.add("hs-dashboard__toggle");
  665. ele.innerHTML = tpl;
  666.  
  667. // toggle → body
  668. bodyContainer.appendChild(ele);
  669. }
  670. /** Dashboard 开关 DOM */
  671. function initialToggleTpl() {
  672. return `
  673. <!-- menu -->
  674. <div class="hs-dashboard__toggle-item hs-dashboard__toggle-menu">
  675. <i class="hs-dashboard__toggle-icon">
  676. <svg
  677. viewBox="64 64 896 896"
  678. focusable="false"
  679. data-icon="appstore"
  680. width="1em"
  681. height="1em"
  682. fill="currentColor"
  683. aria-hidden="true"
  684. >
  685. <path
  686. 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"
  687. ></path>
  688. </svg>
  689. </i>
  690. </div>
  691. <!-- api -->
  692. <div class="hs-dashboard__toggle-item hs-dashboard__toggle-help">
  693. <i class="hs-dashboard__toggle-icon">
  694. <svg
  695. viewBox="64 64 896 896"
  696. focusable="false"
  697. class=""
  698. data-icon="bulb"
  699. width="1em"
  700. height="1em"
  701. fill="currentColor"
  702. aria-hidden="true"
  703. >
  704. <path
  705. 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"
  706. ></path>
  707. </svg>
  708. </i>
  709. </div>
  710. `;
  711. }
  712. // #endregion TOGGLE
  713.  
  714. // #region THEME
  715. function handleTheme(isInit) {
  716. if (isInit) {
  717. const theme = localStorage.getItem("hs_dashboard_theme");
  718.  
  719. if (theme && theme === "dark") {
  720. themeSwitchForm.checked = true;
  721. } else {
  722. themeSwitchForm.checked = false;
  723. }
  724. } else {
  725. themeSwitchForm.click();
  726. }
  727.  
  728. const checked = themeSwitchForm.checked;
  729.  
  730. if (checked) {
  731. localStorage.setItem("hs_dashboard_theme", "dark");
  732. wrapperEle.classList.add("hs-dashboard__wrapper_dark");
  733. wrapperEle.classList.remove("hs-dashboard__wrapper_light");
  734. themeSwitchEle.classList.add("hs-theme-switch_checked");
  735. } else {
  736. localStorage.setItem("hs_dashboard_theme", "light");
  737. wrapperEle.classList.add("hs-dashboard__wrapper_light");
  738. wrapperEle.classList.remove("hs-dashboard__wrapper_dark");
  739. themeSwitchEle.classList.remove("hs-theme-switch_checked");
  740. }
  741. }
  742.  
  743. function initialThemeTpl() {
  744. return `
  745. <input type="checkbox" class="hs-toggle-screenreader-only hs-theme-switch__form-control" title="Dark mode" />
  746. <div class="hs-theme-switch__style hs-theme-switch__style_dark">
  747. <i class="hs-theme-switch__icon">
  748. <svg
  749. t="1588325093630"
  750. class="icon"
  751. viewBox="0 0 1024 1024"
  752. version="1.1"
  753. xmlns="http://www.w3.org/2000/svg"
  754. p-id="11008"
  755. width="1em"
  756. height="1em"
  757. >
  758. <path
  759. 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"
  760. fill="#F7FF53"
  761. p-id="11009"
  762. ></path>
  763. <path
  764. 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"
  765. fill="#303133"
  766. p-id="11010"
  767. ></path>
  768. <path
  769. 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"
  770. fill="#303133"
  771. p-id="11011"
  772. ></path>
  773. <path
  774. 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"
  775. fill="#FF2929"
  776. p-id="11012"
  777. ></path>
  778. <path
  779. 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"
  780. fill="#FFA450"
  781. p-id="11013"
  782. ></path>
  783. <path
  784. 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"
  785. fill="#FF7938"
  786. p-id="11014"
  787. ></path>
  788. </svg>
  789. </i>
  790. </div>
  791. <div class="hs-theme-switch__style hs-theme-switch__style_light">
  792. <i class="hs-theme-switch__icon">
  793. <svg
  794. t="1588324703446"
  795. class="icon"
  796. viewBox="0 0 1024 1024"
  797. version="1.1"
  798. xmlns="http://www.w3.org/2000/svg"
  799. p-id="6232"
  800. width="1em"
  801. height="1em"
  802. >
  803. <path
  804. 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"
  805. fill="#FF7938"
  806. p-id="6233"
  807. ></path>
  808. <path
  809. 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"
  810. fill="#F7FF53"
  811. p-id="6234"
  812. ></path>
  813. <path
  814. 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"
  815. fill="#303133"
  816. p-id="6235"
  817. ></path>
  818. <path
  819. 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"
  820. fill="#303133"
  821. p-id="6236"
  822. ></path>
  823. <path
  824. d="M442.78 582.02s17.31 48.31 69.22 48.31 69.22-48.31 69.22-48.31H442.78z"
  825. fill="#FF2929"
  826. p-id="6237"
  827. ></path>
  828. </svg>
  829. </i>
  830. </div>
  831. <div class="hs-theme-switch__thumb"></div>
  832. `;
  833. }
  834. // #endregion THEME
  835.  
  836. // #region COMMON
  837. function hasClass(el, className) {
  838. if (el.classList) {
  839. return el.classList.contains(className);
  840. } else {
  841. return !!el.className.match(new RegExp("(\\s|^)" + className + "(\\s|$)"));
  842. }
  843. }
  844.  
  845. function getParents(elem, selector) {
  846. // Element.matches() polyfill
  847. if (!Element.prototype.matches) {
  848. Element.prototype.matches =
  849. Element.prototype.matchesSelector ||
  850. Element.prototype.mozMatchesSelector ||
  851. Element.prototype.msMatchesSelector ||
  852. Element.prototype.oMatchesSelector ||
  853. Element.prototype.webkitMatchesSelector ||
  854. function (s) {
  855. var matches = (this.document || this.ownerDocument).querySelectorAll(s),
  856. i = matches.length;
  857. while (--i >= 0 && matches.item(i) !== this) { }
  858. return i > -1;
  859. };
  860. }
  861.  
  862. // Get the closest matching element
  863. for (; elem && elem !== document; elem = elem.parentNode) {
  864. if (elem.matches(selector)) return elem;
  865. }
  866. return null;
  867. }
  868. // #endregion
  869. })();