wip(Layout): Layout developing

This commit is contained in:
陈凯龙 2022-01-13 17:26:06 +08:00
parent 66e8d0e41c
commit 2fe9543b84
27 changed files with 282 additions and 35 deletions

View File

@ -41,6 +41,7 @@ specifiers:
pretty-quick: ^3.1.3
qs: ^6.10.3
rimraf: ^3.0.2
screenfull: ^6.0.0
stylelint: ^14.2.0
stylelint-config-html: ^1.0.0
stylelint-config-prettier: ^9.0.3
@ -75,6 +76,7 @@ dependencies:
nprogress: registry.npmmirror.com/nprogress/0.2.0
pinia: registry.npmmirror.com/pinia/2.0.9_typescript@4.5.4+vue@3.2.26
qs: registry.npmmirror.com/qs/6.10.3
screenfull: registry.npmmirror.com/screenfull/6.0.0
vue: registry.npmmirror.com/vue/3.2.26
vue-i18n: registry.npmmirror.com/vue-i18n/9.1.9_vue@3.2.26
vue-router: registry.npmmirror.com/vue-router/4.0.12_vue@3.2.26
@ -7064,8 +7066,8 @@ packages:
vue-i18n:
optional: true
dependencies:
'@intlify/message-compiler': registry.npmmirror.com/@intlify/message-compiler/9.2.0-beta.26
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.26
'@intlify/message-compiler': registry.npmmirror.com/@intlify/message-compiler/9.2.0-beta.27
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.27
jsonc-eslint-parser: registry.npmmirror.com/jsonc-eslint-parser/1.4.1
source-map: registry.nlark.com/source-map/0.6.1
vue-i18n: registry.npmmirror.com/vue-i18n/9.1.9_vue@3.2.26
@ -7121,18 +7123,18 @@ packages:
source-map: registry.nlark.com/source-map/0.6.1
dev: false
registry.npmmirror.com/@intlify/message-compiler/9.2.0-beta.26:
registry.npmmirror.com/@intlify/message-compiler/9.2.0-beta.27:
resolution:
{
integrity: sha512-qtDgHCMqrXNTekKXGzm0Dm6r3+/X7/jFXP+E07hx+PJbPMv7DzK1iU8h5LlAMQ1/jr2UIRBgXvR5wh35OKoGrA==,
integrity: sha512-T3mBTm0559VX6l+lh8p5gDJ9/IS1XbVXeeMNJ2zTzxrf4lXg8OuotNjaxG3ZsuauQ5OqqlArkMYryXGyZnHolA==,
registry: https://registry.npm.taobao.org/,
tarball: https://registry.npmmirror.com/@intlify/message-compiler/download/@intlify/message-compiler-9.2.0-beta.26.tgz
tarball: https://registry.npmmirror.com/@intlify/message-compiler/download/@intlify/message-compiler-9.2.0-beta.27.tgz
}
name: '@intlify/message-compiler'
version: 9.2.0-beta.26
version: 9.2.0-beta.27
engines: { node: '>= 12' }
dependencies:
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.26
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.27
source-map: registry.nlark.com/source-map/0.6.1
dev: true
@ -7176,15 +7178,15 @@ packages:
engines: { node: '>= 10' }
dev: false
registry.npmmirror.com/@intlify/shared/9.2.0-beta.26:
registry.npmmirror.com/@intlify/shared/9.2.0-beta.27:
resolution:
{
integrity: sha512-MjUlkjNThqkqy8yXUcFKBiW/hIfqAn5cP3Vd0b4wdOHS8rPCEbvSbAnF08uiZDkVv8gTcsLyymX21GaU6oYyyQ==,
integrity: sha512-+Av77mIHy0qFkAq96mMAQGYcColMGN7e5+rUsyn3XxBw6oC3AGqYn/cQ6U/T3qOrzcHgcA+etAaLN3IxFqkJDw==,
registry: https://registry.npm.taobao.org/,
tarball: https://registry.npmmirror.com/@intlify/shared/download/@intlify/shared-9.2.0-beta.26.tgz
tarball: https://registry.npmmirror.com/@intlify/shared/download/@intlify/shared-9.2.0-beta.27.tgz
}
name: '@intlify/shared'
version: 9.2.0-beta.26
version: 9.2.0-beta.27
engines: { node: '>= 12' }
dev: true
@ -7210,7 +7212,7 @@ packages:
optional: true
dependencies:
'@intlify/bundle-utils': registry.npmmirror.com/@intlify/bundle-utils/2.2.0_vue-i18n@9.1.9
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.26
'@intlify/shared': registry.npmmirror.com/@intlify/shared/9.2.0-beta.27
'@rollup/pluginutils': registry.npmmirror.com/@rollup/pluginutils/4.1.2
debug: registry.npmmirror.com/debug/4.3.3
fast-glob: registry.nlark.com/fast-glob/3.2.7
@ -11607,6 +11609,18 @@ packages:
tslib: registry.npmmirror.com/tslib/2.3.1
dev: true
registry.npmmirror.com/screenfull/6.0.0:
resolution:
{
integrity: sha512-LGY0nhNQkC4FX4DT4pZdJ5cZH5EOz9Gfh9KcVMl779pS677k4IV1Wv7sY/CwC9VKFT21fYgCh7zkTVVefi5XKA==,
registry: https://registry.npm.taobao.org/,
tarball: https://registry.npmmirror.com/screenfull/download/screenfull-6.0.0.tgz
}
name: screenfull
version: 6.0.0
engines: { node: ^14.13.1 || >=16.0.0 }
dev: false
registry.npmmirror.com/shebang-regex/3.0.0:
resolution:
{

View File

@ -32,6 +32,7 @@ html,
body {
padding: 0;
margin: 0;
overflow: hidden;
.size;
#app {

BIN
src/assets/imgs/avatar.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,3 @@
import Breadcrumb from './src/Breadcrumb.vue'
export { Breadcrumb }

View File

@ -0,0 +1,3 @@
import Collapse from './src/Collapse.vue'
export { Collapse }

View File

@ -0,0 +1,25 @@
<script setup lang="ts">
import { computed, unref } from 'vue'
import { Icon } from '@/components/Icon'
import { useAppStore } from '@/store/modules/app'
const appStore = useAppStore()
const collapse = computed(() => appStore.getCollapse)
function toggleCollapse() {
const collapsed = unref(collapse)
appStore.setCollapse(!collapsed)
}
</script>
<template>
<div>
<Icon
:size="18"
:icon="collapse ? 'ant-design:menu-unfold-outlined' : 'ant-design:menu-fold-outlined'"
class="cursor-pointer"
@click="toggleCollapse"
/>
</div>
</template>

View File

@ -25,6 +25,7 @@ function setLang(lang: LocaleType) {
<template>
<ElDropdown trigger="click" @command="setLang">
<Icon
:size="18"
icon="ion:language-sharp"
color="var(--el-text-color-primary)"
class="cursor-pointer"

View File

@ -22,8 +22,8 @@ export default defineComponent({
const preFixCls = getPrefixCls('menu')
const menuMode = computed(() => {
//
const menuMode = computed((): 'vertical' | 'horizontal' => {
//
const vertical: LayoutType[] = ['classic']
if (vertical.includes(appStore.getLayout)) {
@ -77,7 +77,7 @@ export default defineComponent({
>
{{
default: () => {
const { renderMenuItem } = useRenderMenuItem(routers.value)
const { renderMenuItem } = useRenderMenuItem(routers.value, menuMode.value)
return renderMenuItem()
}
}}
@ -93,7 +93,10 @@ export default defineComponent({
@prefix-cls: ~'@{namespace}-menu';
.@{prefix-cls} {
transition: width var(--transition-time-02);
:deep(.el-menu) {
width: 100% !important;
border-right: none;
//
@ -132,8 +135,55 @@ export default defineComponent({
}
}
//
:deep(.el-menu--collapse) {
width: var(--left-menu-min-width);
& > .is-active,
& > .is-active > .el-sub-menu__title {
background-color: var(--left-menu-collapse-bg-active-color) !important;
}
}
//
:deep(.horizontal-collapse-transition) {
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out !important;
.@{prefix-cls}__title {
display: none;
}
}
}
</style>
<style lang="less">
@prefix-cls: ~'@{namespace}-menu-popper';
.@{prefix-cls} {
&--vertical {
//
.is-active {
& > .el-sub-menu__title {
color: var(--left-menu-text-active-color) !important;
}
}
//
.el-sub-menu__title,
.el-menu-item {
&:hover {
color: var(--left-menu-text-active-color) !important;
background-color: var(--left-menu-bg-color) !important;
}
}
//
.el-menu-item.is-active {
background-color: var(--left-menu-bg-active-color) !important;
&:hover {
background-color: var(--left-menu-bg-active-color) !important;
}
}
}
}
</style>

View File

@ -3,8 +3,13 @@ import type { RouteMeta } from 'vue-router'
import { getAllParentPath, hasOneShowingChild } from '../helper'
import { isUrl } from '@/utils/is'
import { useRenderMenuTitle } from './useRenderMenuTitle'
import { useDesign } from '@/hooks/web/useDesign'
import { pathResolve } from '@/utils/routerHelper'
export function useRenderMenuItem(allRouters: AppRouteRecordRaw[] = []) {
export function useRenderMenuItem(
allRouters: AppRouteRecordRaw[] = [],
menuMode: 'vertical' | 'horizontal'
) {
function renderMenuItem(routers?: AppRouteRecordRaw[]) {
return (routers || allRouters).map((v) => {
const meta = (v.meta ?? {}) as RouteMeta
@ -23,15 +28,23 @@ export function useRenderMenuItem(allRouters: AppRouteRecordRaw[] = []) {
!meta?.alwaysShow
) {
return (
<ElMenuItem index={fullPath}>
<ElMenuItem index={onlyOneChild ? pathResolve(fullPath, onlyOneChild.path) : fullPath}>
{{
default: () => renderMenuTitle(meta)
default: () => renderMenuTitle(onlyOneChild ? onlyOneChild?.meta : meta)
}}
</ElMenuItem>
)
} else {
const { getPrefixCls } = useDesign()
const preFixCls = getPrefixCls('menu-popper')
return (
<ElSubMenu index={fullPath}>
<ElSubMenu
index={fullPath}
popperClass={
menuMode === 'vertical' ? `${preFixCls}--vertical` : `${preFixCls}--horizontal`
}
>
{{
title: () => renderMenuTitle(meta),
default: () => renderMenuItem(v.children)

View File

@ -10,10 +10,10 @@ export function useRenderMenuTitle() {
return icon ? (
<>
<Icon icon={meta.icon}></Icon>
{t(title as string)}
<span>{t(title as string)}</span>
</>
) : (
t(title as string)
<span>{t(title as string)}</span>
)
}

View File

@ -0,0 +1,3 @@
import Screenfull from './src/Screenfull.vue'
export { Screenfull }

View File

@ -0,0 +1,16 @@
<script setup lang="ts">
import { Icon } from '@/components/Icon'
import { useFullscreen } from '@vueuse/core'
const { toggle, isFullscreen } = useFullscreen()
function toggleFullscreen() {
toggle()
}
</script>
<template>
<div @click="toggleFullscreen">
<Icon :size="18" :icon="isFullscreen ? 'zmdi:fullscreen-exit' : 'zmdi:fullscreen'" />
</div>
</template>

View File

@ -16,7 +16,12 @@ function setSize(size: ElememtPlusSzie) {
<template>
<ElDropdown trigger="click" @command="setSize">
<Icon icon="mdi:format-size" color="var(--el-text-color-primary)" class="cursor-pointer" />
<Icon
:size="18"
icon="mdi:format-size"
color="var(--el-text-color-primary)"
class="cursor-pointer"
/>
<template #dropdown>
<ElDropdownMenu>
<ElDropdownItem v-for="item in sizeMap" :key="item" :command="item">

View File

@ -0,0 +1,3 @@
import UserInfo from './src/UserInfo.vue'
export { UserInfo }

View File

@ -0,0 +1,46 @@
<script setup lang="ts">
import { ElDropdown, ElDropdownMenu, ElDropdownItem, ElMessageBox } from 'element-plus'
import { useI18n } from '@/hooks/web/useI18n'
import { useCache } from '@/hooks/web/useCache'
import { resetRouter } from '@/router'
import { useRouter } from 'vue-router'
const { t } = useI18n()
const { wsCache } = useCache()
const { replace } = useRouter()
function loginOut() {
ElMessageBox.confirm(t('common.loginOutMessage'), t('common.reminder'), {
confirmButtonText: t('common.ok'),
cancelButtonText: t('common.cancel'),
type: 'warning'
})
.then(() => {
wsCache.clear()
resetRouter() //
replace('/login')
})
.catch(() => {})
}
</script>
<template>
<ElDropdown trigger="click">
<div class="flex items-center">
<img src="@/assets/imgs/avatar.png" alt="" class="w-[calc(var(--tags-view-height)-10px)]" />
<span class="<lg:hidden text-14px pl-[5px] text-dark-50">Archer</span>
</div>
<template #dropdown>
<ElDropdownMenu>
<ElDropdownItem>
<div>{{ t('common.document') }}</div>
</ElDropdownItem>
<ElDropdownItem divided>
<div @click="loginOut">{{ t('common.loginOut') }}</div>
</ElDropdownItem>
</ElDropdownMenu>
</template>
</ElDropdown>
</template>

View File

@ -4,6 +4,11 @@ import { useTagsViewStore } from '@/store/modules/tagsView'
import { useAppStore } from '@/store/modules/app'
import { Menu } from '@/components/Menu'
import { useDesign } from '@/hooks/web/useDesign'
import { Collapse } from '@/components/Collapse'
import { LocaleDropdown } from '@/components/LocaleDropdown'
import { SizeDropdown } from '@/components/SizeDropdown'
import { UserInfo } from '@/components/UserInfo'
import { Screenfull } from '@/components/Screenfull'
// import { TagsView } from '@/components/TagsView'
const tagsViewStore = useTagsViewStore()
@ -43,10 +48,18 @@ export default defineComponent({
<div
class={[
`${perFixCls}-right__tool`,
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center'
'h-[var(--top-tool-height)] relative px-[var(--top-tool-p-x)] flex items-center justify-between'
]}
>
ssss
<div class="h-full flex items-center">
<Collapse class="header__tigger"></Collapse>
</div>
<div class="h-full flex items-center">
<Screenfull class="header__tigger"></Screenfull>
<SizeDropdown class="header__tigger"></SizeDropdown>
<LocaleDropdown class="header__tigger"></LocaleDropdown>
<UserInfo class="header__tigger"></UserInfo>
</div>
</div>
<router-view>
{{
@ -67,8 +80,23 @@ export default defineComponent({
<style lang="less" scoped>
@prefix-cls: ~'@{namespace}-app';
.header__tigger {
display: flex;
height: 100%;
padding: 1px 10px 0;
cursor: pointer;
align-items: center;
transition: background var(--transition-time-02);
&:hover {
background-color: #f6f6f6;
}
}
.@{prefix-cls} {
&-right {
transition: left var(--transition-time-02);
&__tool {
&::after {
position: absolute;

View File

@ -5,7 +5,13 @@ export default {
startTimeText: 'Start time',
endTimeText: 'End time',
login: 'Login',
required: 'This is required'
required: 'This is required',
loginOut: 'Login out',
document: 'Document',
reminder: 'Reminder',
loginOutMessage: 'Exit the system',
ok: 'OK',
cancel: 'Cancel'
},
size: {
default: 'Default',

View File

@ -5,7 +5,13 @@ export default {
startTimeText: '开始时间',
endTimeText: '结束时间',
login: '登录',
required: '该项为必填项'
required: '该项为必填项',
loginOut: '退出系统',
document: '项目文档',
reminder: '温馨提示',
loginOutMessage: '是否退出本系统?',
ok: '确定',
cancel: '取消'
},
size: {
default: '默认',

View File

@ -94,6 +94,23 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
}
}
]
},
{
path: '/icon',
component: Layout,
name: 'IconsDemo',
meta: {},
children: [
{
path: 'index',
component: () => import('@/views/Level/Menu2.vue'),
name: 'Icons',
meta: {
title: '图标',
icon: 'carbon:skill-level-advanced'
}
}
]
}
]

View File

@ -1,6 +1,7 @@
:root {
--dark-bg-color: #293146;
/* left menu start */
--left-menu-max-width: 200px;
--left-menu-min-width: 64px;
@ -15,11 +16,16 @@
--left-menu-text-active-color: #fff;
--left-menu-collapse-bg-active-color: var(--el-color-primary);
/* left menu end */
--top-tool-height: 40px;
--top-tool-p-x: 20px;
--top-tool-p-x: 0;
--top-tool-border-color: #eee;
--tags-view-height: 40px;
--transition-time-02: 0.2s;
}

View File

@ -149,7 +149,3 @@ function subtractLight(color: string, amount: number) {
const c = cc < 0 ? 0 : cc
return c.toString(16).length > 1 ? c.toString(16) : `0${c.toString(16)}`
}
export function setCssVar(prop: string, val: any, dom = document.documentElement) {
dom.style.setProperty(prop, val)
}

View File

@ -34,3 +34,7 @@ export function underlineToHump(str: string): string {
return letter.toUpperCase()
})
}
export function setCssVar(prop: string, val: any, dom = document.documentElement) {
dom.style.setProperty(prop, val)
}

View File

@ -122,7 +122,8 @@ export function generateRoutesFn2(routes: AppRouteRecordRaw[]): AppRouteRecordRa
}
export function pathResolve(parentPath: string, path: string) {
return `${parentPath}/${path}`
const childPath = path.startsWith('/') || !path ? path : `/${path}`
return `${parentPath}${childPath}`
}
// 路由降级

View File

@ -1,5 +1,5 @@
<script setup lang="ts"></script>
<template>
<div>Menu111</div>
<div>Menu111 <input type="text" /></div>
</template>

View File

@ -1,5 +1,5 @@
<script setup lang="ts"></script>
<template>
<div>Menu12</div>
<div>Menu12 <input type="text" /></div>
</template>

View File

@ -1,5 +1,5 @@
<script setup lang="ts"></script>
<template>
<div>Menu2</div>
<div>Menu2 <input type="text" /></div>
</template>