mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-11 18:10:49 +08:00
feat: 增强工作流侧边栏,支持移动端显示和组件点击事件处理
This commit is contained in:
@@ -10,7 +10,7 @@ import WorkflowSidebar from '@/layouts/components/WorkflowSidebar.vue'
|
||||
import DropzoneBackground from '@/layouts/components/DropzoneBackground.vue'
|
||||
import ImportCodeDialog from '@/components/dialog/ImportCodeDialog.vue'
|
||||
|
||||
const { onConnect, addEdges, nodes, edges } = useVueFlow()
|
||||
const { onConnect, addEdges, nodes, edges, addNodes, screenToFlowCoordinate } = useVueFlow()
|
||||
|
||||
const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop()
|
||||
|
||||
@@ -98,6 +98,43 @@ const $toast = useToast()
|
||||
// 导入代码对话框
|
||||
const importCodeDialog = ref(false)
|
||||
|
||||
// 为移动端生成节点ID
|
||||
function getId() {
|
||||
return 'act_' + Math.random().toString(36).substr(2, 9)
|
||||
}
|
||||
|
||||
// 处理移动端组件点击事件
|
||||
function handleComponentClick(action: any) {
|
||||
// 计算当前视图中心点
|
||||
const centerX = window.innerWidth / 2
|
||||
const centerY = window.innerHeight / 3
|
||||
|
||||
// 转换为画布坐标
|
||||
const position = screenToFlowCoordinate({
|
||||
x: centerX,
|
||||
y: centerY,
|
||||
})
|
||||
|
||||
// 生成一个新节点ID
|
||||
const nodeId = getId()
|
||||
|
||||
// 创建新节点
|
||||
const newNode = {
|
||||
id: nodeId,
|
||||
type: action.type,
|
||||
name: action.name,
|
||||
description: action.desc || '',
|
||||
position,
|
||||
data: {},
|
||||
}
|
||||
|
||||
// 添加节点到画布
|
||||
addNodes(newNode)
|
||||
|
||||
// 显示提示
|
||||
$toast.success('已添加组件到画布')
|
||||
}
|
||||
|
||||
// 调用API 编辑任务
|
||||
async function updateWorkflow() {
|
||||
// 更新节点和流程
|
||||
@@ -157,32 +194,34 @@ const isMacOS = computed(() => {
|
||||
|
||||
<template>
|
||||
<VDialog scrollable fullscreen :scrim="false" transition="dialog-bottom-transition">
|
||||
<VCard>
|
||||
<VCard class="workflow-dialog">
|
||||
<!-- Toolbar -->
|
||||
<div>
|
||||
<VToolbar color="primary">
|
||||
<VToolbarItems>
|
||||
<VBtn icon @click="emit('close')" class="ms-3">
|
||||
<VIcon size="large" color="white" icon="mdi-close" />
|
||||
</VBtn>
|
||||
</VToolbarItems>
|
||||
<VToolbarTitle> 编辑流程 - {{ workflow?.name }} </VToolbarTitle>
|
||||
<VToolbarItems>
|
||||
<VBtn icon @click="importCodeDialog = true">
|
||||
<VIcon size="large" color="white" icon="mdi-import" />
|
||||
</VBtn>
|
||||
<VBtn icon @click="shareWorkflow">
|
||||
<VIcon size="large" color="white" icon="mdi-share" />
|
||||
</VBtn>
|
||||
<VBtn icon @click="updateWorkflow" class="mx-5">
|
||||
<VIcon size="large" color="white" icon="mdi-content-save" />
|
||||
</VBtn>
|
||||
</VToolbarItems>
|
||||
</VToolbar>
|
||||
</div>
|
||||
<VDivider />
|
||||
<VCardText class="px-0 py-0">
|
||||
<div class="dnd-flow" @drop="onDrop">
|
||||
<VToolbar color="primary">
|
||||
<VToolbarItems>
|
||||
<VBtn icon @click="emit('close')" class="ms-3">
|
||||
<VIcon size="large" color="white" icon="mdi-close" />
|
||||
</VBtn>
|
||||
</VToolbarItems>
|
||||
<VToolbarTitle class="text-truncate"> 编辑流程 - {{ workflow?.name }} </VToolbarTitle>
|
||||
<VSpacer></VSpacer>
|
||||
<VToolbarItems>
|
||||
<VBtn icon variant="text" @click="importCodeDialog = true" class="ms-2">
|
||||
<VIcon size="24" color="white" icon="mdi-import" />
|
||||
<VTooltip activator="parent" location="bottom">导入流程代码</VTooltip>
|
||||
</VBtn>
|
||||
<VBtn icon variant="text" @click="shareWorkflow" class="ms-2">
|
||||
<VIcon size="24" color="white" icon="mdi-share" />
|
||||
<VTooltip activator="parent" location="bottom">分享流程代码</VTooltip>
|
||||
</VBtn>
|
||||
<VBtn icon variant="text" @click="updateWorkflow" class="ms-2 me-3">
|
||||
<VIcon size="24" color="white" icon="mdi-content-save" />
|
||||
<VTooltip activator="parent" location="bottom">保存流程</VTooltip>
|
||||
</VBtn>
|
||||
</VToolbarItems>
|
||||
</VToolbar>
|
||||
|
||||
<VCardText class="workflow-content pa-0">
|
||||
<div class="workflow-canvas" @drop="onDrop">
|
||||
<VueFlow
|
||||
:nodes="nodes"
|
||||
:edges="edges"
|
||||
@@ -204,10 +243,11 @@ const isMacOS = computed(() => {
|
||||
>
|
||||
</DropzoneBackground>
|
||||
</VueFlow>
|
||||
<WorkflowSidebar />
|
||||
<WorkflowSidebar @component-click="handleComponentClick" />
|
||||
</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
|
||||
<ImportCodeDialog
|
||||
v-if="importCodeDialog"
|
||||
v-model="importCodeDialog"
|
||||
@@ -218,88 +258,43 @@ const isMacOS = computed(() => {
|
||||
/>
|
||||
</VDialog>
|
||||
</template>
|
||||
<style>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@vue-flow/core/dist/style.css';
|
||||
@import '@vue-flow/core/dist/theme-default.css';
|
||||
@import '@vue-flow/controls/dist/style.css';
|
||||
@import '@vue-flow/minimap/dist/style.css';
|
||||
@import '@vue-flow/node-resizer/dist/style.css';
|
||||
|
||||
.vue-flow__minimap {
|
||||
transform: scale(75%);
|
||||
transform-origin: bottom right;
|
||||
}
|
||||
|
||||
.dnd-flow {
|
||||
.workflow-dialog {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-direction: column;
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
.dnd-flow aside {
|
||||
background: #10b981bf;
|
||||
border-inline-end: 1px solid #eee;
|
||||
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 30%);
|
||||
box-shadow: 0 5px 10px #0000004d;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
padding-block: 15px;
|
||||
padding-inline: 10px;
|
||||
.workflow-content {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.dnd-flow aside .nodes > * {
|
||||
box-shadow: 5px 5px 10px 2px rgba(0, 0, 0, 25%);
|
||||
box-shadow: 5px 5px 10px 2px #00000040;
|
||||
cursor: grab;
|
||||
font-weight: 500;
|
||||
margin-block-end: 10px;
|
||||
}
|
||||
|
||||
.dnd-flow aside .description {
|
||||
margin-block-end: 10px;
|
||||
}
|
||||
|
||||
.dnd-flow .vue-flow-wrapper {
|
||||
flex-grow: 1;
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
@media screen and (width >= 640px) {
|
||||
.dnd-flow {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dnd-flow aside {
|
||||
max-inline-size: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (width <= 639px) {
|
||||
.dnd-flow aside .nodes {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropzone-background {
|
||||
.workflow-canvas {
|
||||
position: relative;
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
}
|
||||
|
||||
.dropzone-background .overlay {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
inset-block-start: 0;
|
||||
inset-inline-start: 0;
|
||||
pointer-events: none;
|
||||
.vue-flow__minimap {
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
border-radius: 8px;
|
||||
background-color: rgba(var(--v-theme-surface), 0.8);
|
||||
box-shadow: 0 4px 15px rgba(var(--v-shadow-key-umbra-color), 0.1);
|
||||
inset-block-end: 20px;
|
||||
inset-inline-end: 20px;
|
||||
transform: scale(75%);
|
||||
transform-origin: bottom right;
|
||||
}
|
||||
|
||||
.vue-flow__handle {
|
||||
@@ -320,4 +315,39 @@ const isMacOS = computed(() => {
|
||||
.vue-flow__handle-right {
|
||||
background-color: rgb(var(--v-theme-error));
|
||||
}
|
||||
|
||||
// 自定义节点样式
|
||||
.vue-flow__node {
|
||||
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
border-radius: 12px;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 8px 16px rgba(var(--v-shadow-key-umbra-color), 0.15) !important;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
box-shadow: 0 0 0 1px rgb(var(--v-theme-primary)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义动作连线样式
|
||||
.vue-flow__edge.animation {
|
||||
.vue-flow__edge-path {
|
||||
stroke: rgb(var(--v-theme-primary));
|
||||
}
|
||||
|
||||
&.selected {
|
||||
.vue-flow__edge-path {
|
||||
stroke: rgb(var(--v-theme-primary));
|
||||
stroke-width: 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (width <= 600px) {
|
||||
.vue-flow__minimap {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -44,7 +44,7 @@ onMounted(() => {
|
||||
<VCardItem>
|
||||
<template v-slot:prepend>
|
||||
<VAvatar>
|
||||
<VIcon icon="mdi-download-box-outline" size="x-large"></VIcon>
|
||||
<VIcon icon="mdi-download" size="x-large"></VIcon>
|
||||
</VAvatar>
|
||||
</template>
|
||||
<VCardTitle>添加下载</VCardTitle>
|
||||
|
||||
@@ -19,7 +19,7 @@ defineProps({
|
||||
<VCardItem>
|
||||
<template v-slot:prepend>
|
||||
<VAvatar>
|
||||
<VIcon icon="mdi-star-check" size="x-large"></VIcon>
|
||||
<VIcon icon="mdi-star-plus" size="x-large"></VIcon>
|
||||
</VAvatar>
|
||||
</template>
|
||||
<VCardTitle>添加订阅</VCardTitle>
|
||||
|
||||
@@ -110,7 +110,7 @@ onMounted(() => {
|
||||
<VCardItem>
|
||||
<template v-slot:prepend>
|
||||
<VAvatar>
|
||||
<VIcon icon="mdi-multimedia" size="x-large"></VIcon>
|
||||
<VIcon icon="mdi-movie-search" size="x-large"></VIcon>
|
||||
</VAvatar>
|
||||
</template>
|
||||
<VCardTitle>获取媒体数据</VCardTitle>
|
||||
|
||||
@@ -20,7 +20,7 @@ defineProps({
|
||||
<VCardItem>
|
||||
<template v-slot:prepend>
|
||||
<VAvatar>
|
||||
<VIcon icon="mdi-file-move" size="x-large"></VIcon>
|
||||
<VIcon icon="mdi-folder-search" size="x-large"></VIcon>
|
||||
</VAvatar>
|
||||
</template>
|
||||
<VCardTitle>扫描目录</VCardTitle>
|
||||
|
||||
@@ -1,11 +1,29 @@
|
||||
<script lang="ts" setup>
|
||||
import api from '@/api'
|
||||
import useDragAndDrop from '@core/utils/workflow'
|
||||
import { useDisplay } from 'vuetify'
|
||||
|
||||
interface ActionItem {
|
||||
name: string
|
||||
type: string
|
||||
desc?: string
|
||||
}
|
||||
|
||||
const display = useDisplay()
|
||||
// APP
|
||||
const appMode = inject('pwaMode') && display.mdAndDown.value
|
||||
|
||||
const { onDragStart } = useDragAndDrop()
|
||||
|
||||
// 组件列表
|
||||
const actions = ref([])
|
||||
const actions = ref<ActionItem[]>([])
|
||||
// 侧边栏是否收起 (仅在桌面端有效)
|
||||
const isSidebarCollapsed = ref(false)
|
||||
// 侧边栏在移动端是否显示
|
||||
const showMobileSidebar = ref(false)
|
||||
|
||||
// 定义emit
|
||||
const emit = defineEmits(['component-click'])
|
||||
|
||||
// 加载组件列表
|
||||
async function load_actions() {
|
||||
@@ -16,25 +34,382 @@ async function load_actions() {
|
||||
}
|
||||
}
|
||||
|
||||
// 切换侧边栏收起状态
|
||||
function toggleSidebar() {
|
||||
isSidebarCollapsed.value = !isSidebarCollapsed.value
|
||||
}
|
||||
|
||||
// 切换移动端侧边栏显示状态
|
||||
function toggleMobileSidebar() {
|
||||
showMobileSidebar.value = !showMobileSidebar.value
|
||||
}
|
||||
|
||||
// 处理移动端点击组件事件
|
||||
function handleComponentClick(action: ActionItem) {
|
||||
// 向父组件发送事件
|
||||
emit('component-click', action)
|
||||
// 关闭侧边栏
|
||||
showMobileSidebar.value = false
|
||||
}
|
||||
|
||||
// 根据动作类型获取图标
|
||||
function getActionIcon(type: string): string {
|
||||
const iconMap: Record<string, string> = {
|
||||
'AddSubscribeAction': 'mdi-star-plus',
|
||||
'AddDownloadAction': 'mdi-download',
|
||||
'FetchDownloadsAction': 'mdi-progress-download',
|
||||
'FetchMediasAction': 'mdi-movie-search',
|
||||
'FetchRssAction': 'mdi-rss',
|
||||
'FetchTorrentsAction': 'mdi-search-web',
|
||||
'FilterMediasAction': 'mdi-filter-check',
|
||||
'FilterTorrentsAction': 'mdi-filter-multiple',
|
||||
'ScanFileAction': 'mdi-folder-search',
|
||||
'ScrapeFileAction': 'mdi-file-find',
|
||||
'SendEventAction': 'mdi-send-check',
|
||||
'SendMessageAction': 'mdi-message-arrow-right',
|
||||
'TransferFileAction': 'mdi-file-move',
|
||||
}
|
||||
|
||||
return iconMap[type] || 'mdi-puzzle-outline'
|
||||
}
|
||||
|
||||
// 计算侧边栏类名
|
||||
const sidebarClasses = computed(() => {
|
||||
return {
|
||||
'sidebar-collapsed': isSidebarCollapsed.value && !display.smAndDown.value,
|
||||
'sidebar-mobile': display.smAndDown.value,
|
||||
'sidebar-mobile-open': showMobileSidebar.value && display.smAndDown.value,
|
||||
}
|
||||
})
|
||||
|
||||
// 监听屏幕尺寸变化,自动关闭移动端侧边栏
|
||||
watch(
|
||||
() => display.smAndDown.value,
|
||||
isMobile => {
|
||||
if (!isMobile) {
|
||||
showMobileSidebar.value = false
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
load_actions()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<aside>
|
||||
<div class="mb-3"><VLabel>可选动作组件:</VLabel></div>
|
||||
<!-- 移动端触发按钮 -->
|
||||
<div
|
||||
v-if="display.smAndDown.value"
|
||||
class="workflow-sidebar-trigger"
|
||||
:class="appMode ? 'right-4 bottom-28' : 'right-4 bottom-4'"
|
||||
@click="toggleMobileSidebar"
|
||||
>
|
||||
<VBtn icon size="large" class="workflow-sidebar-fab">
|
||||
<VIcon :icon="showMobileSidebar ? 'mdi-close' : 'mdi-plus'" />
|
||||
</VBtn>
|
||||
</div>
|
||||
|
||||
<div class="nodes flex flex-wrap justify-center">
|
||||
<div
|
||||
class="vue-flow__node-default cursor-grab mx-1"
|
||||
v-for="(action, index) in actions"
|
||||
:key="index"
|
||||
:draggable="true"
|
||||
@dragstart="onDragStart($event, action)"
|
||||
>
|
||||
{{ action['name'] }}
|
||||
<!-- 侧边栏 -->
|
||||
<aside class="workflow-sidebar" :class="sidebarClasses">
|
||||
<div class="sidebar-container">
|
||||
<!-- 侧边栏头部 -->
|
||||
<div class="sidebar-header">
|
||||
<div class="header-content">
|
||||
<VAvatar size="36" class="workflow-logo">
|
||||
<VIcon icon="mdi-puzzle" />
|
||||
</VAvatar>
|
||||
<span v-if="!isSidebarCollapsed || display.smAndDown.value" class="header-title">动作组件</span>
|
||||
<IconBtn v-if="!display.smAndDown.value" @click="toggleSidebar" class="collapse-btn">
|
||||
<VIcon :icon="isSidebarCollapsed ? 'mdi-chevron-right' : 'mdi-chevron-left'" />
|
||||
</IconBtn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 组件列表 -->
|
||||
<div class="components-container">
|
||||
<div
|
||||
v-for="(action, index) in actions"
|
||||
:key="index"
|
||||
class="component-item"
|
||||
:draggable="!display.smAndDown.value"
|
||||
@dragstart="!display.smAndDown.value && onDragStart($event, action)"
|
||||
@click="display.smAndDown.value && handleComponentClick(action)"
|
||||
>
|
||||
<div class="component-card">
|
||||
<VAvatar size="36" class="component-avatar">
|
||||
<VIcon :icon="getActionIcon(action.type)" size="18" />
|
||||
</VAvatar>
|
||||
<div v-if="!isSidebarCollapsed || display.smAndDown.value" class="component-info">
|
||||
<div class="component-name">{{ action.name }}</div>
|
||||
<div class="component-desc">{{ display.smAndDown.value ? '点击添加' : '拖动到画布' }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 底部提示 -->
|
||||
<div class="sidebar-footer">
|
||||
<VBtn block class="drag-btn">
|
||||
<div class="btn-content">
|
||||
<VIcon v-if="isSidebarCollapsed && !display.smAndDown.value" class="footer-icon" icon="mdi-gesture-swipe" />
|
||||
<template v-else>
|
||||
<VIcon :icon="display.smAndDown.value ? 'mdi-gesture-tap' : 'mdi-gesture-swipe'" class="me-2" />
|
||||
<span>{{ display.smAndDown.value ? '点击组件添加到画布' : '拖动组件到画布' }}</span>
|
||||
</template>
|
||||
</div>
|
||||
</VBtn>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@use 'sass:color';
|
||||
|
||||
.workflow-sidebar {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
overflow: hidden;
|
||||
background-color: #f5f5f7;
|
||||
box-shadow: 0 0 15px rgba(0, 0, 0, 8%);
|
||||
inline-size: 280px;
|
||||
inset-block: 0;
|
||||
inset-inline-start: 0;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&.sidebar-collapsed {
|
||||
inline-size: 70px;
|
||||
}
|
||||
|
||||
&.sidebar-mobile {
|
||||
inline-size: 240px;
|
||||
transform: translateX(-100%);
|
||||
|
||||
&.sidebar-mobile-open {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
flex-shrink: 0;
|
||||
padding: 16px;
|
||||
background-color: #fff;
|
||||
border-block-end: 1px solid rgba(0, 0, 0, 6%);
|
||||
|
||||
.header-content {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.workflow-logo {
|
||||
background-color: #8c58f5;
|
||||
color: white;
|
||||
margin-inline-end: 10px;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
color: #1a1a1a;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.collapse-btn {
|
||||
position: absolute;
|
||||
color: #8c58f5;
|
||||
inset-block-start: 0;
|
||||
inset-inline-end: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.components-container {
|
||||
flex: 1;
|
||||
padding: 12px;
|
||||
overflow-y: auto;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
inline-size: 5px;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
background-color: rgba(140, 88, 245, 30%);
|
||||
}
|
||||
}
|
||||
|
||||
.component-item {
|
||||
cursor: grab;
|
||||
margin-block-end: 10px;
|
||||
|
||||
&:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
}
|
||||
|
||||
.component-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 10px;
|
||||
border-radius: 12px;
|
||||
background-color: #e4e4e7;
|
||||
transition: all 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
background-color: #d4d4d8;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
}
|
||||
|
||||
.component-avatar {
|
||||
flex-shrink: 0;
|
||||
background-color: #8c58f5;
|
||||
color: white;
|
||||
margin-inline-end: 12px;
|
||||
|
||||
.v-icon {
|
||||
color: white !important;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.component-info {
|
||||
overflow: hidden;
|
||||
max-inline-size: calc(100% - 48px);
|
||||
}
|
||||
|
||||
.component-name {
|
||||
overflow: hidden;
|
||||
color: #1a1a1a;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.component-desc {
|
||||
overflow: hidden;
|
||||
color: #71717a;
|
||||
font-size: 12px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
flex-shrink: 0;
|
||||
padding: 12px;
|
||||
background-color: #fff;
|
||||
border-block-start: 1px solid rgba(0, 0, 0, 6%);
|
||||
|
||||
.drag-btn {
|
||||
background-color: #8c58f5;
|
||||
block-size: 44px;
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
letter-spacing: normal;
|
||||
text-transform: none;
|
||||
|
||||
&:hover {
|
||||
background-color: color.adjust(#8c58f5, $lightness: -5%);
|
||||
}
|
||||
|
||||
.btn-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
inline-size: 100%;
|
||||
}
|
||||
|
||||
.footer-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 移动端悬浮按钮
|
||||
.workflow-sidebar-trigger {
|
||||
position: fixed;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.workflow-sidebar-fab {
|
||||
background-color: #8c58f5;
|
||||
box-shadow: 0 4px 10px rgba(140, 88, 245, 40%);
|
||||
color: white;
|
||||
|
||||
&:hover {
|
||||
background-color: color.adjust(#8c58f5, $lightness: -5%);
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-collapsed {
|
||||
.component-card {
|
||||
justify-content: center;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.component-avatar {
|
||||
block-size: 40px !important;
|
||||
inline-size: 40px !important;
|
||||
margin-inline-end: 0;
|
||||
|
||||
.v-icon {
|
||||
font-size: 20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
padding-block: 10px;
|
||||
padding-inline: 6px;
|
||||
|
||||
.drag-btn {
|
||||
padding: 0;
|
||||
border-radius: 10px;
|
||||
block-size: 48px;
|
||||
inline-size: 100%;
|
||||
min-inline-size: 0;
|
||||
|
||||
.btn-content {
|
||||
inline-size: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 600px) {
|
||||
.component-card {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.component-item {
|
||||
margin-block-end: 8px;
|
||||
}
|
||||
|
||||
.components-container {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.sidebar-footer {
|
||||
padding: 8px;
|
||||
|
||||
.drag-btn {
|
||||
block-size: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user