|
<template> |
|
<div class="line-style-panel"> |
|
<div class="row"> |
|
<div style="width: 40%;">线条样式:</div> |
|
<SelectCustom style="width: 60%;"> |
|
<template #options> |
|
<div class="option" v-for="item in lineStyleOptions" :key="item" @click="updateLine({ style: item })"> |
|
<SVGLine :type="item" /> |
|
</div> |
|
</template> |
|
<template #label> |
|
<SVGLine :type="handleLineElement.style" /> |
|
</template> |
|
</SelectCustom> |
|
</div> |
|
<div class="row"> |
|
<div style="width: 40%;">线条颜色:</div> |
|
<Popover trigger="click" style="width: 60%;"> |
|
<template #content> |
|
<ColorPicker |
|
:modelValue="handleLineElement.color" |
|
@update:modelValue="value => updateLine({ color: value })" |
|
/> |
|
</template> |
|
<ColorButton :color="handleLineElement.color" /> |
|
</Popover> |
|
</div> |
|
<div class="row"> |
|
<div style="width: 40%;">线条宽度:</div> |
|
<NumberInput |
|
:value="handleLineElement.width" |
|
@update:value="value => updateLine({ width: value })" |
|
style="width: 60%;" |
|
/> |
|
</div> |
|
|
|
<div class="row"> |
|
<div style="width: 40%;">起点样式:</div> |
|
<SelectCustom style="width: 60%;"> |
|
<template #options> |
|
<div class="option" v-for="item in lineMarkerOptions" :key="item" @click="updateLine({ points: [item, handleLineElement.points[1]] })"> |
|
<SVGLine :padding="5" :markers="[item, '']" /> |
|
</div> |
|
</template> |
|
<template #label> |
|
<SVGLine :padding="5" :markers="[handleLineElement.points[0], '']" /> |
|
</template> |
|
</SelectCustom> |
|
</div> |
|
<div class="row"> |
|
<div style="width: 40%;">终点样式:</div> |
|
<SelectCustom style="width: 60%;"> |
|
<template #options> |
|
<div class="option" v-for="item in lineMarkerOptions" :key="item" @click="updateLine({ points: [handleLineElement.points[0], item] })"> |
|
<SVGLine :padding="5" :markers="['', item]" /> |
|
</div> |
|
</template> |
|
<template #label> |
|
<SVGLine :padding="5" :markers="['', handleLineElement.points[1]]" /> |
|
</template> |
|
</SelectCustom> |
|
</div> |
|
|
|
<Divider /> |
|
|
|
<div class="row"> |
|
<Button style="flex: 1;" @click="updateLine({ start: handleLineElement.end, end: handleLineElement.start })"><IconSwitch /> 交换方向</Button> |
|
</div> |
|
|
|
<Divider /> |
|
<ElementShadow /> |
|
</div> |
|
</template> |
|
|
|
<script lang="ts" setup> |
|
import { type Ref, ref } from 'vue' |
|
import { storeToRefs } from 'pinia' |
|
import { useMainStore, useSlidesStore } from '@/store' |
|
import type { LinePoint, LineStyleType, PPTLineElement } from '@/types/slides' |
|
import useHistorySnapshot from '@/hooks/useHistorySnapshot' |
|
|
|
import ElementShadow from '../common/ElementShadow.vue' |
|
import SVGLine from '../common/SVGLine.vue' |
|
import Button from '@/components/Button.vue' |
|
import ColorButton from '@/components/ColorButton.vue' |
|
import ColorPicker from '@/components/ColorPicker/index.vue' |
|
import Divider from '@/components/Divider.vue' |
|
import NumberInput from '@/components/NumberInput.vue' |
|
import SelectCustom from '@/components/SelectCustom.vue' |
|
import Popover from '@/components/Popover.vue' |
|
|
|
const slidesStore = useSlidesStore() |
|
const { handleElement } = storeToRefs(useMainStore()) |
|
|
|
const handleLineElement = handleElement as Ref<PPTLineElement> |
|
|
|
const { addHistorySnapshot } = useHistorySnapshot() |
|
|
|
const lineStyleOptions = ref<LineStyleType[]>(['solid', 'dashed', 'dotted']) |
|
const lineMarkerOptions = ref<LinePoint[]>(['', 'arrow', 'dot']) |
|
|
|
const updateLine = (props: Partial<PPTLineElement>) => { |
|
if (!handleElement.value) return |
|
slidesStore.updateElement({ id: handleElement.value.id, props }) |
|
addHistorySnapshot() |
|
} |
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
.row { |
|
width: 100%; |
|
display: flex; |
|
align-items: center; |
|
margin-bottom: 10px; |
|
} |
|
.line-btn { |
|
display: flex; |
|
align-items: center; |
|
justify-content: space-between; |
|
padding: 0 !important; |
|
|
|
.line-wrapper { |
|
margin-left: 8px; |
|
} |
|
} |
|
.line-wrapper { |
|
overflow: visible; |
|
} |
|
.line-btn-icon { |
|
width: 30px; |
|
font-size: 12px; |
|
margin-top: 2px; |
|
color: #bfbfbf; |
|
} |
|
.preset-point-style { |
|
padding: 0 10px; |
|
|
|
& + .preset-point-style { |
|
margin-top: 10px; |
|
} |
|
} |
|
.option { |
|
height: 32px; |
|
padding: 0 5px; |
|
border-radius: $borderRadius; |
|
|
|
&:not(.selected):hover { |
|
background-color: rgba($color: $themeColor, $alpha: .05); |
|
cursor: pointer; |
|
} |
|
|
|
&.selected { |
|
color: $themeColor; |
|
font-weight: 700; |
|
} |
|
} |
|
</style> |