菜单设置、主题设置、深色模式切换、磁贴小demo
Frontend CI/CD / build (web-office) (push) Failing after 16s Details

This commit is contained in:
hujiale 2024-10-11 19:24:37 +08:00
parent 154c104148
commit 3a72fb8a4b
22 changed files with 1748 additions and 67 deletions

View File

@ -1,9 +1,10 @@
<script lang="ts" setup>
import { computed, useSlots } from 'vue';
import { computed, useSlots, ref } from 'vue';
import { preferences, usePreferences } from '@vben/preferences';
import { preferences, usePreferences, updatePreferences } from '@vben/preferences';
import { useAccessStore } from '@vben/stores';
import VbenFullScreen from './../../full-screen/full-screen.vue';
import VbenFullScreen from './../../full-screen/full-screen.vue';
import {
LanguageToggle,
@ -95,22 +96,29 @@ const leftSlots = computed(() => {
function clearPreferencesAndLogout() {
emit('clearPreferencesAndLogout');
}
let themeSwitch = ref(preferences.theme.mode == 'dark');
let themeChange = () => {
themeSwitch.value = !themeSwitch.value;
updatePreferences({
theme: {
mode: themeSwitch.value ? 'dark' : 'light'
}
})
console.log(preferences.app.layout,'????');
}
</script>
<template>
<template
v-for="slot in leftSlots.filter((item) => item.index < 5)"
:key="slot.name"
>
<template v-for="slot in leftSlots.filter((item) => item.index < 5)" :key="slot.name">
<slot :name="slot.name"></slot>
</template>
<div class="flex-center hidden lg:block">
<slot name="breadcrumb"></slot>
</div>
<template
v-for="slot in leftSlots.filter((item) => item.index > 5)"
:key="slot.name"
>
<template v-for="slot in leftSlots.filter((item) => item.index > 5)" :key="slot.name">
<slot :name="slot.name"></slot>
</template>
<div class="flex h-full min-w-0 flex-1 items-center">
@ -123,10 +131,7 @@ function clearPreferencesAndLogout() {
</template>
<template v-else-if="slot.name === 'preferences'">
<PreferencesButton
class="mr-1"
@clear-preferences-and-logout="clearPreferencesAndLogout"
/>
<PreferencesButton class="mr-1" @clear-preferences-and-logout="clearPreferencesAndLogout" />
</template>
<template v-else-if="slot.name === 'theme-toggle'">
<ThemeToggle class="mr-1 mt-[2px]" />
@ -139,5 +144,136 @@ function clearPreferencesAndLogout() {
</template>
</slot>
</template>
<div class="mr-2 scale-75">
<label class="switch">
<span class="sun"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g fill="#ffd43b">
<circle r="5" cy="12" cx="12"></circle>
<path
d="m21 13h-1a1 1 0 0 1 0-2h1a1 1 0 0 1 0 2zm-17 0h-1a1 1 0 0 1 0-2h1a1 1 0 0 1 0 2zm13.66-5.66a1 1 0 0 1 -.66-.29 1 1 0 0 1 0-1.41l.71-.71a1 1 0 1 1 1.41 1.41l-.71.71a1 1 0 0 1 -.75.29zm-12.02 12.02a1 1 0 0 1 -.71-.29 1 1 0 0 1 0-1.41l.71-.66a1 1 0 0 1 1.41 1.41l-.71.71a1 1 0 0 1 -.7.24zm6.36-14.36a1 1 0 0 1 -1-1v-1a1 1 0 0 1 2 0v1a1 1 0 0 1 -1 1zm0 17a1 1 0 0 1 -1-1v-1a1 1 0 0 1 2 0v1a1 1 0 0 1 -1 1zm-5.66-14.66a1 1 0 0 1 -.7-.29l-.71-.71a1 1 0 0 1 1.41-1.41l.71.71a1 1 0 0 1 0 1.41 1 1 0 0 1 -.71.29zm12.02 12.02a1 1 0 0 1 -.7-.29l-.66-.71a1 1 0 0 1 1.36-1.36l.71.71a1 1 0 0 1 0 1.41 1 1 0 0 1 -.71.24z">
</path>
</g>
</svg></span>
<span class="moon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512">
<path
d="m223.5 32c-123.5 0-223.5 100.3-223.5 224s100 224 223.5 224c60.6 0 115.5-24.2 155.8-63.4 5-4.9 6.3-12.5 3.1-18.7s-10.1-9.7-17-8.5c-9.8 1.7-19.8 2.6-30.1 2.6-96.9 0-175.5-78.8-175.5-176 0-65.8 36-123.1 89.3-153.3 6.1-3.5 9.2-10.5 7.7-17.3s-7.3-11.9-14.3-12.5c-6.3-.5-12.6-.8-19-.8z">
</path>
</svg></span>
<input type="checkbox" class="input" :checked="themeSwitch" @change="themeChange">
<span class="slider"></span>
</label>
</div>
</div>
</template>
<style>
/* From Uiverse.io by andrew-demchenk0 */
.switch {
font-size: 17px;
position: relative;
display: inline-block;
width: 64px;
height: 34px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #73C0FC;
transition: .4s;
border-radius: 30px;
}
.slider:before {
position: absolute;
content: "";
height: 30px;
width: 30px;
border-radius: 20px;
left: 2px;
bottom: 2px;
z-index: 2;
background-color: #e8e8e8;
transition: .4s;
}
.sun svg {
position: absolute;
top: 6px;
left: 36px;
z-index: 1;
width: 24px;
height: 24px;
}
.moon svg {
fill: #73C0FC;
position: absolute;
top: 5px;
left: 5px;
z-index: 1;
width: 24px;
height: 24px;
}
/* .switch:hover */.sun svg {
animation: rotate 15s linear infinite;
}
@keyframes rotate {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
/* .switch:hover */.moon svg {
animation: tilt 5s linear infinite;
}
@keyframes tilt {
0% {
transform: rotate(0deg);
}
25% {
transform: rotate(-10deg);
}
75% {
transform: rotate(10deg);
}
100% {
transform: rotate(0deg);
}
}
.input:checked + .slider {
background-color: #183153;
}
.input:focus + .slider {
box-shadow: 0 0 1px #183153;
}
.input:checked + .slider:before {
transform: translateX(30px);
}
</style>

View File

@ -137,7 +137,7 @@ const {sidebarCollapsed } = usePreferences();
</span>
<span v-else></span>
</div>
<div v-else class="rounded-full w100% flex justify-center">
<div v-else class="rounded-full w100% flex justify-center cursor-pointer" @click="toggleOpen()">
<Search class="text-muted-foreground group-hover:text-foreground size-4 group-hover:opacity-100" />
</div>
</div>

View File

@ -0,0 +1,141 @@
<script setup lang="ts">
import type { BuiltinThemeType } from '@vben/types';
import { computed, ref } from 'vue';
import { UserRoundPen } from '@vben/icons';
import { $t } from '@vben/locales';
import {
BUILT_IN_THEME_PRESETS,
type BuiltinThemePreset,
} from '@vben/preferences';
import { convertToHsl, TinyColor } from '@vben/utils';
defineOptions({
name: 'PreferenceBuiltinTheme',
});
const props = defineProps<{ isDark: boolean }>();
const colorInput = ref();
const modelValue = defineModel<BuiltinThemeType>({ default: 'default' });
const themeColorPrimary = defineModel<string>('themeColorPrimary');
const inputValue = computed(() => {
return new TinyColor(themeColorPrimary.value || '').toHexString();
});
const builtinThemePresets = computed(() => {
return [...BUILT_IN_THEME_PRESETS];
});
function typeView(name: BuiltinThemeType) {
switch (name) {
case 'default': {
return $t('preferences.theme.builtin.default');
}
case 'violet': {
return $t('preferences.theme.builtin.violet');
}
case 'pink': {
return $t('preferences.theme.builtin.pink');
}
case 'rose': {
return $t('preferences.theme.builtin.rose');
}
case 'sky-blue': {
return $t('preferences.theme.builtin.skyBlue');
}
case 'deep-blue': {
return $t('preferences.theme.builtin.deepBlue');
}
case 'green': {
return $t('preferences.theme.builtin.green');
}
case 'deep-green': {
return $t('preferences.theme.builtin.deepGreen');
}
case 'orange': {
return $t('preferences.theme.builtin.orange');
}
case 'yellow': {
return $t('preferences.theme.builtin.yellow');
}
case 'zinc': {
return $t('preferences.theme.builtin.zinc');
}
case 'neutral': {
return $t('preferences.theme.builtin.neutral');
}
case 'slate': {
return $t('preferences.theme.builtin.slate');
}
case 'gray': {
return $t('preferences.theme.builtin.gray');
}
case 'custom': {
return $t('preferences.theme.builtin.custom');
}
}
}
function handleSelect(theme: BuiltinThemePreset) {
modelValue.value = theme.type;
const primaryColor = props.isDark
? theme.darkPrimaryColor || theme.primaryColor
: theme.primaryColor;
themeColorPrimary.value = primaryColor || theme.color;
}
function handleInputChange(e: Event) {
const target = e.target as HTMLInputElement;
themeColorPrimary.value = convertToHsl(target.value);
}
function selectColor() {
colorInput.value?.[0]?.click?.();
}
</script>
<template>
<div class="flex w-full flex-wrap justify-between">{{ }}
<template v-for="theme in builtinThemePresets" :key="theme.type">
<div class="flex cursor-pointer flex-col" @click="handleSelect(theme)">
<div
:class="{
'outline-box-active': theme.type === modelValue,
}"
class="outline-box flex-center group cursor-pointer"
>
<template v-if="theme.type !== 'custom'">
<div
:style="{ backgroundColor: theme.color }"
class="mx-10 my-2 size-5 rounded-md"
></div>
</template>
<template v-else>
<div class="size-full px-10 py-2" @click.stop="selectColor">
<div class="flex-center relative size-5 rounded-sm">
<UserRoundPen
class="absolute z-10 size-5 opacity-60 group-hover:opacity-100"
/>
<input
ref="colorInput"
:value="inputValue"
class="absolute inset-0 opacity-0"
type="color"
@input="handleInputChange"
/>
</div>
</div>
</template>
</div>
<div class="text-muted-foreground my-2 text-center text-xs">
{{ typeView(theme.type) }}
</div>
</div>
</template>
</div>
</template>

View File

@ -0,0 +1,119 @@
<template>
<svg
class="custom-radio-image"
fill="none"
height="66"
width="104"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<rect
id="svg_1"
fill="currentColor"
fill-opacity="0.02"
height="66"
rx="4"
stroke="null"
width="104"
x="0.13514"
y="0.13514"
/>
<rect
id="svg_8"
fill="hsl(var(--primary))"
height="9.07027"
stroke="null"
width="104.07934"
x="-0.07419"
y="-0.05773"
/>
<rect
id="svg_3"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="15.58168"
y="3.20832"
/>
<path
id="svg_12"
d="m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z"
fill="#ffffff"
opacity="undefined"
stroke="null"
/>
<rect
id="svg_13"
fill="currentColor"
fill-opacity="0.08"
height="21.51892"
rx="2"
stroke="null"
width="41.98275"
x="45.37589"
y="13.53192"
/>
<path
id="svg_14"
d="m16.4123,15.53192c0,-1.08676 0.74096,-2 1.62271,-2l21.74653,0c0.88175,0 1.62271,0.91324 1.62271,2l0,17.24865c0,1.08676 -0.74096,2 -1.62271,2l-21.74653,0c-0.88175,0 -1.62271,-0.91324 -1.62271,-2l0,-17.24865z"
fill="currentColor"
fill-opacity="0.08"
opacity="undefined"
stroke="null"
/>
<rect
id="svg_15"
fill="currentColor"
fill-opacity="0.08"
height="21.65405"
rx="2"
stroke="null"
width="71.10636"
x="16.54743"
y="39.34689"
/>
<rect
id="svg_21"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="28.14924"
y="3.07319"
/>
<rect
id="svg_22"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="41.25735"
y="3.20832"
/>
<rect
id="svg_23"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="54.23033"
y="3.07319"
/>
<rect
id="svg_4"
fill="#ffffff"
height="7.13843"
rx="2"
stroke="null"
width="7.78397"
x="1.5327"
y="0.881"
/>
</g>
</svg>
</template>

View File

@ -0,0 +1,50 @@
<template>
<svg
class="custom-radio-image"
fill="none"
height="66"
width="104"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<path
id="svg_1"
d="m0.13514,4.13514c0,-2.17352 1.82648,-4 4,-4l96,0c2.17352,0 4,1.82648 4,4l0,58c0,2.17352 -1.82648,4 -4,4l-96,0c-2.17352,0 -4,-1.82648 -4,-4l0,-58z"
fill="currentColor"
fill-opacity="0.02"
opacity="undefined"
stroke="null"
/>
<rect
id="svg_13"
fill="currentColor"
fill-opacity="0.08"
height="26.57155"
rx="2"
stroke="null"
width="53.18333"
x="45.79979"
y="3.77232"
/>
<path
id="svg_14"
d="m4.28142,5.96169c0,-1.37748 1.06465,-2.53502 2.33158,-2.53502l31.2463,0c1.26693,0 2.33158,1.15754 2.33158,2.53502l0,21.86282c0,1.37748 -1.06465,2.53502 -2.33158,2.53502l-31.2463,0c-1.26693,0 -2.33158,-1.15754 -2.33158,-2.53502l0,-21.86282z"
fill="currentColor"
fill-opacity="0.08"
opacity="undefined"
stroke="null"
/>
<rect
id="svg_15"
fill="currentColor"
fill-opacity="0.08"
height="25.02247"
rx="2"
stroke="null"
width="94.39371"
x="4.56735"
y="34.92584"
/>
</g>
</svg>
</template>

View File

@ -0,0 +1,119 @@
<template>
<svg
class="custom-radio-image"
fill="none"
height="66"
width="104"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<rect
id="svg_1"
fill="currentColor"
fill-opacity="0.02"
height="66"
rx="4"
stroke="null"
width="104"
x="0.13514"
y="0.13514"
/>
<rect
id="svg_8"
fill="hsl(var(--primary))"
height="9.07027"
stroke="null"
width="104.07934"
x="-0.07419"
y="-0.05773"
/>
<rect
id="svg_3"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="15.58168"
y="3.20832"
/>
<path
id="svg_12"
d="m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z"
fill="#ffffff"
opacity="undefined"
stroke="null"
/>
<rect
id="svg_13"
fill="currentColor"
fill-opacity="0.08"
height="21.51892"
rx="2"
stroke="null"
width="53.60438"
x="43.484"
y="13.66705"
/>
<path
id="svg_14"
d="m3.43932,15.53192c0,-1.08676 1.03344,-2 2.26323,-2l30.33036,0c1.22979,0 2.26323,0.91324 2.26323,2l0,17.24865c0,1.08676 -1.03344,2 -2.26323,2l-30.33036,0c-1.22979,0 -2.26323,-0.91324 -2.26323,-2l0,-17.24865z"
fill="currentColor"
fill-opacity="0.08"
opacity="undefined"
stroke="null"
/>
<rect
id="svg_15"
fill="currentColor"
fill-opacity="0.08"
height="21.65405"
rx="2"
stroke="null"
width="95.02528"
x="3.30419"
y="39.34689"
/>
<rect
id="svg_21"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="28.14924"
y="3.07319"
/>
<rect
id="svg_22"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="41.25735"
y="3.20832"
/>
<rect
id="svg_23"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="54.23033"
y="3.07319"
/>
<rect
id="svg_4"
fill="#ffffff"
height="7.13843"
rx="2"
stroke="null"
width="7.78397"
x="1.5327"
y="0.881"
/>
</g>
</svg>
</template>

View File

@ -0,0 +1,10 @@
import HeaderNav from './header-nav.vue';
export { default as ContentCompact } from './content-compact.vue';
export { default as FullContent } from './full-content.vue';
export { default as MixedNav } from './mixed-nav.vue';
export { default as SidebarMixedNav } from './sidebar-mixed-nav.vue';
export { default as SidebarNav } from './sidebar-nav.vue';
const ContentWide = HeaderNav;
export { ContentWide, HeaderNav };

View File

@ -0,0 +1,161 @@
<template>
<svg
class="custom-radio-image"
fill="none"
height="66"
width="104"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<rect
id="svg_1"
fill="currentColor"
fill-opacity="0.02"
height="66"
rx="4"
stroke="null"
width="104"
x="0.13514"
y="0.13514"
/>
<rect
id="svg_8"
fill="hsl(var(--primary))"
height="9.07027"
stroke="null"
width="104.07934"
x="-0.07419"
y="-0.05773"
/>
<rect
id="svg_3"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="15.58168"
y="3.20832"
/>
<path
id="svg_12"
d="m98.19822,2.872c0,-0.54338 0.45662,-1 1,-1l1.925,0c0.54338,0 1,0.45662 1,1l0,2.4c0,0.54338 -0.45662,1 -1,1l-1.925,0c-0.54338,0 -1,-0.45662 -1,-1l0,-2.4z"
fill="#ffffff"
opacity="undefined"
stroke="null"
/>
<rect
id="svg_13"
fill="currentColor"
fill-opacity="0.08"
height="21.51892"
rx="2"
stroke="null"
width="44.13071"
x="53.37873"
y="13.45652"
/>
<path
id="svg_14"
d="m19.4393,15.74245c0,-1.08676 0.79001,-2 1.73013,-2l23.18605,0c0.94011,0 1.73013,0.91324 1.73013,2l0,17.24865c0,1.08676 -0.79001,2 -1.73013,2l-23.18605,0c-0.94011,0 -1.73013,-0.91324 -1.73013,-2l0,-17.24865z"
fill="currentColor"
fill-opacity="0.08"
opacity="undefined"
stroke="null"
/>
<rect
id="svg_15"
fill="currentColor"
fill-opacity="0.08"
height="21.65405"
rx="2"
stroke="null"
width="78.39372"
x="19.93575"
y="39.34689"
/>
<rect
id="svg_21"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="28.14924"
y="3.07319"
/>
<rect
id="svg_22"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="41.25735"
y="3.20832"
/>
<rect
id="svg_23"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="7.52486"
x="54.23033"
y="3.07319"
/>
<rect
id="svg_4"
fill="#ffffff"
height="7.13843"
rx="2"
stroke="null"
width="7.78397"
x="1.5327"
y="0.881"
/>
<rect
id="svg_5"
fill="currentColor"
fill-opacity="0.08"
height="56.81191"
stroke="null"
width="15.44642"
x="-0.06423"
y="9.03113"
/>
<path
id="svg_2"
d="m2.38669,15.38074c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
fill="currentColor"
fill-opacity="0.08"
opacity="undefined"
stroke="null"
/>
<path
id="svg_6"
d="m2.38669,28.43336c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
fill="currentColor"
fill-opacity="0.08"
opacity="undefined"
stroke="null"
/>
<path
id="svg_7"
d="m2.17616,41.27545c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
fill="currentColor"
fill-opacity="0.08"
opacity="undefined"
stroke="null"
/>
<path
id="svg_9"
d="m2.17616,54.32806c0,-0.20384 0.27195,-0.37513 0.59557,-0.37513l7.98149,0c0.32362,0 0.59557,0.17129 0.59557,0.37513l0,3.23525c0,0.20384 -0.27195,0.37513 -0.59557,0.37513l-7.98149,0c-0.32362,0 -0.59557,-0.17129 -0.59557,-0.37513l0,-3.23525z"
fill="currentColor"
fill-opacity="0.08"
opacity="undefined"
stroke="null"
/>
</g>
</svg>
</template>

View File

@ -0,0 +1,12 @@
<template>
<svg
height="1em"
viewBox="0 0 24 24"
width="1em"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19.9 12.66a1 1 0 0 1 0-1.32l1.28-1.44a1 1 0 0 0 .12-1.17l-2-3.46a1 1 0 0 0-1.07-.48l-1.88.38a1 1 0 0 1-1.15-.66l-.61-1.83a1 1 0 0 0-.95-.68h-4a1 1 0 0 0-1 .68l-.56 1.83a1 1 0 0 1-1.15.66L5 4.79a1 1 0 0 0-1 .48L2 8.73a1 1 0 0 0 .1 1.17l1.27 1.44a1 1 0 0 1 0 1.32L2.1 14.1a1 1 0 0 0-.1 1.17l2 3.46a1 1 0 0 0 1.07.48l1.88-.38a1 1 0 0 1 1.15.66l.61 1.83a1 1 0 0 0 1 .68h4a1 1 0 0 0 .95-.68l.61-1.83a1 1 0 0 1 1.15-.66l1.88.38a1 1 0 0 0 1.07-.48l2-3.46a1 1 0 0 0-.12-1.17ZM18.41 14l.8.9l-1.28 2.22l-1.18-.24a3 3 0 0 0-3.45 2L12.92 20h-2.56L10 18.86a3 3 0 0 0-3.45-2l-1.18.24l-1.3-2.21l.8-.9a3 3 0 0 0 0-4l-.8-.9l1.28-2.2l1.18.24a3 3 0 0 0 3.45-2L10.36 4h2.56l.38 1.14a3 3 0 0 0 3.45 2l1.18-.24l1.28 2.22l-.8.9a3 3 0 0 0 0 3.98m-6.77-6a4 4 0 1 0 4 4a4 4 0 0 0-4-4m0 6a2 2 0 1 1 2-2a2 2 0 0 1-2 2"
/>
</svg>
</template>

View File

@ -0,0 +1,173 @@
<template>
<svg
class="custom-radio-image"
fill="none"
height="66"
width="104"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<rect
id="svg_1"
fill="currentColor"
fill-opacity="0.02"
height="66"
rx="4"
stroke="null"
width="104"
x="0.13514"
y="0.13514"
/>
<path
id="svg_2"
d="m-3.37838,3.7543a1.93401,4.02457 0 0 1 1.93401,-4.02457l11.3488,0l0,66.40541l-11.3488,0a1.93401,4.02457 0 0 1 -1.93401,-4.02457l0,-58.35627z"
fill="hsl(var(--primary))"
stroke="null"
/>
<rect
id="svg_3"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="5.47439"
x="1.64059"
y="15.46086"
/>
<rect
id="svg_4"
fill="#ffffff"
height="7.67897"
rx="2"
stroke="null"
width="8.18938"
x="0.58676"
y="1.42154"
/>
<rect
id="svg_8"
fill="currentColor"
fill-opacity="0.08"
height="9.07027"
rx="2"
stroke="null"
width="75.91967"
x="25.38277"
y="1.42876"
/>
<rect
id="svg_9"
fill="#b2b2b2"
height="4.4"
rx="1"
stroke="null"
width="3.925"
x="27.91529"
y="3.69284"
/>
<rect
id="svg_10"
fill="#b2b2b2"
height="4.4"
rx="1"
stroke="null"
width="3.925"
x="80.75054"
y="3.62876"
/>
<rect
id="svg_11"
fill="#b2b2b2"
height="4.4"
rx="1"
stroke="null"
width="3.925"
x="87.78868"
y="3.69981"
/>
<rect
id="svg_12"
fill="#b2b2b2"
height="4.4"
rx="1"
stroke="null"
width="3.925"
x="94.6847"
y="3.62876"
/>
<rect
id="svg_13"
fill="currentColor"
fill-opacity="0.08"
height="21.51892"
rx="2"
stroke="null"
width="42.9287"
x="58.75427"
y="14.613"
/>
<rect
id="svg_14"
fill="currentColor"
fill-opacity="0.08"
height="20.97838"
rx="2"
stroke="null"
width="28.36894"
x="26.14342"
y="14.613"
/>
<rect
id="svg_15"
fill="currentColor"
fill-opacity="0.08"
height="21.65405"
rx="2"
stroke="null"
width="75.09493"
x="26.34264"
y="39.68822"
/>
<rect
id="svg_5"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="5.47439"
x="1.79832"
y="28.39462"
/>
<rect
id="svg_6"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="5.47439"
x="1.64059"
y="41.80156"
/>
<rect
id="svg_7"
fill="#e5e5e5"
height="2.789"
rx="1.395"
stroke="null"
width="5.47439"
x="1.64059"
y="55.36623"
/>
<rect
id="svg_16"
fill="currentColor"
fill-opacity="0.08"
height="65.72065"
stroke="null"
width="12.49265"
x="9.85477"
y="-0.02618"
/>
</g>
</svg>
</template>

View File

@ -0,0 +1,153 @@
<template>
<svg
class="custom-radio-image"
fill="none"
height="66"
width="104"
xmlns="http://www.w3.org/2000/svg"
>
<g>
<rect
id="svg_1"
fill="currentColor"
fill-opacity="0.02"
height="66"
rx="4"
stroke="null"
width="104"
/>
<path
id="svg_2"
d="m-3.37838,3.61916a4.4919,4.02457 0 0 1 4.4919,-4.02457l26.35848,0l0,66.40541l-26.35848,0a4.4919,4.02457 0 0 1 -4.4919,-4.02457l0,-58.35627z"
fill="hsl(var(--primary))"
stroke="null"
/>
<rect
id="svg_3"
fill="#e5e5e5"
height="2.789"
rx="1.395"
width="17.66"
x="4.906"
y="23.884"
/>
<rect
id="svg_4"
fill="#ffffff"
height="9.706"
rx="2"
width="9.811"
x="8.83"
y="5.881"
/>
<path
id="svg_5"
d="m4.906,35.833c0,-0.75801 0.63699,-1.395 1.395,-1.395l14.87,0c0.75801,0 1.395,0.63699 1.395,1.395l0,-0.001c0,0.75801 -0.63699,1.395 -1.395,1.395l-14.87,0c-0.75801,0 -1.395,-0.63699 -1.395,-1.395l0,0.001z"
fill="#ffffff"
opacity="undefined"
/>
<rect
id="svg_6"
fill="#ffffff"
height="2.789"
rx="1.395"
width="17.66"
x="4.906"
y="44.992"
/>
<rect
id="svg_7"
fill="#ffffff"
height="2.789"
rx="1.395"
width="17.66"
x="4.906"
y="55.546"
/>
<rect
id="svg_8"
fill="currentColor"
fill-opacity="0.08"
height="9.07027"
rx="2"
stroke="null"
width="73.53879"
x="28.97986"
y="1.42876"
/>
<rect
id="svg_9"
fill="#b2b2b2"
height="4.4"
rx="1"
stroke="null"
width="3.925"
x="32.039"
y="3.89903"
/>
<rect
id="svg_10"
fill="#b2b2b2"
height="4.4"
rx="1"
stroke="null"
width="3.925"
x="80.75054"
y="3.62876"
/>
<rect
id="svg_11"
fill="#b2b2b2"
height="4.4"
rx="1"
stroke="null"
width="3.925"
x="87.58249"
y="3.49362"
/>
<rect
id="svg_12"
fill="#b2b2b2"
height="4.4"
rx="1"
stroke="null"
width="3.925"
x="94.6847"
y="3.62876"
/>
<rect
id="svg_13"
fill="currentColor"
fill-opacity="0.08"
height="21.51892"
rx="2"
stroke="null"
width="45.63141"
x="56.05157"
y="14.613"
/>
<rect
id="svg_14"
fill="currentColor"
fill-opacity="0.08"
height="20.97838"
rx="2"
stroke="null"
width="22.82978"
x="29.38527"
y="14.613"
/>
<rect
id="svg_15"
fill="currentColor"
fill-opacity="0.08"
height="21.65405"
rx="2"
stroke="null"
width="72.45771"
x="28.97986"
y="39.48203"
/>
</g>
</svg>
</template>

View File

@ -0,0 +1,101 @@
<script setup lang="ts">
import type { LayoutType } from '@vben/types';
import { type Component, computed } from 'vue';
import { CircleHelp } from '@vben/icons';
import { $t } from '@vben/locales';
import { VbenTooltip } from '@vben-core/shadcn-ui';
import {
FullContent,
HeaderNav,
MixedNav,
SidebarMixedNav,
SidebarNav,
} from './icons';
interface PresetItem {
name: string;
tip: string;
type: LayoutType;
}
defineOptions({
name: 'PreferenceLayout',
});
const modelValue = defineModel<LayoutType>({ default: 'sidebar-topbar' });
const components: Record<LayoutType, Component> = {
'sidebar-topbar': MixedNav,
'full-content': FullContent,
'header-nav': HeaderNav,
'mixed-nav': MixedNav,
'sidebar-mixed-nav': SidebarMixedNav,
'sidebar-nav': SidebarNav,
};
const PRESET = computed((): PresetItem[] => [
{
name: '默认',
tip: '顶部栏仅用于显示全局信息或操作,不包含菜单。',
type: 'sidebar-topbar',
},
{
name: $t('preferences.vertical'),
tip: $t('preferences.verticalTip'),
type: 'sidebar-nav',
},
{
name: $t('preferences.twoColumn'),
tip: $t('preferences.twoColumnTip'),
type: 'sidebar-mixed-nav',
},
// {
// name: $t('preferences.horizontal'),
// tip: $t('preferences.horizontalTip'),
// type: 'header-nav',
// },
// {
// name: $t('preferences.mixedMenu'),
// tip: $t('preferences.mixedMenuTip'),
// type: 'mixed-nav',
// },
// {
// name: $t('preferences.fullContent'),
// tip: $t('preferences.fullContentTip'),
// type: 'full-content',
// },
]);
function activeClass(theme: string): string[] {
return theme === modelValue.value ? ['outline-box-active'] : [];
}
</script>
<template>
<div class="flex w-full flex-wrap gap-5">
<template v-for="theme in PRESET" :key="theme.name">
<div
class="flex w-[100px] cursor-pointer flex-col"
@click="modelValue = theme.type"
>
<div :class="activeClass(theme.type)" class="outline-box flex-center">
<component :is="components[theme.type]" />
</div>
<div
class="text-muted-foreground flex-center hover:text-foreground mt-2 text-center text-xs"
>
{{ theme.name }}
<VbenTooltip v-if="theme.tip" side="bottom">
<template #trigger>
<CircleHelp class="ml-1 size-3 cursor-help" />
</template>
{{ theme.tip }}
</VbenTooltip>
</div>
</div>
</template>
</div>
</template>

View File

@ -1,32 +1,142 @@
<template>
<Modal title="个人偏好" :visible="visible" @cancel="close">
<Modal title="个人偏好" :visible="visible" @cancel="close" :width="600">
<Tabs v-model:activeKey="activeKey" centered>
<TabPane key="1" tab="自定义菜单">Content of Tab Pane 1</TabPane>
<TabPane key="2" tab="菜单区设置" force-render>Content of Tab Pane 2</TabPane>
<TabPane key="3" tab="主题设置">Content of Tab Pane 3</TabPane>
<TabPane key="4" tab="消息语音">Content of Tab Pane 4</TabPane>
<TabPane key="1" tab="自定义菜单">
<div class="list-box flex flex-col gap-4 my-2">
<div class="list-item-box flex justify-around items-center">
<div class="i-n w-100 shrink-0">
<FolderOutlined class="mr-2" />总部系统
</div>
<div class="i-s">显示菜单<Checkbox v-model:checked="checked"></Checkbox>
</div>
<div class="i-n">排序0</div>
</div>
<div class="list-item-box flex justify-around items-center" v-for="(item, index) in otherRouter"
:key="index">
<div class="i-n w-100 shrink-0">
<FolderOutlined class="mr-2" />{{ item.name }}
</div>
<div class="i-s">显示菜单<Checkbox v-model:checked="checked"></Checkbox>
</div>
<div class="i-n">排序{{ index + 1 }}</div>
</div>
</div>
</TabPane>
<TabPane key="2" tab="菜单区设置" force-render>
<div class="flex justify-center">
<Form style="width: 450px;">
<FormItem label="菜单栏默认打开:" class="mb-3">
<Switch v-model:checked="menuOpen" />
</FormItem>
<FormItem label="深色侧边栏:" class="mb-3">
<Switch v-model:checked="menuTheme" />
</FormItem>
<FormItem label="布局:" class="mb-3">
<layout v-model="layoutVlaue"></layout>
</FormItem>
</Form>
</div>
</TabPane>
<TabPane key="3" tab="主题设置">
<div class="flex justify-center">
<Form style="width: 450px;">
<FormItem label="默认主题:" class="mb-3">
<theme v-model="themeValue"></theme>
</FormItem>
<FormItem label="内置主题:" class="mb-3">
<builtin :isDark="true" v-model="builtinValue"></builtin>
</FormItem>
</Form>
</div>
</TabPane>
<TabPane key="4" tab="消息语音">
<div class="flex justify-center">
<Form style="width: 450px;">
<FormItem label="消息语音提醒:" class="mb-3">
<Switch v-model:checked="checked" class="ml-3" />
</FormItem>
<FormItem label="提示语言选择列表:" class="mb-3">
<Select ref="select" class="ml-3" v-model:value="value1" :options="options1"></Select>
</FormItem>
<FormItem label="提示语音选择文件地址" class="mb-3">
<div class="ml-3 flex flex-col gap-2">
<div class="flex gap-2">
<Button type="primary">试听</Button>
<Button type="primary">上传</Button>
</div>
</div>
</FormItem>
</Form>
</div>
</TabPane>
</Tabs>
<template #footer>
<Button type="link" key="back" @click="close">恢复</Button>
<Button type="link" key="back" @click="close">恢复</Button>
<Button key="back" @click="close">取消</Button>
<Button key="submit" type="primary" @click="close">确定</Button>
</template>
</Modal>
</template>
<script setup lang="ts">
import { Modal, Tabs, Form, FormItem, Select, Button, TabPane } from 'ant-design-vue';
import { ref } from 'vue';
import { Modal, Tabs, Form, FormItem, Select, Button, TabPane, Checkbox, Switch, Radio, RadioGroup } from 'ant-design-vue';
import { FolderOutlined } from '@ant-design/icons-vue';
import layout from './layout.vue';
import theme from './theme.vue';
import builtin from './builtin.vue';
import { ref, watch } from 'vue';
import { otherRouter } from "#/router/routes/modules/linkdata"
import { preferences, updatePreferences } from '@vben/preferences';
let layoutVlaue = ref(preferences.app.layout)
watch(layoutVlaue, (n, o) => {
updatePreferences({
app: {
layout: n
}
})
})
let themeValue = ref(preferences.theme.mode);
watch(themeValue, (n, o) => {
updatePreferences({
theme: {
mode: n
}
})
})
let builtinValue = ref(preferences.theme.builtinType);
watch(builtinValue, (n, o) => {
updatePreferences({
theme: {
builtinType: n
}
})
console.log('zzzz',preferences.theme.builtinType);
})
let menuOpen = ref(preferences.sidebar.enable)
watch(menuOpen, (n, o) => {
updatePreferences({
sidebar: {
enable: n
}
})
console.log('zz111zz',n);
})
let menuTheme = ref(preferences.theme.semiDarkSidebar)
watch(menuTheme, (n, o) => {
updatePreferences({
theme: {
semiDarkSidebar: n
}
})
console.log('zz222zz',n);
})
let value1 = ref('')
let activeKey = ref('1');
let options1 = [
{
value: '1',
label: '西北油田xbyt',
},
{
value: '2',
label: '智能油气田znyqt',
}
]
let checked = ref(true)
let options1 = []
const visible = defineModel<boolean>('visible');

View File

@ -0,0 +1,69 @@
<script setup lang="ts">
import type { ThemeModeType } from '@vben/types';
import type { Component } from 'vue';
import { MoonStar, Sun, SunMoon } from '@vben/icons';
import { $t } from '@vben/locales';
defineOptions({
name: 'PreferenceTheme',
});
const modelValue = defineModel<string>({ default: 'auto' });
const THEME_PRESET: Array<{ icon: Component; name: ThemeModeType }> = [
{
icon: Sun,
name: 'light',
},
{
icon: MoonStar,
name: 'dark',
},
{
icon: SunMoon,
name: 'auto',
},
];
function activeClass(theme: string): string[] {
return theme === modelValue.value ? ['outline-box-active'] : [];
}
function nameView(name: string) {
switch (name) {
case 'light': {
return $t('preferences.theme.light');
}
case 'dark': {
return $t('preferences.theme.dark');
}
case 'auto': {
return $t('preferences.followSystem');
}
}
}
</script>
<template>
<div class="flex w-full flex-wrap justify-between">
<template v-for="theme in THEME_PRESET" :key="theme.name">
<div
class="flex cursor-pointer flex-col"
@click="modelValue = theme.name"
>
<div
:class="activeClass(theme.name)"
class="outline-box flex-center py-4"
>
<component :is="theme.icon" class="mx-9 size-5" />
</div>
<div class="text-muted-foreground mt-2 text-center text-xs">
{{ nameView(theme.name) }}
</div>
</div>
</template>
</div>
</template>

View File

@ -21,7 +21,7 @@ export const overridesPreferences = defineOverridesPreferences({
// 检查更新的时间间隔,单位为分钟
checkUpdatesInterval: 1,
// 开启布局设置按钮
enablePreferences: true,
enablePreferences: false,
enableRefreshToken: false,
isMobile: false,
layout: 'sidebar-topbar',

View File

@ -64,6 +64,7 @@ const routes: RouteRecordRaw[] = [
{
name: 'home',
path: '/home',
// component: () => import('#/views/dashboard/home/index.vue'),
component: () => import('#/views/dashboard/home/index.vue'),
meta: {
hideInMenu: true,

View File

@ -1,3 +1,18 @@
<template>
<div class="text-white">我是示例组件1</div>
<a href="#">
<img :src="'/xbyt/'+data.component.img" alt="" class="w-full h-full">
</a>
</template>
<script setup lang="ts">
import { toRefs } from 'vue'
const props = defineProps({
data: {
type: Object,
default: {}
},
})
console.log('propsprops', props.data);
let { data } = toRefs(props);
</script>
<style></style>

View File

@ -1,3 +1,18 @@
<template>
<div class="text-white">我是示例组件2</div>
<a href="#">
<img :src="'/xbyt/'+data.component.img" alt="" class="w-full h-full">
</a>
</template>
<script setup lang="ts">
import { toRefs } from 'vue'
const props = defineProps({
data: {
type: Object,
default: {}
},
})
console.log('propsprops', props.data);
let { data } = toRefs(props);
</script>
<style></style>

View File

@ -1,3 +1,18 @@
<template>
<div class="text-white">我是示例组件3</div>
<a href="#">
<img :src="'/xbyt/'+data.component.img" alt="" class="w-full h-full">
</a>
</template>
<script setup lang="ts">
import { toRefs } from 'vue'
const props = defineProps({
data: {
type: Object,
default: {}
},
})
console.log('propsprops', props.data);
let { data } = toRefs(props);
</script>
<style></style>

View File

@ -0,0 +1,18 @@
<template>
<a href="#">
<img :src="'/xbyt/'+data.component.img" alt="" class="w-full h-full">
</a>
</template>
<script setup lang="ts">
import { toRefs } from 'vue'
const props = defineProps({
data: {
type: Object,
default: {}
},
})
console.log('propsprops', props.data);
let { data } = toRefs(props);
</script>
<style></style>

View File

@ -1,5 +1,9 @@
<script setup>
import { defineAsyncComponent, getCurrentInstance, onMounted, ref } from 'vue';
import { preferences, updatePreferences } from '@vben/preferences';
import { CloseCircleFilled } from '@ant-design/icons-vue';
const { proxy } = getCurrentInstance();
const layout = ref([]);
@ -20,30 +24,43 @@ const DragPos = {
const componentsInfo = [
{
id: '1-1',
title: '示例组件1',
name: 'annualOutput',
title: '磁贴管理2×2',
name: 'xl',
component: './components/Output1/index.vue',
des: '示例组件1',
w: 4,
h: 8,
des:'磁贴管理2×2',
w: 1,
h: 2,
img: 'WORKBENCH_MANAGER.png'
},
{
id: '1-2',
title: '示例组件2',
name: 'MonthOutput',
title: '饼图示例8×8',
name: 'xxl',
component: './components/Output2/index.vue',
des: '示例组件2',
w: 2,
h: 2,
des: '饼图示例8×8',
w: 8,
h: 8,
img:'AUTO_1620294688040.png'
},
{
id: '1-3',
title: '示例组件3',
name: 'dayOutput',
title: '报表示例4×4',
name: 'xxxl',
component: './components/Output3/index.vue',
des: '示例组件3',
w: 8,
des: '报表示例4×4',
w: 4,
h: 4,
img:"AUTO_1621594591994.png"
},
{
id: '1-3',
title: '列表示例16×8',
name: 'xxxxl',
component: './components/Output4/index.vue',
des: '列表示例16×8',
w: 16,
h: 8,
img:'AUTO_1620296071109.png'
},
];
let currentDragCom = null;
@ -113,7 +130,8 @@ const drag = (e, item) => {
proxy.$refs.gridItem[layout.value.length - 1].$refs.item.style.display =
'none';
} catch {}
const el = proxy.$refs.gridItem[index];
const el = proxy.$refs.gridItem?proxy.$refs.gridItem[index]:null;
if (el) {
el.dragging = {
top: mouseXY.y - parentRect.top,
@ -216,6 +234,7 @@ const delItem = (item) => {
<template>
<div class="container h-[100vh]">
<!-- 自定义布局的部分 -->
<div class="grid-box">
<grid-layout
@ -242,9 +261,9 @@ const delItem = (item) => {
@resized="resizedEvent"
>
<span class="close" @click="delItem(item)"
><i class="sky-iconfont icon-guanbi">x</i></span
><CloseCircleFilled style="color: #f10215;" /></span
>
<component :is="item.loadComp" />
<component :is="item.loadComp" :data="item"/>
</grid-item>
</grid-layout>
</div>
@ -259,7 +278,7 @@ const delItem = (item) => {
@dragend="dragend"
@dragstart="dragstart($event, item)"
>
{{ item.des }}
<img :src="'/xbyt/'+item.img" alt="">
</div>
</div>
</div>
@ -283,17 +302,27 @@ const delItem = (item) => {
height: 100%;
padding: 12px 20px;
border: 1px solid rgb(66 66 66 / 100%);
display: flex;
flex-wrap: wrap;
gap: 10px;
align-content: flex-start;
.ctrl-box {
display: flex;
align-items: center;
height: 40px;
padding: 0 12px;
margin-top: 20px;
color: #fff;
height: 70px;
height: 70px;
// padding: 0 12px;
// margin-top: 20px;
background: #fff;
user-select: none;
background: #2d2d2c;
border: 1px solid rgb(66 66 66 / 100%);
img {
width: 100%;
height: 100%;
object-fit: contain
}
}
}
</style>
@ -306,16 +335,16 @@ const delItem = (item) => {
border: 1px solid rgb(66 66 66 / 100%);
.vue-grid-item {
padding: 12px 20px;
background: #2d2d2c;
border: 1px solid rgb(66 66 66 / 100%);
// padding: 12px 20px;
// background: #2d2d2c;
// border: 1px solid rgb(66 66 66 / 100%);
border-radius: 2px;
}
.close {
position: absolute;
top: 10px;
right: 10px;
top: 0;
right: 0;
display: inline-block;
width: 16px;
height: 16px;

View File

@ -0,0 +1,234 @@
<template>
<div>
<div>
<div class="layoutJSON">
Displayed as <code>[x, y, w, h]</code>:
<div class="columns">
<div class="layoutItem" v-for="item in layout">
<b>{{ item.i }}</b>: [{{ item.x }}, {{ item.y }}, {{ item.w }}, {{ item.h }}]
</div>
</div>
</div>
</div>
<br/>
<div @drag="drag" @dragend="dragend" class="droppable-element" draggable="true"
unselectable="on">Droppable Element (Drag me!)</div>
<div id="content">
<grid-layout ref="gridlayout" :layout.sync="layout"
:col-num="12"
:row-height="30"
:is-draggable="true"
:is-resizable="true"
:vertical-compact="true"
:use-css-transforms="true"
>
<grid-item :key="item.i" v-for="item in layout"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
>
<span class="text">{{ item.i }}</span>
</grid-item>
</grid-layout>
</div>
</div>
</template>
<script>
import {GridLayout, GridItem} from "vue-grid-layout-v3"
let mouseXY = {"x": null, "y": null};
let DragPos = {"x": null, "y": null, "w": 1, "h": 1, "i": null};
export default {
components: {
GridLayout,
GridItem
},
data() {
return {
layout: [
{"x": 0, "y": 0, "w": 2, "h": 2, "i": "0"},
{"x": 2, "y": 0, "w": 2, "h": 4, "i": "1"},
{"x": 4, "y": 0, "w": 2, "h": 5, "i": "2"},
{"x": 6, "y": 0, "w": 2, "h": 3, "i": "3"},
{"x": 8, "y": 0, "w": 2, "h": 3, "i": "4"},
{"x": 10, "y": 0, "w": 2, "h": 3, "i": "5"},
{"x": 0, "y": 5, "w": 2, "h": 5, "i": "6"},
{"x": 2, "y": 5, "w": 2, "h": 5, "i": "7"},
{"x": 4, "y": 5, "w": 2, "h": 5, "i": "8"},
{"x": 5, "y": 10, "w": 4, "h": 3, "i": "9"},
],
}
},
mounted() {
document.addEventListener("dragover", function (e) {
mouseXY.x = e.clientX;
mouseXY.y = e.clientY;
}, false);
},
beforeDestroy() {
},
methods: {
drag: function (e) {
let parentRect = document.getElementById('content').getBoundingClientRect();
let mouseInGrid = false;
if (((mouseXY.x > parentRect.left) && (mouseXY.x < parentRect.right)) && ((mouseXY.y > parentRect.top) && (mouseXY.y < parentRect.bottom))) {
mouseInGrid = true;
}
if (mouseInGrid === true && (this.layout.findIndex(item => item.i === 'drop')) === -1) {
this.layout.push({
x: (this.layout.length * 2) % (this.colNum || 12),
y: this.layout.length + (this.colNum || 12), // puts it at the bottom
w: 1,
h: 1,
i: 'drop',
});
}
let index = this.layout.findIndex(item => item.i === 'drop');
if (index !== -1) {
try {
this.$refs.gridlayout.$children[this.layout.length].$refs.item.style.display = "none";
} catch {
}
let el = this.$refs.gridlayout.$children[index];
el.dragging = {"top": mouseXY.y - parentRect.top, "left": mouseXY.x - parentRect.left};
let new_pos = el.calcXY(mouseXY.y - parentRect.top, mouseXY.x - parentRect.left);
if (mouseInGrid === true) {
this.$refs.gridlayout.dragEvent('dragstart', 'drop', new_pos.x, new_pos.y, 1, 1);
DragPos.i = String(index);
DragPos.x = this.layout[index].x;
DragPos.y = this.layout[index].y;
}
if (mouseInGrid === false) {
this.$refs.gridlayout.dragEvent('dragend', 'drop', new_pos.x, new_pos.y, 1, 1);
this.layout = this.layout.filter(obj => obj.i !== 'drop');
}
}
},
dragend: function (e) {
let parentRect = document.getElementById('content').getBoundingClientRect();
let mouseInGrid = false;
if (((mouseXY.x > parentRect.left) && (mouseXY.x < parentRect.right)) && ((mouseXY.y > parentRect.top) && (mouseXY.y < parentRect.bottom))) {
mouseInGrid = true;
}
if (mouseInGrid === true) {
alert(`Dropped element props:\n${JSON.stringify(DragPos, ['x', 'y', 'w', 'h'], 2)}`);
this.$refs.gridlayout.dragEvent('dragend', 'drop', DragPos.x, DragPos.y, 1, 1);
this.layout = this.layout.filter(obj => obj.i !== 'drop');
// UNCOMMENT below if you want to add a grid-item
/*
this.layout.push({
x: DragPos.x,
y: DragPos.y,
w: 1,
h: 1,
i: DragPos.i,
});
this.$refs.gridLayout.dragEvent('dragend', DragPos.i, DragPos.x,DragPos.y,1,1);
try {
this.$refs.gridLayout.$children[this.layout.length].$refs.item.style.display="block";
} catch {
}
*/
}
},
}
}
</script>
<style scoped>
.droppable-element {
width: 150px;
text-align: center;
background: #fdd;
border: 1px solid black;
margin: 10px 0;
padding: 10px;
}
.vue-grid-layout {
background: #eee;
}
.vue-grid-item:not(.vue-grid-placeholder) {
background: #ccc;
border: 1px solid black;
}
.vue-grid-item .resizing {
opacity: 0.9;
}
.vue-grid-item .static {
background: #cce;
}
.vue-grid-item .text {
font-size: 24px;
text-align: center;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
height: 100%;
width: 100%;
}
.vue-grid-item .no-drag {
height: 100%;
width: 100%;
}
.vue-grid-item .minMax {
font-size: 12px;
}
.vue-grid-item .add {
cursor: pointer;
}
.vue-draggable-handle {
position: absolute;
width: 20px;
height: 20px;
top: 0;
left: 0;
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10'><circle cx='5' cy='5' r='5' fill='#999999'/></svg>") no-repeat;
background-position: bottom right;
padding: 0 8px 8px 0;
background-repeat: no-repeat;
background-origin: content-box;
box-sizing: border-box;
cursor: pointer;
}
.layoutJSON {
background: #ddd;
border: 1px solid black;
margin-top: 10px;
padding: 10px;
}
.layoutJSON {
background: #ddd;
border: 1px solid black;
margin-top: 10px;
padding: 10px;
}
.columns {
-moz-columns: 120px;
-webkit-columns: 120px;
columns: 120px;
}
</style>