1
This commit is contained in:
163
app/src/components/TheContextMenu/index.vue
Normal file
163
app/src/components/TheContextMenu/index.vue
Normal file
@ -0,0 +1,163 @@
|
||||
<template>
|
||||
<div v-if="uiStore.contextMenu.isOpen" class="context-menu-overlay" @click="close" @contextmenu.prevent="close">
|
||||
<div class="context-menu" :style="menuStyle">
|
||||
<ul v-if="uiStore.contextMenu.itemType === 'icon'">
|
||||
<li><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="menu-icon"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15 3 21 3 21 9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>在新标签页打开</li>
|
||||
<li><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="menu-icon"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"></path><path d="m15 5 4 4"></path></svg>编辑图标</li>
|
||||
<li><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="menu-icon"><path d="m12 19-7-7 7-7 7 7-7 7Z"></path><path d="M19 5v14"></path><path d="M5 5v14"></path></svg>编辑主页</li>
|
||||
<li @click="deleteItem"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="menu-icon"><path d="M3 6h18"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>删除</li>
|
||||
</ul>
|
||||
<ul v-else-if="uiStore.contextMenu.itemType === 'widget'">
|
||||
<li class="layout-section">
|
||||
<div class="layout-title">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="menu-icon"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"></rect><line x1="3" y1="9" x2="21" y2="9"></line><line x1="9" y1="21" x2="9" y2="9"></line></svg>
|
||||
<span>布局</span>
|
||||
</div>
|
||||
<div class="widget-size-options">
|
||||
<span v-for="size in widgetSizes" :key="size" @click="changeWidgetSize(size)" class="size-option">{{ size }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<li><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="menu-icon"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"></path></svg>编辑组件</li>
|
||||
<li @click="deleteItem"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="menu-icon"><path d="M3 6h18"></path><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"></path><path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path></svg>删除</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { useUIStore } from '@/store/useUIStore';
|
||||
import { useLayoutStore } from '@/store/useLayoutStore';
|
||||
import { useWidgetsStore } from '@/store/useWidgetsStore';
|
||||
|
||||
const uiStore = useUIStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
const widgetsStore = useWidgetsStore();
|
||||
|
||||
const widgetSizes = ['1x1', '1x2', '2x1', '2x2', '2x4'];
|
||||
|
||||
const menuStyle = computed(() => ({
|
||||
left: `${uiStore.contextMenu.x}px`,
|
||||
top: `${uiStore.contextMenu.y}px`,
|
||||
}));
|
||||
|
||||
const close = () => {
|
||||
uiStore.closeContextMenu();
|
||||
};
|
||||
|
||||
const deleteItem = () => {
|
||||
if (uiStore.contextMenu.itemId) {
|
||||
if (uiStore.contextMenu.itemType === 'icon') {
|
||||
layoutStore.deleteIcon(uiStore.contextMenu.itemId);
|
||||
} else if (uiStore.contextMenu.itemType === 'widget') {
|
||||
// 组件删除逻辑
|
||||
}
|
||||
}
|
||||
close();
|
||||
};
|
||||
|
||||
const changeWidgetSize = (newSize: '1x1' | '1x2' | '2x1' | '2x2' | '2x4') => {
|
||||
if (uiStore.contextMenu.itemId) {
|
||||
widgetsStore.updateWidgetSize(uiStore.contextMenu.itemId, newSize);
|
||||
}
|
||||
close();
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/tokens.scss';
|
||||
|
||||
.context-menu-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
z-index: $z-index-menu - 1;
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
position: absolute;
|
||||
width: var(--context-menu-width);
|
||||
background-color: $color-surface-2;
|
||||
backdrop-filter: blur($backdrop-filter-blur) saturate($backdrop-filter-saturation);
|
||||
border-radius: $border-radius-medium;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
box-shadow: $shadow-lg;
|
||||
z-index: $z-index-menu;
|
||||
padding: var(--context-menu-padding);
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: var(--context-menu-item-padding-y) var(--context-menu-item-padding-x);
|
||||
border-radius: $border-radius-small;
|
||||
cursor: pointer;
|
||||
color: $color-text-primary;
|
||||
font-size: 14px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
|
||||
&.layout-section {
|
||||
padding: var(--context-menu-layout-section-padding-y) var(--context-menu-layout-section-padding-x);
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
cursor: default;
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li:last-child {
|
||||
color: #ff5c5c; // 删除项浅红色
|
||||
|
||||
.menu-icon {
|
||||
stroke: #ff5c5c;
|
||||
}
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
margin-right: var(--context-menu-icon-margin-right);
|
||||
width: var(--context-menu-icon-size);
|
||||
height: var(--context-menu-icon-size);
|
||||
}
|
||||
}
|
||||
|
||||
.layout-title {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
margin-bottom: var(--context-menu-layout-title-margin-bottom);
|
||||
}
|
||||
|
||||
.widget-size-options {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--context-menu-layout-options-gap);
|
||||
|
||||
.size-option {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: var(--context-menu-layout-option-width); // 固定宽度便于对齐
|
||||
padding: var(--context-menu-layout-option-padding-y) 0; // 固定宽度下调整内边距
|
||||
border-radius: var(--radius-pill); // 胶囊形状
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user