+layout.svelte 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. <script lang="ts">
  2. import { onMount } from 'svelte';
  3. import { isShowNavStore, isWideScreenStore } from '../../store';
  4. import Menu from '$lib/menu/Menu.svelte';
  5. import { page } from '$app/state';
  6. import type { MenuListChild } from '../../data/menuList.js';
  7. import { goto } from '$app/navigation';
  8. let { children } = $props();
  9. const isZh = localStorage.getItem('lang') === 'zh_CN';
  10. type menuListChildsProps = { title: string; title_en: string; nav: string; doc?: string };
  11. type menuListProps = { class: string; class_en: string; childs: menuListChildsProps[] };
  12. const menuList: menuListProps[] = [
  13. {
  14. class: '常规',
  15. class_en: 'General',
  16. childs: [
  17. { title: '快速上手', title_en: 'Quick start', nav: 'quick-start', doc: 'quickStart' },
  18. { title: '更新日志', title_en: 'Changelog', nav: 'changelog', doc: 'changelog' },
  19. { title: '主题配置', title_en: 'Theme', nav: 'theme', doc: 'theme' },
  20. { title: '图标', title_en: 'Icon', nav: 'icon', doc: 'icon' },
  21. { title: '函数式反馈', title_en: 'Functional Feedback', nav: 'feedback', doc: 'feedback' },
  22. { title: '国际化', title_en: 'Internationalization', nav: 'internation', doc: 'internation' },
  23. { title: '常见问题', title_en: 'FAQ', nav: 'faq', doc: 'faq' },
  24. { title: '贡献指南', title_en: 'Contribution Guide', nav: 'contribution', doc: 'contribution' },
  25. { title: '兼容性', title_en: 'Compatibility', nav: 'compatibility', doc: 'compatibility' },
  26. { title: '升级指南', title_en: 'Upgrade Guide', nav: 'upgrade', doc: 'upgrade' }
  27. ]
  28. },
  29. {
  30. class: '设计',
  31. class_en: 'Design',
  32. childs: [
  33. { title: '色彩', title_en: 'Color', nav: 'color' },
  34. { title: 'LOGO', title_en: 'LOGO', nav: 'logo' }
  35. ]
  36. },
  37. {
  38. class: '工具',
  39. class_en: 'Tools',
  40. childs: [
  41. { title: '主题生成器', title_en: 'Theme generator', nav: 'generator' },
  42. { title: '工具方法', title_en: 'Utils', nav: 'utils', doc: 'utils' },
  43. { title: 'IDE 插件', title_en: 'IDE plugin', nav: 'vscode', doc: 'vscode' },
  44. { title: '脚手架', title_en: 'Create cli', nav: 'create' },
  45. { title: '图标插件', title_en: 'Icon plugin', nav: 'icon-plugin' },
  46. { title: 'MD 插件', title_en: 'MD plugin', nav: 'md' },
  47. { title: '快捷键', title_en: 'Shortcut key', nav: 'shortkey' }
  48. ]
  49. },
  50. {
  51. class: '其他',
  52. class_en: 'Other',
  53. childs: [
  54. { title: '关于', title_en: 'About', nav: 'about', doc: 'about' },
  55. { title: '里程碑', title_en: 'Milestone', nav: 'milestone', doc: 'milestone' },
  56. { title: '计划', title_en: 'Future', nav: 'future', doc: 'future' }
  57. ]
  58. }
  59. ];
  60. //扁平 menuList
  61. const flatMenuList: menuListChildsProps[] = [];
  62. for (let e = 0; e < menuList.length; e++) {
  63. flatMenuList.push(...menuList[e].childs);
  64. }
  65. let currentNav = $state(menuList[0].childs[0]);
  66. let menuHeight = $state(0);
  67. const getMenuHeightFun = () => {
  68. menuHeight = document.documentElement.clientHeight - 56;
  69. };
  70. const menuClickFun = (currentMenu: MenuListChild) => {
  71. if ($isShowNavStore) {
  72. isShowNavStore.set(false);
  73. }
  74. currentNav = currentMenu;
  75. // 将当前点击的 currentMenu 设置 url 参数
  76. // window.location.href = '/guide?nav=' + currentMenu.nav;
  77. goto(`/guide${currentMenu.nav === 'quick-start' ? '' : `/${currentMenu.nav}`}`);
  78. };
  79. onMount(() => {
  80. menuHeight = document.documentElement.clientHeight - 56;
  81. window.addEventListener('resize', getMenuHeightFun);
  82. // 根据 page.url.pathname 获取 currentNav
  83. const urlNav = flatMenuList.find((item) => (page.url.pathname.includes(item.nav) ? item : null));
  84. currentNav = urlNav || flatMenuList[0];
  85. return () => {
  86. window.removeEventListener('resize', getMenuHeightFun);
  87. };
  88. });
  89. // 全屏
  90. const changeFullFunc = () => {
  91. if ($isWideScreenStore) {
  92. isWideScreenStore.set(false);
  93. localStorage.setItem('isFull', 'notFull');
  94. } else {
  95. isWideScreenStore.set(true);
  96. localStorage.setItem('isFull', 'full');
  97. }
  98. };
  99. // 编辑地址处理
  100. const editUrlFn = (nav: string) => {
  101. const baseUrl = 'https://github.com/any-tdf/stdf/edit/main/';
  102. if (nav === 'create') {
  103. return baseUrl + 'packages/create-stdf/README' + (isZh ? '_CN' : '') + '.md';
  104. }
  105. if (nav === 'icon-plugin') {
  106. return baseUrl + 'packages/rollup-plugin-stdf-icon/README' + (isZh ? '_CN' : '') + '.md';
  107. }
  108. return baseUrl + `docs/mds/guide/${flatMenuList.filter((item) => item.nav === nav)[0]?.doc}${isZh ? '' : '_en'}.md`;
  109. };
  110. </script>
  111. <div class="flex">
  112. <div
  113. class="bg-bg-base dark:bg-bg-base-dark fixed top-14 -left-52 z-100 w-48 overflow-y-scroll border-black/10 transition-all duration-300 md:left-0 md:bg-transparent dark:border-white/20 dark:md:bg-transparent"
  114. class:left-0={$isShowNavStore}
  115. class:-left-52={!$isShowNavStore}
  116. style="height:{menuHeight + 'px'}"
  117. >
  118. <Menu {menuList} currentNav={currentNav.nav} onclickMenu={menuClickFun} showNum={false} />
  119. </div>
  120. <div class="w-screen md:pl-48">
  121. <!-- {#if !page.url.pathname.includes('generator')}
  122. <div class="px-4 py-12 md:px-8 md:py-4">
  123. <div class="text-4xl font-bold">
  124. {isZh ? currentNav.title : currentNav.title_en}
  125. </div>
  126. </div>
  127. <div class="h-px bg-black/10 dark:bg-white/20"></div>
  128. {/if} -->
  129. <div class="px-4 pt-4 {page.url.pathname.includes('generator') ? 'md:px-4 md:pt-4' : 'md:px-8 md:pt-12'}">
  130. {@render children()}
  131. </div>
  132. {#if !page.url.pathname.includes('generator') && currentNav.nav != 'color' && currentNav.nav != 'logo' && currentNav.nav != 'shortkey'}
  133. <div class="mx-auto flex gap-2 px-4 pb-8 text-xs {$isWideScreenStore ? 'max-w-full md:px-8' : 'max-w-7xl md:px-0'}">
  134. <a href={editUrlFn(currentNav.nav)} class="text-primary dark:text-dark flex w-full" target="_blank">
  135. <span class="mr-1 h-4 w-4">
  136. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" class="h-4 w-4" style="fill: currentColor;">
  137. <path
  138. d="M12.8995 6.85431L17.1421 11.0969L7.24264 20.9964H3V16.7538L12.8995 6.85431ZM14.3137 5.44009L16.435 3.31877C16.8256 2.92825 17.4587 2.92825 17.8492 3.31877L20.6777 6.1472C21.0682 6.53772 21.0682 7.17089 20.6777 7.56141L18.5563 9.68273L14.3137 5.44009Z"
  139. />
  140. </svg>
  141. </span>
  142. {isZh ? '在 GitHub 上编辑' : 'Edit on GitHub'}
  143. </a>
  144. </div>
  145. {/if}
  146. </div>
  147. </div>
  148. {#if !page.url.pathname.includes('generator')}
  149. <button
  150. class="bg-primary shadow-primary/50 dark:bg-dark dark:shadow-dark/50 fixed right-2 bottom-4 z-50 hidden h-8 w-8 cursor-pointer rounded-full p-1.5 text-white shadow-md md:block dark:text-black"
  151. onclick={changeFullFunc}
  152. >
  153. {#if $isWideScreenStore}
  154. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
  155. ><path
  156. d="M20 3C20.5523 3 21 3.44772 21 4V20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V4C3 3.44772 3.44772 3 4 3H20ZM11 5H5V19H11V15H13V19H19V5H13V9H11V5ZM15 9L18 12L15 15V13H9V15L6 12L9 9V11H15V9Z"
  157. fill="currentColor"
  158. ></path></svg
  159. >
  160. {:else}
  161. <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
  162. ><path
  163. d="M20 3C20.5523 3 21 3.44772 21 4V20C21 20.5523 20.5523 21 20 21H4C3.44772 21 3 20.5523 3 20V4C3 3.44772 3.44772 3 4 3H20ZM11 5H5V10.999H7V9L10 12L7 15V13H5V19H11V17H13V19H19V13H17V15L14 12L17 9V10.999H19V5H13V7H11V5ZM13 13V15H11V13H13ZM13 9V11H11V9H13Z"
  164. fill="currentColor"
  165. ></path></svg
  166. >
  167. {/if}
  168. </button>
  169. {/if}
  170. <!-- 为 code-groups 预先编译 tailwind -->
  171. <div
  172. class="peer-checked/tab-0-0:border-primary peer-checked/tab-0-1:border-primary peer-checked/tab-0-2:border-primary peer-checked/tab-0-3:border-primary peer-checked/tab-0-4:border-primary peer-checked/tab-0-5:border-primary
  173. peer-checked/tab-1-0:border-primary peer-checked/tab-1-1:border-primary peer-checked/tab-1-2:border-primary
  174. peer-checked/tab-1-3:border-primary peer-checked/tab-1-4:border-primary peer-checked/tab-1-5:border-primary
  175. peer-checked/tab-2-0:border-primary peer-checked/tab-2-1:border-primary peer-checked/tab-2-2:border-primary
  176. peer-checked/tab-2-3:border-primary peer-checked/tab-2-4:border-primary peer-checked/tab-2-5:border-primary
  177. peer-checked/tab-3-0:border-primary peer-checked/tab-3-1:border-primary peer-checked/tab-3-2:border-primary
  178. peer-checked/tab-3-3:border-primary peer-checked/tab-3-4:border-primary peer-checked/tab-3-5:border-primary
  179. peer-checked/tab-4-0:border-primary peer-checked/tab-4-1:border-primary peer-checked/tab-4-2:border-primary
  180. peer-checked/tab-4-3:border-primary peer-checked/tab-4-4:border-primary peer-checked/tab-4-5:border-primary
  181. dark:peer-checked/tab-0-0:border-dark dark:peer-checked/tab-0-1:border-dark dark:peer-checked/tab-0-2:border-dark
  182. dark:peer-checked/tab-0-3:border-dark dark:peer-checked/tab-0-4:border-dark dark:peer-checked/tab-0-5:border-dark
  183. dark:peer-checked/tab-1-0:border-dark dark:peer-checked/tab-1-1:border-dark dark:peer-checked/tab-1-2:border-dark
  184. dark:peer-checked/tab-1-3:border-dark dark:peer-checked/tab-1-4:border-dark dark:peer-checked/tab-1-5:border-dark
  185. dark:peer-checked/tab-2-0:border-dark dark:peer-checked/tab-2-1:border-dark dark:peer-checked/tab-2-2:border-dark
  186. dark:peer-checked/tab-2-3:border-dark dark:peer-checked/tab-2-4:border-dark dark:peer-checked/tab-2-5:border-dark
  187. dark:peer-checked/tab-3-0:border-dark dark:peer-checked/tab-3-1:border-dark dark:peer-checked/tab-3-2:border-dark
  188. dark:peer-checked/tab-3-3:border-dark dark:peer-checked/tab-3-4:border-dark dark:peer-checked/tab-3-5:border-dark
  189. dark:peer-checked/tab-4-0:border-dark dark:peer-checked/tab-4-1:border-dark dark:peer-checked/tab-4-2:border-dark
  190. dark:peer-checked/tab-4-3:border-dark dark:peer-checked/tab-4-4:border-dark dark:peer-checked/tab-4-5:border-dark
  191. hidden border-b-2 border-black/10 peer-checked/tab-0-0:block
  192. peer-checked/tab-0-1:block peer-checked/tab-0-2:block peer-checked/tab-0-3:block
  193. peer-checked/tab-0-4:block peer-checked/tab-0-5:block peer-checked/tab-1-0:block
  194. peer-checked/tab-1-1:block peer-checked/tab-1-2:block peer-checked/tab-1-3:block
  195. peer-checked/tab-1-4:block peer-checked/tab-1-5:block peer-checked/tab-2-0:block
  196. peer-checked/tab-2-1:block peer-checked/tab-2-2:block peer-checked/tab-2-3:block
  197. peer-checked/tab-2-4:block peer-checked/tab-2-5:block peer-checked/tab-3-0:block
  198. peer-checked/tab-3-1:block peer-checked/tab-3-2:block peer-checked/tab-3-3:block
  199. peer-checked/tab-3-4:block peer-checked/tab-3-5:block peer-checked/tab-4-0:block
  200. peer-checked/tab-4-1:block peer-checked/tab-4-2:block peer-checked/tab-4-3:block
  201. peer-checked/tab-4-4:block peer-checked/tab-4-5:block dark:border-white/10 dark:bg-white/5"
  202. ></div>