Vant 组件菜单 (2x)

快速预览 Vant 组件菜单面板/Van component dashboard

当前为 2020-05-02 提交的版本,查看 最新版本

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