ShapeStylePanel.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. <template>
  2. <div class="shape-style-panel">
  3. <div class="row">
  4. <Select
  5. style="flex: 10;"
  6. :value="fillType"
  7. @change="value => updateFillType(value)"
  8. >
  9. <SelectOption value="fill">纯色填充</SelectOption>
  10. <SelectOption value="gradient">渐变填充</SelectOption>
  11. </Select>
  12. <div style="flex: 1;"></div>
  13. <Popover trigger="click" v-if="fillType === 'fill'">
  14. <template #content>
  15. <ColorPicker
  16. :modelValue="fill"
  17. @update:modelValue="value => updateFill(value)"
  18. />
  19. </template>
  20. <ColorButton :color="fill" style="flex: 10;" />
  21. </Popover>
  22. <Select
  23. style="flex: 10;"
  24. :value="gradient.type"
  25. @change="value => updateGradient({ type: value })"
  26. v-else
  27. >
  28. <SelectOption value="linear">线性渐变</SelectOption>
  29. <SelectOption value="radial">径向渐变</SelectOption>
  30. </Select>
  31. </div>
  32. <template v-if="fillType === 'gradient'">
  33. <div class="row">
  34. <div style="flex: 2;">起点颜色:</div>
  35. <Popover trigger="click">
  36. <template #content>
  37. <ColorPicker
  38. :modelValue="gradient.color[0]"
  39. @update:modelValue="value => updateGradient({ color: [value, gradient.color[1]] })"
  40. />
  41. </template>
  42. <ColorButton :color="gradient.color[0]" style="flex: 3;" />
  43. </Popover>
  44. </div>
  45. <div class="row">
  46. <div style="flex: 2;">终点颜色:</div>
  47. <Popover trigger="click">
  48. <template #content>
  49. <ColorPicker
  50. :modelValue="gradient.color[1]"
  51. @update:modelValue="value => updateGradient({ color: [gradient.color[0], value] })"
  52. />
  53. </template>
  54. <ColorButton :color="gradient.color[1]" style="flex: 3;" />
  55. </Popover>
  56. </div>
  57. <div class="row" v-if="gradient.type === 'linear'">
  58. <div style="flex: 2;">渐变角度:</div>
  59. <Slider
  60. :min="0"
  61. :max="360"
  62. :step="15"
  63. :value="gradient.rotate"
  64. style="flex: 3;"
  65. @change="value => updateGradient({ rotate: value })"
  66. />
  67. </div>
  68. </template>
  69. <Divider />
  70. <ElementOutline />
  71. <Divider />
  72. <ElementShadow />
  73. <Divider />
  74. <ElementOpacity />
  75. </div>
  76. </template>
  77. <script lang="ts">
  78. import { computed, defineComponent, ref, watch } from 'vue'
  79. import { useStore } from 'vuex'
  80. import { MutationTypes, State } from '@/store'
  81. import { PPTShapeElement, ShapeGradient } from '@/types/slides'
  82. import useHistorySnapshot from '@/hooks/useHistorySnapshot'
  83. import ElementOpacity from '../common/ElementOpacity.vue'
  84. import ElementOutline from '../common/ElementOutline.vue'
  85. import ElementShadow from '../common/ElementShadow.vue'
  86. import ColorButton from '../common/ColorButton.vue'
  87. export default defineComponent({
  88. name: 'shape-style-panel',
  89. components: {
  90. ElementOpacity,
  91. ElementOutline,
  92. ElementShadow,
  93. ColorButton,
  94. },
  95. setup() {
  96. const store = useStore<State>()
  97. const handleElement = computed<PPTShapeElement>(() => store.getters.handleElement)
  98. const fill = ref<string>()
  99. const gradient = ref<ShapeGradient>()
  100. const fillType = ref('fill')
  101. watch(handleElement, () => {
  102. if(!handleElement.value || handleElement.value.type !== 'shape') return
  103. fill.value = handleElement.value.fill || '#000'
  104. gradient.value = handleElement.value.gradient || { type: 'linear', rotate: 0, color: [fill.value, '#fff'] }
  105. fillType.value = handleElement.value.gradient ? 'gradient' : 'fill'
  106. }, { deep: true, immediate: true })
  107. const { addHistorySnapshot } = useHistorySnapshot()
  108. const updateFillType = (type: 'gradient' | 'fill') => {
  109. if(type === 'fill') {
  110. store.commit(MutationTypes.REMOVE_ELEMENT_PROPS, {
  111. id: handleElement.value.id,
  112. propName: 'gradient',
  113. })
  114. }
  115. else {
  116. const props = { gradient: gradient.value }
  117. store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
  118. }
  119. addHistorySnapshot()
  120. }
  121. const updateGradient = (gradientProps: Partial<ShapeGradient>) => {
  122. const props = { gradient: { ...gradient.value, ...gradientProps } }
  123. store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
  124. addHistorySnapshot()
  125. }
  126. const updateFill = (value: string) => {
  127. const props = { fill: value }
  128. store.commit(MutationTypes.UPDATE_ELEMENT, { id: handleElement.value.id, props })
  129. addHistorySnapshot()
  130. }
  131. return {
  132. fill,
  133. gradient,
  134. fillType,
  135. updateFillType,
  136. updateFill,
  137. updateGradient,
  138. }
  139. },
  140. })
  141. </script>
  142. <style lang="scss" scoped>
  143. .row {
  144. width: 100%;
  145. display: flex;
  146. align-items: center;
  147. margin-bottom: 10px;
  148. }
  149. </style>