2025-03-28 08:50:40 +08:00

150 lines
3.2 KiB
Vue

<script setup lang="ts">
import { useI18n } from "vue-i18n";
import { emitter } from "@/utils/mitt";
import { onClickOutside } from "@vueuse/core";
import { ref, computed, onMounted, onBeforeUnmount } from "vue";
import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
import CloseIcon from "~icons/ep/close";
const target = ref(null);
const show = ref<Boolean>(false);
const iconClass = computed(() => {
return [
"w-[22px]",
"h-[22px]",
"flex",
"justify-center",
"items-center",
"outline-hidden",
"rounded-[4px]",
"cursor-pointer",
"transition-colors",
"hover:bg-[#0000000f]",
"dark:hover:bg-[#ffffff1f]",
"dark:hover:text-[#ffffffd9]"
];
});
const { t } = useI18n();
const { onReset } = useDataThemeChange();
onClickOutside(target, (event: any) => {
if (event.clientX > target.value.offsetLeft) return;
show.value = false;
});
onMounted(() => {
emitter.on("openPanel", () => {
show.value = true;
});
});
onBeforeUnmount(() => {
// 解绑`openPanel`公共事件,防止多次触发
emitter.off("openPanel");
});
</script>
<template>
<div :class="{ show }">
<div class="right-panel-background" />
<div ref="target" class="right-panel bg-bg_color">
<div
class="project-configuration border-b-[1px] border-solid border-[var(--pure-border-color)]"
>
<h4 class="dark:text-white">
{{ t("panel.pureSystemSet") }}
</h4>
<span
v-tippy="{
content: t('panel.pureCloseSystemSet'),
placement: 'bottom-start',
zIndex: 41000
}"
:class="iconClass"
>
<IconifyIconOffline
class="dark:text-white"
width="18px"
height="18px"
:icon="CloseIcon"
@click="show = !show"
/>
</span>
</div>
<el-scrollbar>
<slot />
</el-scrollbar>
<div
class="flex justify-end p-3 border-t-[1px] border-solid border-[var(--pure-border-color)]"
>
<el-button
v-tippy="{
content: t('panel.pureClearCacheAndToLogin'),
placement: 'left-start',
zIndex: 41000
}"
type="danger"
text
bg
@click="onReset"
>
{{ t("panel.pureClearCache") }}
</el-button>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
:deep(.el-scrollbar) {
height: calc(100vh - 110px);
}
.right-panel-background {
position: fixed;
top: 0;
left: 0;
z-index: -1;
background: rgb(0 0 0 / 20%);
opacity: 0;
transition: opacity 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
}
.right-panel {
position: fixed;
top: 0;
right: 0;
z-index: 40000;
width: 100%;
max-width: 280px;
box-shadow: 0 0 15px 0 rgb(0 0 0 / 5%);
transform: translate(100%);
transition: all 0.25s cubic-bezier(0.7, 0.3, 0.1, 1);
}
.show {
transition: all 0.3s cubic-bezier(0.7, 0.3, 0.1, 1);
.right-panel-background {
z-index: 20000;
width: 100%;
height: 100%;
opacity: 1;
}
.right-panel {
transform: translate(0);
}
}
.project-configuration {
display: flex;
align-items: center;
justify-content: space-between;
padding: 14px 20px;
}
</style>