feat: appProvider / appInject / breakpoints / tags-style(fix) / mobile-menu-layout

main
NoahLan 1 year ago
parent 949db8a088
commit b8572d6304

@ -1,4 +1,4 @@
{
"icons": {},
"prefix": "nl-svg"
"prefix": "nl"
}

@ -71,7 +71,6 @@
"fast-glob": "^3.3.2",
"https-localhost": "^4.7.1",
"less": "^4.2.0",
"less-loader": "^11.1.3",
"lint-staged": "^14.0.1",
"markdown-it-link-attributes": "^4.0.1",
"markdown-it-shiki": "^0.9.0",
@ -104,7 +103,8 @@
"vite-plugin-webfont-dl": "^3.7.6",
"vitest": "^0.34.6",
"vue-request": "^2.0.4",
"vue-tsc": "^1.8.20"
"vue-tsc": "^1.8.20",
"vuedraggable": "^4.1.0"
},
"simple-git-hooks": {
"pre-commit": "pnpm lint-staged"

File diff suppressed because it is too large Load Diff

@ -45,6 +45,7 @@ const themeOverridesRef = computed((): GlobalThemeOverrides => {
class="h-full w-full" :theme="theme" :theme-overrides="themeOverridesRef" :locale="zhCN"
:date-locale="dateZhCN"
>
<NGlobalStyle />
<NLoadingBarProvider>
<NMessageProvider>
<NNotificationProvider>
@ -53,11 +54,12 @@ const themeOverridesRef = computed((): GlobalThemeOverrides => {
content="TODO 水印" cross fullscreen :font-size="12" :line-height="16" :width="384" :height="384"
:x-offset="12" :y-offset="60" :rotate="-15"
/>
<RouterView />
<LAppProvider>
<RouterView />
</LAppProvider>
</NDialogProvider>
</NNotificationProvider>
</NMessageProvider>
</NLoadingBarProvider>
<NGlobalStyle />
</NConfigProvider>
</template>

@ -13,7 +13,7 @@ declare global {
const $shallowRef: typeof import('vue/macros')['$shallowRef']
const $toRef: typeof import('vue/macros')['$toRef']
const EffectScope: typeof import('vue')['EffectScope']
const RouterLink: typeof import('vue-router/auto')['RouterLink']
const NLBreakpointsEnum2: typeof import('naive-ui')['NLBreakpointsEnum2']
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const computed: typeof import('vue')['computed']
@ -24,6 +24,9 @@ declare global {
const controlledComputed: typeof import('@vueuse/core')['controlledComputed']
const controlledRef: typeof import('@vueuse/core')['controlledRef']
const createApp: typeof import('vue')['createApp']
const createAppProviderContext: typeof import('./composables/web/app-context')['createAppProviderContext']
const createBreakpointListen: typeof import('./composables/event/useBreakpoint')['createBreakpointListen']
const createContext: typeof import('./composables/context')['createContext']
const createEventHook: typeof import('@vueuse/core')['createEventHook']
const createGlobalState: typeof import('@vueuse/core')['createGlobalState']
const createGridLayoutListen: typeof import('./composables/web/theme')['createGridLayoutListen']
@ -40,22 +43,17 @@ declare global {
const debouncedWatch: typeof import('@vueuse/core')['debouncedWatch']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const defineLoader: typeof import('vue-router/auto')['defineLoader']
const definePage: typeof import('unplugin-vue-router/runtime')['_definePage']
const eagerComputed: typeof import('@vueuse/core')['eagerComputed']
const effectScope: typeof import('vue')['effectScope']
const envD: typeof import('./types/env.d')['default']
const extendRef: typeof import('@vueuse/core')['extendRef']
const getActiveHead: typeof import('@unhead/vue')['getActiveHead']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const getRoutes: typeof import('./composables/router/routes')['getRoutes']
const h: typeof import('vue')['h']
const ignorableWatch: typeof import('@vueuse/core')['ignorableWatch']
const inject: typeof import('vue')['inject']
const injectHead: typeof import('@unhead/vue')['injectHead']
const injectLocal: typeof import('@vueuse/core')['injectLocal']
const isDark: typeof import('./composables/dark')['isDark']
const isDefined: typeof import('@vueuse/core')['isDefined']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
@ -89,7 +87,6 @@ declare global {
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const pausableWatch: typeof import('@vueuse/core')['pausableWatch']
const preferredDark: typeof import('./composables/dark')['preferredDark']
const provide: typeof import('vue')['provide']
const provideLocal: typeof import('@vueuse/core')['provideLocal']
const reactify: typeof import('@vueuse/core')['reactify']
@ -109,7 +106,6 @@ declare global {
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveRef: typeof import('@vueuse/core')['resolveRef']
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
const routeLink: typeof import('vue-router/auto')['routeLink']
const setGlobalOptions: typeof import('./composables/request')['setGlobalOptions']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
@ -124,7 +120,6 @@ declare global {
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const toggleDark: typeof import('./composables/dark')['toggleDark']
const triggerRef: typeof import('vue')['triggerRef']
const tryOnBeforeMount: typeof import('@vueuse/core')['tryOnBeforeMount']
const tryOnBeforeUnmount: typeof import('@vueuse/core')['tryOnBeforeUnmount']
@ -138,6 +133,8 @@ declare global {
const useAnimate: typeof import('@vueuse/core')['useAnimate']
const useAppConfig: typeof import('./composables/config/app-config')['useAppConfig']
const useAppConfigStore: typeof import('./stores/app-config')['useAppConfigStore']
const useAppInject: typeof import('./composables/web/app-inject')['useAppInject']
const useAppProviderContext: typeof import('./composables/web/app-context')['useAppProviderContext']
const useAppTheme: typeof import('./composables/web/theme')['useAppTheme']
const useArrayDifference: typeof import('@vueuse/core')['useArrayDifference']
const useArrayEvery: typeof import('@vueuse/core')['useArrayEvery']
@ -157,6 +154,7 @@ declare global {
const useBase64: typeof import('@vueuse/core')['useBase64']
const useBattery: typeof import('@vueuse/core')['useBattery']
const useBluetooth: typeof import('@vueuse/core')['useBluetooth']
const useBreakpoint: typeof import('./composables/event/useBreakpoint')['useBreakpoint']
const useBreakpoints: typeof import('@vueuse/core')['useBreakpoints']
const useBroadcastChannel: typeof import('@vueuse/core')['useBroadcastChannel']
const useBrowserLocation: typeof import('@vueuse/core')['useBrowserLocation']
@ -165,6 +163,7 @@ declare global {
const useCloned: typeof import('@vueuse/core')['useCloned']
const useColorMode: typeof import('@vueuse/core')['useColorMode']
const useConfirmDialog: typeof import('@vueuse/core')['useConfirmDialog']
const useContext: typeof import('./composables/context')['useContext']
const useCounter: typeof import('@vueuse/core')['useCounter']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVar: typeof import('@vueuse/core')['useCssVar']
@ -211,7 +210,6 @@ declare global {
const useHeaderSetting: typeof import('./composables/setting/header-setting')['useHeaderSetting']
const useI18n: typeof import('./composables/locale/i18n')['useI18n']
const useIcon: typeof import('./composables/icon')['useIcon']
const useIconRender: typeof import('./composables/icon')['useIconRender']
const useIdle: typeof import('@vueuse/core')['useIdle']
const useImage: typeof import('@vueuse/core')['useImage']
const useInfiniteScroll: typeof import('@vueuse/core')['useInfiniteScroll']
@ -235,13 +233,11 @@ declare global {
const useMemory: typeof import('@vueuse/core')['useMemory']
const useMenu: typeof import('./composables/router/menu')['useMenu']
const useMenuSetting: typeof import('./composables/setting/menu-setting')['useMenuSetting']
const useMenuStore: typeof import('./stores/menu')['useMenuStore']
const useMessage: typeof import('naive-ui')['useMessage']
const useMounted: typeof import('@vueuse/core')['useMounted']
const useMouse: typeof import('@vueuse/core')['useMouse']
const useMouseInElement: typeof import('@vueuse/core')['useMouseInElement']
const useMousePressed: typeof import('@vueuse/core')['useMousePressed']
const useMultipleTab: typeof import('./stores/multiple-tab')['useMultipleTab']
const useMultipleTabSetting: typeof import('./composables/setting/multiple-tab-setting')['useMultipleTabSetting']
const useMultipleTabStore: typeof import('./stores/multiple-tab')['useMultipleTabStore']
const useMutationObserver: typeof import('@vueuse/core')['useMutationObserver']
@ -381,6 +377,9 @@ declare module 'vue' {
readonly controlledComputed: UnwrapRef<typeof import('@vueuse/core')['controlledComputed']>
readonly controlledRef: UnwrapRef<typeof import('@vueuse/core')['controlledRef']>
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
readonly createAppProviderContext: UnwrapRef<typeof import('./composables/web/app-context')['createAppProviderContext']>
readonly createBreakpointListen: UnwrapRef<typeof import('./composables/event/useBreakpoint')['createBreakpointListen']>
readonly createContext: UnwrapRef<typeof import('./composables/context')['createContext']>
readonly createEventHook: UnwrapRef<typeof import('@vueuse/core')['createEventHook']>
readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']>
readonly createGridLayoutListen: UnwrapRef<typeof import('./composables/web/theme')['createGridLayoutListen']>
@ -487,6 +486,8 @@ declare module 'vue' {
readonly useAnimate: UnwrapRef<typeof import('@vueuse/core')['useAnimate']>
readonly useAppConfig: UnwrapRef<typeof import('./composables/config/app-config')['useAppConfig']>
readonly useAppConfigStore: UnwrapRef<typeof import('./stores/app-config')['useAppConfigStore']>
readonly useAppInject: UnwrapRef<typeof import('./composables/web/app-inject')['useAppInject']>
readonly useAppProviderContext: UnwrapRef<typeof import('./composables/web/app-context')['useAppProviderContext']>
readonly useAppTheme: UnwrapRef<typeof import('./composables/web/theme')['useAppTheme']>
readonly useArrayDifference: UnwrapRef<typeof import('@vueuse/core')['useArrayDifference']>
readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']>
@ -506,6 +507,7 @@ declare module 'vue' {
readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']>
readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']>
readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']>
readonly useBreakpoint: UnwrapRef<typeof import('./composables/event/useBreakpoint')['useBreakpoint']>
readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']>
readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']>
readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']>
@ -514,6 +516,7 @@ declare module 'vue' {
readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']>
readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']>
readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']>
readonly useContext: UnwrapRef<typeof import('./composables/context')['useContext']>
readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']>
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']>
@ -721,6 +724,9 @@ declare module '@vue/runtime-core' {
readonly controlledComputed: UnwrapRef<typeof import('@vueuse/core')['controlledComputed']>
readonly controlledRef: UnwrapRef<typeof import('@vueuse/core')['controlledRef']>
readonly createApp: UnwrapRef<typeof import('vue')['createApp']>
readonly createAppProviderContext: UnwrapRef<typeof import('./composables/web/app-context')['createAppProviderContext']>
readonly createBreakpointListen: UnwrapRef<typeof import('./composables/event/useBreakpoint')['createBreakpointListen']>
readonly createContext: UnwrapRef<typeof import('./composables/context')['createContext']>
readonly createEventHook: UnwrapRef<typeof import('@vueuse/core')['createEventHook']>
readonly createGlobalState: UnwrapRef<typeof import('@vueuse/core')['createGlobalState']>
readonly createGridLayoutListen: UnwrapRef<typeof import('./composables/web/theme')['createGridLayoutListen']>
@ -827,6 +833,8 @@ declare module '@vue/runtime-core' {
readonly useAnimate: UnwrapRef<typeof import('@vueuse/core')['useAnimate']>
readonly useAppConfig: UnwrapRef<typeof import('./composables/config/app-config')['useAppConfig']>
readonly useAppConfigStore: UnwrapRef<typeof import('./stores/app-config')['useAppConfigStore']>
readonly useAppInject: UnwrapRef<typeof import('./composables/web/app-inject')['useAppInject']>
readonly useAppProviderContext: UnwrapRef<typeof import('./composables/web/app-context')['useAppProviderContext']>
readonly useAppTheme: UnwrapRef<typeof import('./composables/web/theme')['useAppTheme']>
readonly useArrayDifference: UnwrapRef<typeof import('@vueuse/core')['useArrayDifference']>
readonly useArrayEvery: UnwrapRef<typeof import('@vueuse/core')['useArrayEvery']>
@ -846,6 +854,7 @@ declare module '@vue/runtime-core' {
readonly useBase64: UnwrapRef<typeof import('@vueuse/core')['useBase64']>
readonly useBattery: UnwrapRef<typeof import('@vueuse/core')['useBattery']>
readonly useBluetooth: UnwrapRef<typeof import('@vueuse/core')['useBluetooth']>
readonly useBreakpoint: UnwrapRef<typeof import('./composables/event/useBreakpoint')['useBreakpoint']>
readonly useBreakpoints: UnwrapRef<typeof import('@vueuse/core')['useBreakpoints']>
readonly useBroadcastChannel: UnwrapRef<typeof import('@vueuse/core')['useBroadcastChannel']>
readonly useBrowserLocation: UnwrapRef<typeof import('@vueuse/core')['useBrowserLocation']>
@ -854,6 +863,7 @@ declare module '@vue/runtime-core' {
readonly useCloned: UnwrapRef<typeof import('@vueuse/core')['useCloned']>
readonly useColorMode: UnwrapRef<typeof import('@vueuse/core')['useColorMode']>
readonly useConfirmDialog: UnwrapRef<typeof import('@vueuse/core')['useConfirmDialog']>
readonly useContext: UnwrapRef<typeof import('./composables/context')['useContext']>
readonly useCounter: UnwrapRef<typeof import('@vueuse/core')['useCounter']>
readonly useCssModule: UnwrapRef<typeof import('vue')['useCssModule']>
readonly useCssVar: UnwrapRef<typeof import('@vueuse/core')['useCssVar']>

@ -7,6 +7,7 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
LAppProvider: typeof import('./components/LAppProvider/index.vue')['default']
LAuth: typeof import('./components/LAuth/index.ts')['default']
LAuthBg: typeof import('./components/LAuth/bg.vue')['default']
LAuthLayout: typeof import('./components/LAuth/layout.vue')['default']
@ -24,6 +25,7 @@ declare module 'vue' {
NDrawer: typeof import('naive-ui')['NDrawer']
NDrawerContent: typeof import('naive-ui')['NDrawerContent']
NDropdown: typeof import('naive-ui')['NDropdown']
NEl: typeof import('naive-ui')['NEl']
NEmpty: typeof import('naive-ui')['NEmpty']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']
@ -53,6 +55,7 @@ declare module 'vue' {
NTab: typeof import('naive-ui')['NTab']
NTabPane: typeof import('naive-ui')['NTabPane']
NTabs: typeof import('naive-ui')['NTabs']
NTag: typeof import('naive-ui')['NTag']
NText: typeof import('naive-ui')['NText']
NTooltip: typeof import('naive-ui')['NTooltip']
NWatermark: typeof import('naive-ui')['NWatermark']

@ -0,0 +1,41 @@
<script lang="ts" setup>
import { BreakpointsEnum } from '~/constants'
import { namespace } from '~/setting'
const props = defineProps({
prefixCls: { type: String, default: namespace },
})
const isMobile = ref(false)
let isSetState = $ref(false)
// const configStore = useAppConfigStore()
createBreakpointListen(({ isSmaller }) => {
isMobile.value = isSmaller(BreakpointsEnum.LG)
handleRestoreState()
})
const { prefixCls } = toRefs(props)
// inject into global
createAppProviderContext({ prefixCls, isMobile })
function handleRestoreState() {
if (unref(isMobile)) {
if (!unref(isSetState)) {
isSetState = true
}
}
else {
if (unref(isSetState)) {
isSetState = false
}
}
}
</script>
<template>
<slot />
</template>

@ -50,7 +50,7 @@ const desc = computed(() => import.meta.env.VITE_APP_DESC)
</div>
</template>
<style lang="less">
<style scoped>
.bg-register {
clip-path: polygon(100% 0, 0 0, 100% 100%);
}

@ -165,11 +165,11 @@ const { bem } = createNamespace('l-icon')
</div>
</template>
<style lang="less" scoped>
<style scoped>
.l-icon {
display: inline-block;
overflow: hidden;
fill: currentcolor;
vertical-align: -0.15em;
overflow: hidden;
fill: currentcolor;
vertical-align: -0.15em;
}
</style>

@ -0,0 +1,40 @@
import { readonly as defineReadonly } from 'vue'
import type { InjectionKey, UnwrapRef } from 'vue'
export interface CreateContextOptions {
readonly?: boolean
createProvider?: boolean
native?: boolean
}
type ShallowUnwrap<T> = {
[P in keyof T]: UnwrapRef<T[P]>
}
export function createContext<T>(
context: any,
key: InjectionKey<T> = Symbol('context'),
options: CreateContextOptions = {},
) {
const { readonly = true, createProvider = false, native = false } = options
const state = reactive(context)
const provideData = readonly ? defineReadonly(state) : state
!createProvider && provide(key, native ? context : provideData)
return { state }
}
export function useContext<T>(key: InjectionKey<T>, native?: boolean): T
export function useContext<T>(
key: InjectionKey<T>,
defaultValue?: any,
native?: boolean
): T
export function useContext<T>(
key: InjectionKey<T> = Symbol('context'),
defaultValue?: any,
): ShallowUnwrap<T> {
return inject(key, defaultValue || {})
}

@ -0,0 +1,105 @@
import { useBreakpoints } from '@vueuse/core'
import type { Breakpoints } from '~/constants'
import { BreakpointsEnum, BreakpointsMap } from '~/constants'
let globalScreenRef: ComputedRef<BreakpointsEnum>
let globalWidthRef: ComputedRef<number>
let globalRealWidthRef: ComputedRef<number>
export interface BreakpointCallback {
screen: ComputedRef<BreakpointsEnum>
width: ComputedRef<number>
realWidth: ComputedRef<number>
breakpointsMap: Breakpoints
// vueuse breakpoints
greater(k: BreakpointsEnum): Ref<boolean>
greaterOrEqual: (k: BreakpointsEnum) => Ref<boolean>
smaller(k: BreakpointsEnum): Ref<boolean>
smallerOrEqual(k: BreakpointsEnum): Ref<boolean>
between(a: BreakpointsEnum, b: BreakpointsEnum): Ref<boolean>
isGreater(k: BreakpointsEnum): boolean
isGreaterOrEqual(k: BreakpointsEnum): boolean
isSmaller(k: BreakpointsEnum): boolean
isSmallerOrEqual(k: BreakpointsEnum): boolean
isInBetween(a: BreakpointsEnum, b: BreakpointsEnum): boolean
current(): ComputedRef<string[]>
}
export function useBreakpoint() {
const breakpoints = useBreakpoints(BreakpointsMap)
const screenRef = computed(() => unref(globalScreenRef))
return {
...breakpoints,
screenRef,
}
}
export function createBreakpointListen(fn?: (p: BreakpointCallback) => void) {
const breakpoints = useBreakpoint()
const screenRef = ref<BreakpointsEnum>(BreakpointsEnum.XL)
let realWidthRef = $ref(window.innerWidth)
const {
greater,
greaterOrEqual,
isGreater,
isGreaterOrEqual,
between,
isInBetween,
smaller,
smallerOrEqual,
isSmaller,
isSmallerOrEqual,
current,
} = breakpoints
function getWindowWidth() {
realWidthRef = document.body.clientWidth
screenRef.value = (breakpoints.isSmallerOrEqual(BreakpointsEnum.XS)
? BreakpointsEnum.XS
: breakpoints.isInBetween(BreakpointsEnum.XS, BreakpointsEnum.SM)
? BreakpointsEnum.SM
: breakpoints.isInBetween(BreakpointsEnum.SM, BreakpointsEnum.MD)
? BreakpointsEnum.MD
: breakpoints.isInBetween(BreakpointsEnum.MD, BreakpointsEnum.LG)
? BreakpointsEnum.LG
: breakpoints.isInBetween(BreakpointsEnum.LG, BreakpointsEnum.XL)
? BreakpointsEnum.XL
: breakpoints.isInBetween(BreakpointsEnum.XL, BreakpointsEnum.XXL) ? BreakpointsEnum.XXL : BreakpointsEnum.XL)
}
function resizeFn() {
fn?.({
screen: globalScreenRef,
width: globalWidthRef,
realWidth: globalRealWidthRef,
breakpointsMap: BreakpointsMap,
greater,
greaterOrEqual,
isGreater,
isGreaterOrEqual,
between,
isInBetween,
smaller,
smallerOrEqual,
isSmaller,
isSmallerOrEqual,
current,
})
}
useEventListener(window, 'resize', () => {
getWindowWidth()
resizeFn()
})
getWindowWidth()
globalScreenRef = computed(() => unref(screenRef))
globalWidthRef = computed((): number => BreakpointsMap[unref(screenRef)] as number)
globalRealWidthRef = computed((): number => unref(realWidthRef))
resizeFn()
}

@ -1,14 +1,12 @@
const headerRef = ref<HTMLElement | undefined>()
const contentRef = ref<HTMLElement | undefined>()
const tabRef = ref<HTMLElement | undefined>()
const footerRef = ref<HTMLElement | undefined>()
export function useLayout() {
const { getFixed: getHeaderFixed } = useHeaderSetting()
const headerRef = ref<HTMLElement | null>(null)
const { height: headerHeight, width: headerWidth } = useElementSize(headerRef)
const contentRef = ref<HTMLElement | null>(null)
const tabRef = ref<HTMLElement | null>(null)
const { height: tabHeight, width: tabWidth } = useElementSize(tabRef)
const footerRef = ref<HTMLElement | null>(null)
const { height: footerHeight, width: footerWidth } = useElementSize(footerRef)
const omitContentHeight = computed(() => {

@ -15,7 +15,7 @@ export function useHeaderSetting() {
const { getShowBreadCrumb, getShowLogo } = useRootSetting()
const getShowDoc = computed(() => appConfig.header.value.showDoc)
const getHeaderTheme = computed(() => appConfig.header.value.theme)
// const getHeaderTheme = computed(() => appConfig.header.value.theme)
const getShowHeader = computed(() => appConfig.header.value.show)
const getFixed = computed(() => appConfig.header.value.fixed)
const getShowSearch = computed(() => appConfig.header.value.showSearch)
@ -66,7 +66,7 @@ export function useHeaderSetting() {
setHeaderSetting,
getShowDoc,
getShowSearch,
getHeaderTheme,
// getHeaderTheme,
getUseLockPage,
getShowFullScreen,
getShowNotice,

@ -34,19 +34,8 @@ export function useRootSetting() {
? ContentLayoutEnum.FULL
: ContentLayoutEnum.FIXED,
)
// TODO 待实现
// const getDarkMode = computed(() => configStore.getDarkMode)
// TODO 待实现
// function setRootSetting(setting: Partial<RootSetting>) {
// configStore.setProjectConfig(setting)
// }
// TODO 待实现
// function setDarkMode(mode: ThemeEnum) {
// configStore.setDarkMode(mode)
// }
return {
// setRootSetting,
getSettingButtonPosition,
getFullContent,
getColorWeak,

@ -0,0 +1,16 @@
import type { InjectionKey } from 'vue'
export interface AppProviderContextProps {
prefixCls: Ref<string>
isMobile: Ref<boolean>
}
const key: InjectionKey<AppProviderContextProps> = Symbol('app-provider-context')
export function createAppProviderContext(context: AppProviderContextProps) {
return createContext<AppProviderContextProps>(context, key)
}
export function useAppProviderContext() {
return useContext<AppProviderContextProps>(key)
}

@ -0,0 +1,7 @@
export function useAppInject() {
const values = useAppProviderContext()
return {
isMobile: computed(() => unref(values.isMobile)),
}
}

@ -41,8 +41,11 @@ export enum SessionTimeoutProcessingEnum {
// 设置按钮位置
export enum SettingButtonPositionEnum {
// 自动,当顶栏无法显示设置按钮时,固定浮动
AUTO = 'auto',
// 顶栏
HEADER = 'header',
// 固定浮动
FIXED = 'fixed',
}

@ -0,0 +1,19 @@
export enum BreakpointsEnum {
XS = 'xs',
SM = 'sm',
MD = 'md',
LG = 'lg',
XL = 'xl',
XXL = 'xxl',
}
export type Breakpoints<K extends string = BreakpointsEnum> = Record<K, number | string>
export const BreakpointsMap: Breakpoints = {
xs: 480,
sm: 576,
md: 768,
lg: 992,
xl: 1200,
xxl: 1600,
}

@ -5,3 +5,4 @@ export * from './design'
export * from './sidebar'
export * from './router'
export * from './multiple-tab'
export * from './breakpoint'

@ -13,11 +13,14 @@ const getIsFixedSettingDrawer = computed(() => {
if (!unref(getShowSettingButton)) {
return false
}
const settingButtonPosition = unref(getSettingButtonPosition)
if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
const pos = unref(getSettingButtonPosition)
if (pos.includes(SettingButtonPositionEnum.FIXED)) {
return true
}
if (pos.includes(SettingButtonPositionEnum.AUTO)) {
return !unref(getShowHeader) || unref(getFullContent)
}
return settingButtonPosition === SettingButtonPositionEnum.FIXED
return false
})
</script>

@ -36,11 +36,14 @@ const getShowSetting = computed(() => {
if (!unref(getShowSettingButton)) {
return false
}
const settingButtonPosition = unref(getSettingButtonPosition)
if (settingButtonPosition === SettingButtonPositionEnum.AUTO) {
const pos = unref(getSettingButtonPosition)
if (pos.includes(SettingButtonPositionEnum.HEADER)) {
return true
}
if (pos.includes(SettingButtonPositionEnum.AUTO)) {
return unref(getShowHeader)
}
return settingButtonPosition === SettingButtonPositionEnum.HEADER
return false
})
// header
@ -92,23 +95,23 @@ const { isFullscreen } = useFullscreen()
<NSpace :size="0" align="center" :wrap-item="false">
<!-- Search -->
<!-- Notify -->
<NPopover trigger="hover">
<NPopover v-if="getShowFullScreen" trigger="hover">
<template #trigger>
<Fullscreen v-if="getShowFullScreen" :class="bem('action__item')" />
<Fullscreen :class="bem('action__item')" />
</template>
<span>{{ unref(isFullscreen) ? $t('layout.header.tooltipExitFull') : $t('layout.header.tooltipEntryFull') }}</span>
</NPopover>
<NPopover trigger="hover">
<NPopover v-if="getShowLocalePicker" trigger="hover">
<template #trigger>
<LLocalePicker v-if="getShowLocalePicker" :class="bem('action__item')" :reload="true" :show-text="false" />
<LLocalePicker :class="bem('action__item')" :reload="true" :show-text="false" />
</template>
<span>{{ $t('layout.header.tooltipLanguage') }}</span>
</NPopover>
<!-- UserDropDown -->
<NPopover trigger="hover">
<NPopover v-if="getShowSetting" trigger="hover">
<template #trigger>
<SettingButton v-if="getShowSetting" :class="bem('action__item')" />
<SettingButton :class="bem('action__item')" />
</template>
<span>{{ $t('layout.header.tooltipSettings') }}</span>
</NPopover>
@ -142,7 +145,7 @@ const { isFullscreen } = useFullscreen()
}
&__item:hover {
background-color: var(--n-border-color);
background-color: var(--border-color);
}
}
}

@ -2,17 +2,26 @@
import SettingDrawer from './setting-drawer.vue'
const visible = $ref(false)
const { contentRef } = useLayout()
</script>
<template>
<NAffix
:listen-to="contentRef"
:trigger-top="240"
class="right-0 z-999 flex-center cursor-pointer border-rd-l bg-[var(--primary-color)] p-10px text-white"
@click="visible = true"
>
<LIcon icon="ant-design:setting-outlined" class="hover:cursor-pointer" />
</NAffix>
<NEl tag="div" class="setting-btn fixed bottom-12 right-12 z-10 shadow" @click="visible = true">
<LIcon icon="ant-design:setting-outlined" color="var(--text-color-1)" />
</NEl>
<SettingDrawer $visible="visible" />
</template>
<style lang="less" scoped>
.setting-btn {
background: var(--card-color);
display: inline-flex;
align-items: center;
justify-content: center;
flex-direction: column;
cursor: pointer;
border-radius: 50%;
width: 48px;
height: 48px;
color: var(--card-color);
}
</style>

@ -59,5 +59,5 @@ function onChange(color: string) {
</div>
</template>
<style lang="less" scoped>
<style scoped>
</style>

@ -93,24 +93,22 @@ watch(
</template>
<style lang="less" scoped>
// .drag-bar {
// position: absolute;
// z-index: 999;
// top: 0;
// right: -2px;
// width: 2px;
// height: 100%;
// border-top: none;
// border-bottom: none;
// cursor: col-resize;
// &__hide {
// display: none;
// }
// &:hover {
// background-color: var(--primary-color);
// box-shadow: 0 0 4px 0 rgb(28 36 56 / 15%);
// }
// }
.drag-bar {
position: absolute;
z-index: 999;
top: 0;
right: -2px;
width: 2px;
height: 100%;
border-top: none;
border-bottom: none;
cursor: col-resize;
&__hide {
display: none;
}
&:hover {
background-color: var(--primary-color);
box-shadow: 0 0 4px 0 rgb(28 36 56 / 15%);
}
}
</style>

@ -20,7 +20,7 @@ function handleFold() {
<template>
<div
class="h-full w-32px flex-center cursor-pointer border-l border-[var(--n-border-color)]"
class="h-full w-32px flex-center cursor-pointer border-l border-[var(--border-color)]"
@click="handleFold"
>
<LIcon :icon="getIconRef" />

@ -62,7 +62,7 @@ async function handleSelect(key: TabActionEnum) {
@select="handleSelect"
>
<div
class="h-full w-32px flex-center cursor-pointer border-l border-[var(--n-border-color)]"
class="h-full w-32px flex-center cursor-pointer border-l border-[var(--border-color)]"
>
<LIcon icon="ant-design:down-outlined" />
</div>

@ -16,7 +16,7 @@ const { loading, handleFn: handleRedo } = usePromise(reload, { immediate: false
<template>
<div
class="h-full w-32px flex-center cursor-pointer border-l border-[var(--n-border-color)]"
class="h-full w-32px flex-center cursor-pointer border-l border-[var(--border-color)]"
@click="handleRedo"
>
<LIcon :spin="loading" icon="ant-design:reload-outlined" />

@ -54,7 +54,9 @@ nextTick(() => {
const selection = document.querySelector(
'#drag > div > div > div > div > div.n-tabs-wrapper',
)
Sortable.create(selection as HTMLElement)
Sortable.create(selection as HTMLElement, {
animation: 150,
})
})
function handleContextMenu(e: MouseEvent, tabItem: RouteLocationNormalized) {
@ -72,7 +74,7 @@ function handleClose(e: MouseEvent, route: RouteLocationNormalized) {
</script>
<template>
<div class="mt-2">
<NEl class="mt-2">
<NTabs
id="drag"
v-model:value="activeTabName"
@ -110,5 +112,5 @@ function handleClose(e: MouseEvent, route: RouteLocationNormalized) {
</template>
</NTabs>
<TabDropDown ref="tabDropdownRef" />
</div>
</NEl>
</template>

@ -3,13 +3,18 @@ import LeftMenuLayout from './left-menu.vue'
import MixMenuLayout from './mix-menu.vue'
import TopMenuLayout from './top-menu.vue'
import TopMenuMixLayout from './top-menu-mixed.vue'
import MobileLayout from './mobile-menu.vue'
import { NavBarModeEnum } from '~/constants'
// TODO lockScreen
const { isMobile } = useAppInject()
const { getMenuType } = useMenuSetting()
const layout = computed<ReturnType<typeof defineComponent>>(() => {
// TODO appInject mobile
if (unref(isMobile)) {
return MobileLayout
}
switch (getMenuType.value) {
case NavBarModeEnum.SIDEBAR:
return LeftMenuLayout

@ -80,7 +80,7 @@ const { isSidebarDark } = useAppTheme()
</NLayout>
</template>
<style lang="less" scoped>
<style scoped>
.layout-mix-sidebar {
z-index: var(--mix-sider-z-index);
}

@ -0,0 +1,67 @@
<script setup lang="ts">
import LayoutMenu from './components/menu/index.vue'
import LayoutHeader from './components/header.vue'
import LayoutMain from './components/main.vue'
import LayoutFooter from './components/footer.vue'
import Logo from './components/logo/index.vue'
const {
headerRef,
footerRef,
contentStyle,
mainStyle,
contentRef,
} = useLayout()
const { getMenuWidth } = useMenuSetting()
const { getShowFooter } = useRootSetting()
let active = $ref(false)
onMounted(() => {
active = true
})
function activeTrigger() {
active = !active
}
</script>
<template>
<NLayout class="h-full min-w-375px">
<NDrawer v-model:show="active" placement="left" :width="getMenuWidth">
<NDrawerContent :body-content-style="{ padding: 0 }">
<LayoutMenu />
</NDrawerContent>
</NDrawer>
<NLayoutHeader ref="headerRef">
<slot name="header">
<LayoutHeader>
<template #logo>
<NSpace align="center" :wrap-item="false">
<Logo :show-title="false" />
<LIcon
:icon="active ? 'ant-design:menu-fold-outlined' : 'ant-design:menu-unfold-outlined'"
class="hover:cursor-pointer"
:size="24"
@click="activeTrigger"
/>
</NSpace>
</template>
</LayoutHeader>
</slot>
</NLayoutHeader>
<NLayout :content-style="contentStyle">
<NLayoutContent ref="contentRef" :content-style="mainStyle">
<LayoutMain>
<slot name="main" />
</LayoutMain>
</NLayoutContent>
<NLayoutFooter v-if="getShowFooter" ref="footerRef">
<slot name="footer">
<LayoutFooter />
</slot>
</NLayoutFooter>
</NLayout>
</NLayout>
</template>

@ -108,10 +108,10 @@ statusMapRef.set(ExceptionEnum.NET_WORK_ERROR, {
</NResult>
</template>
<style lang="less" scoped>
<style scoped>
.exception-page {
display: flex;
align-items: center;
flex-direction: column;
display: flex;
align-items: center;
flex-direction: column;
}
</style>

@ -10,16 +10,21 @@ import { initRouter, setupRouterGuards } from './modules/router/router'
import { setupPWA } from './modules/pwa'
import 'virtual:svg-icons-register'
let meta = document.createElement('meta')
meta.name = 'naive-ui-style'
document.head.appendChild(meta)
meta = document.createElement('meta')
meta.name = 'vueuc-style'
document.head.appendChild(meta)
; (async () => {
// TODO loadingApp
{
const meta = document.createElement('meta')
meta.name = 'naive-ui-style'
document.head.appendChild(meta)
}
{
const meta = document.createElement('meta')
meta.name = 'vueuc-style'
document.head.appendChild(meta)
}
;
(async () => {
// loadingApp
const appLoading = createApp(AppLoading)
// setupPinia(appLoading)
// setup I18n

@ -10,7 +10,6 @@ useHead({
<template>
<div>
<NInput />
<LIcon icon="nl-net-error" />
<div>placeholder</div>
<div>placeholder</div>
<div>placeholder</div>
@ -80,3 +79,18 @@ meta:
order: 1
icon: carbon-home
</route>
<style lang="less" scoped>
.setting-btn {
background: var(--card-color);
display: inline-flex;
align-items: center;
justify-content: center;
flex-direction: column;
cursor: pointer;
border-radius: 50%;
width: 48px;
height: 48px;
color: var(--card-color);
}
</style>

@ -25,7 +25,7 @@ export const projectSetting: DefineAppConfigOptions = {
closeMessageOnSwitch: false,
removeAllHttpPending: true,
// permissionCacheType: CacheTypeEnum.LOCAL,
settingButtonPosition: SettingButtonPositionEnum.AUTO,
settingButtonPosition: [SettingButtonPositionEnum.FIXED, SettingButtonPositionEnum.HEADER],
openSettingDrawer: false,
permissionMode: PermissionModeEnum.PERM,
sessionTimeoutProcessing: SessionTimeoutProcessingEnum.ROUTE_JUMP,
@ -40,7 +40,7 @@ export const projectSetting: DefineAppConfigOptions = {
show: true,
visible: true,
fixed: false,
width: 210,
width: 230,
mixSidebarWidth: 80,
collapsedWidth: 48,
collapsed: false,
@ -60,10 +60,10 @@ export const projectSetting: DefineAppConfigOptions = {
subMenuWidth: 0,
},
header: {
theme: ThemeEnum.DARK,
theme: ThemeEnum.LIGHT,
show: true,
visible: true,
fixed: false,
fixed: true,
height: 48,
showDoc: true,
showBreadCrumb: true,

@ -21,7 +21,7 @@ const initState: ThemeStoreState = {
},
theme: ThemeEnum.LIGHT,
sidebar: ThemeEnum.DARK,
header: ThemeEnum.DARK,
header: ThemeEnum.LIGHT,
}
export const useThemeStore = defineStore('APP_THEME', () => {

@ -40,7 +40,7 @@ declare global {
// Permission mode
permissionMode: PermissionModeEnum
// Configure where the button is displayed
settingButtonPosition: SettingButtonPositionEnum
settingButtonPosition: SettingButtonPositionEnum[]
// Configuration setting drawer open
openSettingDrawer: boolean
// Session timeout processing

Loading…
Cancel
Save