preferences.vue 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <script setup lang="ts">
  2. import type {
  3. ContentCompactType,
  4. LayoutHeaderModeType,
  5. LayoutType,
  6. SupportedLanguagesType,
  7. ThemeModeType,
  8. } from '@vben/types';
  9. import type {
  10. BreadcrumbStyleType,
  11. NavigationStyleType,
  12. } from '@vben-core/preferences';
  13. import type { SegmentedItem } from '@vben-core/shadcn-ui';
  14. import { computed } from 'vue';
  15. import { $t } from '@vben/locales';
  16. import { IcRoundFolderCopy, IcRoundRestartAlt } from '@vben-core/iconify';
  17. import {
  18. preferences,
  19. resetPreferences,
  20. usePreferences,
  21. } from '@vben-core/preferences';
  22. import {
  23. VbenButton,
  24. VbenIconButton,
  25. VbenSegmented,
  26. VbenSheet,
  27. toast,
  28. } from '@vben-core/shadcn-ui';
  29. import { useClipboard } from '@vueuse/core';
  30. import {
  31. Animation,
  32. Block,
  33. Breadcrumb,
  34. ColorMode,
  35. Content,
  36. Footer,
  37. General,
  38. Header,
  39. Layout,
  40. Navigation,
  41. Sidebar,
  42. Tabbar,
  43. Theme,
  44. ThemeColor,
  45. } from './blocks';
  46. import Trigger from './trigger.vue';
  47. import { useOpenPreferences } from './use-open-preferences';
  48. withDefaults(defineProps<{ colorPrimaryPresets: string[] }>(), {
  49. colorPrimaryPresets: () => [],
  50. });
  51. const appThemeMode = defineModel<ThemeModeType>('appThemeMode');
  52. const appLocale = defineModel<SupportedLanguagesType>('appLocale');
  53. const appDynamicTitle = defineModel<boolean>('appDynamicTitle');
  54. const appLayout = defineModel<LayoutType>('appLayout');
  55. const appColorGrayMode = defineModel<boolean>('appColorGrayMode');
  56. const appColorWeakMode = defineModel<boolean>('appColorWeakMode');
  57. const appSemiDarkMenu = defineModel<boolean>('appSemiDarkMenu');
  58. const appContentCompact = defineModel<ContentCompactType>('appContentCompact');
  59. const transitionProgress = defineModel<boolean>('transitionProgress');
  60. const transitionName = defineModel<string>('transitionName');
  61. const transitionEnable = defineModel<boolean>('transitionEnable');
  62. const themeColorPrimary = defineModel<string>('themeColorPrimary');
  63. const sidebarEnable = defineModel<boolean>('sidebarEnable');
  64. const sidebarCollapse = defineModel<boolean>('sidebarCollapse');
  65. const sidebarCollapseShowTitle = defineModel<boolean>(
  66. 'sidebarCollapseShowTitle',
  67. );
  68. const headerEnable = defineModel<boolean>('headerEnable');
  69. const headerMode = defineModel<LayoutHeaderModeType>('headerMode');
  70. const breadcrumbEnable = defineModel<boolean>('breadcrumbEnable');
  71. const breadcrumbShowIcon = defineModel<boolean>('breadcrumbShowIcon');
  72. const breadcrumbShowHome = defineModel<boolean>('breadcrumbShowHome');
  73. const breadcrumbStyleType = defineModel<BreadcrumbStyleType>(
  74. 'breadcrumbStyleType',
  75. );
  76. const breadcrumbHideOnlyOne = defineModel<boolean>('breadcrumbHideOnlyOne');
  77. const tabbarEnable = defineModel<boolean>('tabbarEnable');
  78. const tabbarShowIcon = defineModel<boolean>('tabbarShowIcon');
  79. const navigationStyleType = defineModel<NavigationStyleType>(
  80. 'navigationStyleType',
  81. );
  82. const navigationSplit = defineModel<boolean>('navigationSplit');
  83. const navigationAccordion = defineModel<boolean>('navigationAccordion');
  84. // const logoVisible = defineModel<boolean>('logoVisible');
  85. const footerEnable = defineModel<boolean>('footerEnable');
  86. const footerFixed = defineModel<boolean>('footerFixed');
  87. const shortcutKeysEnable = defineModel<boolean>('shortcutKeysEnable');
  88. const {
  89. diffPreference,
  90. isFullContent,
  91. isHeaderNav,
  92. isMixedNav,
  93. isSideMixedNav,
  94. isSideMode,
  95. isSideNav,
  96. } = usePreferences();
  97. const { copy } = useClipboard();
  98. const tabs = computed((): SegmentedItem[] => {
  99. return [
  100. {
  101. label: $t('preference.appearance'),
  102. value: 'appearance',
  103. },
  104. {
  105. label: $t('preference.layout'),
  106. value: 'layout',
  107. },
  108. {
  109. label: $t('preference.general'),
  110. value: 'general',
  111. },
  112. // {
  113. // label: $t('preference.shortcut-key'),
  114. // value: 'shortcutKey',
  115. // },
  116. ];
  117. });
  118. const showBreadcrumbConfig = computed(() => {
  119. return (
  120. !isFullContent.value &&
  121. !isMixedNav.value &&
  122. !isHeaderNav.value &&
  123. preferences.header.enable
  124. );
  125. });
  126. const { openPreferences } = useOpenPreferences();
  127. async function handleCopy() {
  128. await copy(JSON.stringify(diffPreference.value, null, 2));
  129. toast($t('preference.copy-success'));
  130. }
  131. function handleReset() {
  132. if (!diffPreference.value) {
  133. return;
  134. }
  135. resetPreferences();
  136. toast($t('preference.reset-success'));
  137. }
  138. </script>
  139. <template>
  140. <div class="z-100 fixed right-0 top-1/3">
  141. <VbenSheet
  142. v-model:open="openPreferences"
  143. :description="$t('preference.preferences-subtitle')"
  144. :title="$t('preference.preferences')"
  145. >
  146. <template #trigger>
  147. <Trigger />
  148. </template>
  149. <template #extra>
  150. <VbenIconButton
  151. :disabled="!diffPreference"
  152. :tooltip="$t('preference.reset-tip')"
  153. class="relative"
  154. >
  155. <span
  156. v-if="diffPreference"
  157. class="bg-primary absolute right-0.5 top-0.5 h-2 w-2 rounded"
  158. ></span>
  159. <IcRoundRestartAlt class="size-5" @click="handleReset" />
  160. </VbenIconButton>
  161. </template>
  162. <div class="p-5 pt-4">
  163. <VbenSegmented :tabs="tabs" default-value="appearance">
  164. <template #appearance>
  165. <Block :title="$t('preference.theme')">
  166. <Theme
  167. v-model="appThemeMode"
  168. v-model:app-semi-dark-menu="appSemiDarkMenu"
  169. />
  170. </Block>
  171. <Block :title="$t('preference.theme-color')">
  172. <ThemeColor
  173. v-model="themeColorPrimary"
  174. :color-primary-presets="colorPrimaryPresets"
  175. />
  176. </Block>
  177. <Block :title="$t('preference.other')">
  178. <ColorMode
  179. v-model:app-color-gray-mode="appColorGrayMode"
  180. v-model:app-color-weak-mode="appColorWeakMode"
  181. />
  182. </Block>
  183. </template>
  184. <template #layout>
  185. <Block :title="$t('preference.layout')">
  186. <Layout v-model="appLayout" />
  187. </Block>
  188. <Block :title="$t('preference.content')">
  189. <Content v-model="appContentCompact" />
  190. </Block>
  191. <Block :title="$t('preference.sidebar')">
  192. <Sidebar
  193. v-model:side-collapse-show-title="sidebarCollapseShowTitle"
  194. v-model:sidebar-collapse="sidebarCollapse"
  195. v-model:sidebar-enable="sidebarEnable"
  196. :disabled="!isSideMode"
  197. />
  198. </Block>
  199. <Block :title="$t('preference.header')">
  200. <Header
  201. v-model:headerEnable="headerEnable"
  202. v-model:headerMode="headerMode"
  203. :disabled="isFullContent"
  204. />
  205. </Block>
  206. <Block :title="$t('preference.navigation-menu')">
  207. <Navigation
  208. v-model:navigation-accordion="navigationAccordion"
  209. v-model:navigation-split="navigationSplit"
  210. v-model:navigation-style-type="navigationStyleType"
  211. :disabled="isFullContent"
  212. :disabled-navigation-split="!isMixedNav"
  213. />
  214. </Block>
  215. <Block :title="$t('preference.breadcrumb')">
  216. <Breadcrumb
  217. v-model:breadcrumb-enable="breadcrumbEnable"
  218. v-model:breadcrumb-hide-only-one="breadcrumbHideOnlyOne"
  219. v-model:breadcrumb-show-home="breadcrumbShowHome"
  220. v-model:breadcrumb-show-icon="breadcrumbShowIcon"
  221. v-model:breadcrumb-style-type="breadcrumbStyleType"
  222. :disabled="
  223. !showBreadcrumbConfig || !(isSideNav || isSideMixedNav)
  224. "
  225. />
  226. </Block>
  227. <Block :title="$t('preference.tabs')">
  228. <Tabbar
  229. v-model:tabbar-enable="tabbarEnable"
  230. v-model:tabbar-show-icon="tabbarShowIcon"
  231. />
  232. </Block>
  233. <Block :title="$t('preference.footer')">
  234. <Footer
  235. v-model:footer-enable="footerEnable"
  236. v-model:footer-fixed="footerFixed"
  237. />
  238. </Block>
  239. </template>
  240. <template #general>
  241. <Block :title="$t('preference.general')">
  242. <General
  243. v-model:app-dynamic-title="appDynamicTitle"
  244. v-model:app-locale="appLocale"
  245. v-model:shortcut-keys-enable="shortcutKeysEnable"
  246. />
  247. </Block>
  248. <Block :title="$t('preference.animation')">
  249. <Animation
  250. v-model:transition-enable="transitionEnable"
  251. v-model:transition-name="transitionName"
  252. v-model:transition-progress="transitionProgress"
  253. />
  254. </Block>
  255. </template>
  256. <!-- <template #shortcutKey>
  257. <Block :title="$t('preference.general')">
  258. <General
  259. v-model:locale="locale"
  260. v-model:dynamic-title="dynamicTitle"
  261. v-model:shortcut-keys="shortcutKeys"
  262. />
  263. </Block>
  264. <Block :title="$t('preference.animation')">
  265. <Animation
  266. v-model:page-progress="pageProgress"
  267. v-model:page-transition="pageTransition"
  268. v-model:transition-enable="transitionEnable"
  269. />
  270. </Block>
  271. </template> -->
  272. </VbenSegmented>
  273. </div>
  274. <template #footer>
  275. <VbenButton
  276. :disabled="!diffPreference"
  277. class="mx-6 w-full"
  278. size="sm"
  279. variant="default"
  280. @click="handleCopy"
  281. >
  282. <IcRoundFolderCopy class="mr-2 size-3" />
  283. {{ $t('preference.copy') }}
  284. </VbenButton>
  285. </template>
  286. </VbenSheet>
  287. </div>
  288. </template>