pipipi-pikachu 5 yıl önce
ebeveyn
işleme
f002b05cdc

+ 3 - 0
src/assets/styles/antd.scss

@@ -13,4 +13,7 @@
 }
 .ant-btn {
   font-size: 13px !important;
+}
+.ant-select-item-option-content {
+  font-size: 13px !important;
 }

+ 1 - 1
src/assets/styles/prosemirror.scss

@@ -7,7 +7,7 @@
   font-family: '微软雅黑';
 
   ::selection {
-    background-color: rgba(#41464b, 0.3);
+    background-color: rgba(#d14424, 0.3);
     color: inherit;
   }
 

+ 2 - 1
src/assets/styles/variable.scss

@@ -1,2 +1,3 @@
-$themeColor: #41464b;
+$themeColor: #d14424;
+$textColor: #41464b;
 $borderRadius: 2px;

+ 1 - 1
src/configs/element.ts

@@ -1,4 +1,4 @@
-const DEFAULT_COLOR = '#41464b'
+const DEFAULT_COLOR = '#d14424'
 
 export const ELEMENT_TYPE = {
   'text': '文本',

+ 4 - 4
src/views/Editor/CanvasTool/index.vue

@@ -16,7 +16,7 @@
         </template>
         <StarOutlined class="handler-item" />
       </Popover>
-      <Popover trigger="click" v-model:visible="isOpenlinePool">
+      <Popover trigger="click" v-model:visible="isOpenLinePool">
         <template #content>
           <LinePool @select="line => drawLine(line)" />
         </template>
@@ -100,7 +100,7 @@ export default defineComponent({
     }
 
     const isOpenShapePool = ref(false)
-    const isOpenlinePool = ref(false)
+    const isOpenLinePool = ref(false)
     const drawText = () => {
       store.commit(MutationTypes.SET_CREATING_ELEMENT, {
         type: 'text',
@@ -119,7 +119,7 @@ export default defineComponent({
         type: 'line',
         data: line,
       })
-      isOpenShapePool.value = false
+      isOpenLinePool.value = false
     }
 
     return {
@@ -131,7 +131,7 @@ export default defineComponent({
       undo,
       insertImageElement,
       isOpenShapePool,
-      isOpenlinePool,
+      isOpenLinePool,
       drawText,
       drawShape,
       drawLine,

+ 1 - 1
src/views/Editor/EditorHeader/index.vue

@@ -45,7 +45,7 @@ export default defineComponent({
 }
 .menu-item {
   font-size: 13px;
-  color: $themeColor;
+  color: $textColor;
   margin: 0 10px;
   cursor: pointer;
 

+ 23 - 82
src/views/Editor/Toolbar/ElementStylePanel/TextStylePanel.vue

@@ -96,76 +96,31 @@
 
     <Divider />
 
-    <div class="row">
-      <div style="flex: 2;">描边样式:</div>
-      <Select style="flex: 3;" :value="wordSpace">
-        <template #suffixIcon><ColumnWidthOutlined /></template>
-        <SelectOption v-for="item in wordSpaceOptions" :key="item" :value="item">{{item}}</SelectOption>
-      </Select>
-    </div>
-    <div class="row">
-      <div style="flex: 2;">描边颜色:</div>
-      <Popover trigger="click">
-        <template #content>
-          <ColorPicker v-model="fill" />
-        </template>
-        <Button class="color-btn" style="flex: 3;">
-          <div class="color-block"></div>
-          <DownOutlined class="color-btn-icon" />
-        </Button>
-      </Popover>
-    </div>
-    <div class="row">
-      <div style="flex: 2;">描边粗细:</div>
-      <InputNumber style="flex: 3;" />
-    </div>
+    <ElementOutline />
 
     <Divider />
 
-    <div class="row">
-      <div style="flex: 2;">水平阴影:</div>
-      <Slider :min="0" :max="1" :step="0.1" :value="opacity" style="flex: 3;" />
-    </div>
-    <div class="row">
-      <div style="flex: 2;">垂直阴影:</div>
-      <Slider :min="0" :max="1" :step="0.1" :value="opacity" style="flex: 3;" />
-    </div>
-    <div class="row">
-      <div style="flex: 2;">模糊距离:</div>
-      <Slider :min="0" :max="1" :step="0.1" :value="opacity" style="flex: 3;" />
-    </div>
-    <div class="row">
-      <div style="flex: 2;">阴影颜色:</div>
-      <Popover trigger="click">
-        <template #content>
-          <ColorPicker v-model="fill" />
-        </template>
-        <Button class="color-btn" style="flex: 3;">
-          <div class="color-block"></div>
-          <DownOutlined class="color-btn-icon" />
-        </Button>
-      </Popover>
-    </div>
+    <ElementShadow />
 
     <Divider />
 
-    <div class="row">
-      <div style="flex: 2;">透明度:</div>
-      <Slider :min="0" :max="1" :step="0.1" :value="opacity" style="flex: 3;" />
-    </div>
+    <ElementOpacity />
   </div>
 </template>
 
 <script lang="ts">
-import { computed, defineComponent, onUnmounted, ref } from 'vue'
+import { computed, defineComponent, onUnmounted, Ref, ref, watch } from 'vue'
 import { useStore } from 'vuex'
 import { State } from '@/store'
-import { PPTElementOutline, PPTElementShadow } from '@/types/slides'
+import { PPTTextElement } from '@/types/slides'
 import emitter, { EmitterEvents } from '@/utils/emitter'
 import { TextAttrs } from '@/prosemirror/utils'
 
+import ElementOpacity from '../common/ElementOpacity.vue'
+import ElementOutline from '../common/ElementOutline.vue'
+import ElementShadow from '../common/ElementShadow.vue'
 import ColorPicker from '@/components/ColorPicker/index.vue'
-import { Select, Input, Button, Divider, Slider, Popover, InputNumber } from 'ant-design-vue'
+import { Select, Input, Button, Divider, Popover } from 'ant-design-vue'
 import {
   FontColorsOutlined,
   HighlightOutlined,
@@ -181,7 +136,6 @@ import {
   UnorderedListOutlined,
   ColumnHeightOutlined,
   ColumnWidthOutlined,
-  DownOutlined,
 } from '@ant-design/icons-vue'
 
 export default defineComponent({
@@ -194,9 +148,7 @@ export default defineComponent({
     Button,
     ButtonGroup: Button.Group,
     Divider,
-    Slider,
     Popover,
-    InputNumber,
     FontColorsOutlined,
     HighlightOutlined,
     BgColorsOutlined,
@@ -211,17 +163,24 @@ export default defineComponent({
     UnorderedListOutlined,
     ColumnHeightOutlined,
     ColumnWidthOutlined,
-    DownOutlined,
+    ElementOpacity,
+    ElementOutline,
+    ElementShadow,
   },
   setup() {
     const store = useStore<State>()
+    const handleElement: Ref<PPTTextElement> = computed(() => store.getters.handleElement)
 
-    const fill = ref('#000')
-    const lineHeight = ref(1.5)
-    const wordSpace = ref(0)
-    const opacity = ref(1)
-    const shadow = ref<PPTElementShadow>()
-    const outline = ref<PPTElementOutline>()
+    const fill = ref<string>()
+    const lineHeight = ref<number>()
+    const wordSpace = ref<number>()
+
+    watch(handleElement, () => {
+      if(!handleElement.value) return
+      fill.value = handleElement.value.fill || '#000'
+      lineHeight.value = handleElement.value.lineHeight || 1.5
+      wordSpace.value = handleElement.value.wordSpace || 0
+    }, { deep: true, immediate: true })
 
     const richTextAttrs = ref<TextAttrs>({
       bold: false,
@@ -260,9 +219,6 @@ export default defineComponent({
       fill,
       lineHeight,
       wordSpace,
-      opacity,
-      shadow,
-      outline,
       richTextAttrs,
       availableFonts,
       fontSizeOptions,
@@ -291,19 +247,4 @@ export default defineComponent({
   height: 3px;
   margin-top: 1px;
 }
-.color-btn {
-  display: flex;
-  align-items: center;
-  padding: 0 !important;
-}
-.color-block {
-  width: 100px;
-  height: 20px;
-  background-color: #777;
-  margin: 0 8px;
-}
-.color-btn-icon {
-  font-size: 12px;
-  margin-top: 2px;
-}
 </style>

+ 48 - 0
src/views/Editor/Toolbar/common/ElementOpacity.vue

@@ -0,0 +1,48 @@
+<template>
+  <div class="element-opacity">
+    <div class="row">
+      <div style="flex: 2;">不透明度:</div>
+      <Slider :min="0" :max="1" :step="0.1" :value="opacity" style="flex: 3;" />
+    </div>
+  </div>
+</template>
+
+<script lang="ts">
+import { computed, defineComponent, Ref, ref, watch } from 'vue'
+import { useStore } from 'vuex'
+import { State } from '@/store'
+import { PPTElement } from '@/types/slides'
+
+import { Slider } from 'ant-design-vue'
+
+export default defineComponent({
+  name: 'element-opacity',
+  components: {
+    Slider,
+  },
+  setup() {
+    const store = useStore<State>()
+    const handleElement: Ref<PPTElement> = computed(() => store.getters.handleElement)
+
+    const opacity = ref<number>()
+
+    watch(handleElement, () => {
+      if(!handleElement.value) return
+      opacity.value = 'opacity' in handleElement.value && handleElement.value.opacity || 1
+    }, { deep: true, immediate: true })
+
+    return {
+      opacity,
+    }
+  },
+})
+</script>
+
+<style lang="scss" scoped>
+.row {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  margin-bottom: 10px;
+}
+</style>

+ 118 - 0
src/views/Editor/Toolbar/common/ElementOutline.vue

@@ -0,0 +1,118 @@
+<template>
+  <div class="element-outline">
+    <div class="row">
+      <div style="flex: 2;">启用边框:</div>
+      <div class="switch-wrapper" style="flex: 3;">
+        <Switch :checked="hasOutline" @change="checked => toggleOutline(checked)" />
+      </div>
+    </div>
+    <template v-if="hasOutline">
+      <div class="row">
+        <div style="flex: 2;">边框样式:</div>
+        <Select style="flex: 3;" :value="outline.style">
+          <SelectOption value="solid">实线边框</SelectOption>
+          <SelectOption value="dashed">虚线边框</SelectOption>
+        </Select>
+      </div>
+      <div class="row">
+        <div style="flex: 2;">边框颜色:</div>
+        <Popover trigger="click">
+          <template #content>
+            <ColorPicker v-model="outline.color" />
+          </template>
+          <Button class="color-btn" style="flex: 3;">
+            <div class="color-block" :style="{ backgroundColor: outline.color }"></div>
+            <DownOutlined class="color-btn-icon" />
+          </Button>
+        </Popover>
+      </div>
+      <div class="row">
+        <div style="flex: 2;">边框粗细:</div>
+        <InputNumber :value="outline.width" style="flex: 3;" />
+      </div>
+    </template>
+  </div>
+</template>
+
+<script lang="ts">
+import { computed, defineComponent, Ref, ref, watch } from 'vue'
+import { useStore } from 'vuex'
+import { State } from '@/store'
+import { PPTElement, PPTElementOutline } from '@/types/slides'
+
+import ColorPicker from '@/components/ColorPicker/index.vue'
+import { Select, Button, Popover, InputNumber, Switch } from 'ant-design-vue'
+import { DownOutlined } from '@ant-design/icons-vue'
+
+export default defineComponent({
+  name: 'element-outline',
+  components: {
+    ColorPicker,
+    Select,
+    SelectOption: Select.Option,
+    Button,
+    Popover,
+    InputNumber,
+    Switch,
+    DownOutlined,
+  },
+  setup() {
+    const store = useStore<State>()
+    const handleElement: Ref<PPTElement> = computed(() => store.getters.handleElement)
+
+    const outline = ref<PPTElementOutline>()
+    const hasOutline = ref(false)
+
+    watch(handleElement, () => {
+      if(!handleElement.value) return
+      outline.value = 'outline' in handleElement.value && handleElement.value.outline || undefined
+      hasOutline.value = !!outline.value
+    }, { deep: true, immediate: true })
+
+    const toggleOutline = (checked: boolean) => {
+      if(!checked) {
+        outline.value = undefined
+        hasOutline.value = false
+      }
+      else {
+        outline.value = { width: 2, color: '#000', style: 'solid' }
+        hasOutline.value = true
+      }
+    }
+
+    return {
+      outline,
+      hasOutline,
+      toggleOutline,
+    }
+  },
+})
+</script>
+
+<style lang="scss" scoped>
+.row {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  margin-bottom: 10px;
+}
+.color-btn {
+  display: flex;
+  align-items: center;
+  padding: 0 !important;
+}
+.color-block {
+  width: 100px;
+  height: 20px;
+  background-color: #777;
+  margin: 0 8px;
+}
+.color-btn-icon {
+  font-size: 12px;
+  margin-top: 2px;
+  color: #bfbfbf;
+}
+.switch-wrapper {
+  text-align: right;
+}
+</style>

+ 117 - 0
src/views/Editor/Toolbar/common/ElementShadow.vue

@@ -0,0 +1,117 @@
+<template>
+  <div class="element-shadow">
+    <div class="row">
+      <div style="flex: 2;">启用阴影:</div>
+      <div class="switch-wrapper" style="flex: 3;">
+        <Switch :checked="hasShadow" @change="checked => toggleShadow(checked)" />
+      </div>
+    </div>
+    <template v-if="hasShadow">
+      <div class="row">
+        <div style="flex: 2;">水平阴影:</div>
+        <Slider :min="1" :max="10" :step="1" :value="shadow.h" style="flex: 3;" />
+      </div>
+      <div class="row">
+        <div style="flex: 2;">垂直阴影:</div>
+        <Slider :min="1" :max="10" :step="1" :value="shadow.v" style="flex: 3;" />
+      </div>
+      <div class="row">
+        <div style="flex: 2;">模糊距离:</div>
+        <Slider :min="1" :max="20" :step="1" :value="shadow.blur" style="flex: 3;" />
+      </div>
+      <div class="row">
+        <div style="flex: 2;">阴影颜色:</div>
+        <Popover trigger="click">
+          <template #content>
+            <ColorPicker v-model="shadow.color" />
+          </template>
+          <Button class="color-btn" style="flex: 3;">
+            <div class="color-block"></div>
+            <DownOutlined class="color-btn-icon" />
+          </Button>
+        </Popover>
+      </div>
+    </template>
+  </div>
+</template>
+
+<script lang="ts">
+import { computed, defineComponent, Ref, ref, watch } from 'vue'
+import { useStore } from 'vuex'
+import { State } from '@/store'
+import { PPTElement, PPTElementShadow } from '@/types/slides'
+
+import ColorPicker from '@/components/ColorPicker/index.vue'
+import { Slider, Button, Popover, Switch } from 'ant-design-vue'
+import { DownOutlined } from '@ant-design/icons-vue'
+
+export default defineComponent({
+  name: 'element-shadow',
+  components: {
+    ColorPicker,
+    Slider,
+    Button,
+    Popover,
+    Switch,
+    DownOutlined,
+  },
+  setup() {
+    const store = useStore<State>()
+    const handleElement: Ref<PPTElement> = computed(() => store.getters.handleElement)
+
+    const shadow = ref<PPTElementShadow>()
+    const hasShadow = ref(false)
+
+    watch(handleElement, () => {
+      if(!handleElement.value) return
+      shadow.value = 'shadow' in handleElement.value && handleElement.value.shadow || undefined
+      hasShadow.value = !!shadow.value
+    }, { deep: true, immediate: true })
+
+    const toggleShadow = (checked: boolean) => {
+      if(!checked) {
+        shadow.value = undefined
+        hasShadow.value = false
+      }
+      else {
+        shadow.value = { h: 1, v: 1, blur: 2, color: '#000' }
+        hasShadow.value = true
+      }
+    }
+
+    return {
+      shadow,
+      hasShadow,
+      toggleShadow,
+    }
+  },
+})
+</script>
+
+<style lang="scss" scoped>
+.row {
+  width: 100%;
+  display: flex;
+  align-items: center;
+  margin-bottom: 10px;
+}
+.color-btn {
+  display: flex;
+  align-items: center;
+  padding: 0 !important;
+}
+.color-block {
+  width: 100px;
+  height: 20px;
+  background-color: #777;
+  margin: 0 8px;
+}
+.color-btn-icon {
+  font-size: 12px;
+  margin-top: 2px;
+  color: #bfbfbf;
+}
+.switch-wrapper {
+  text-align: right;
+}
+</style>

+ 1 - 1
src/views/components/element/hooks/useElementOutline.ts

@@ -4,7 +4,7 @@ import { PPTElementOutline } from '@/types/slides'
 export default (outline: Ref<PPTElementOutline | undefined>) => {
   const outlineWidth = computed(() => (outline.value && outline.value.width !== undefined) ? outline.value.width : 0)
   const outlineStyle = computed(() => (outline.value && outline.value.style !== undefined) ? outline.value.style : 'solid')
-  const outlineColor = computed(() => (outline.value && outline.value.color !== undefined) ? outline.value.color : '#41464b')
+  const outlineColor = computed(() => (outline.value && outline.value.color !== undefined) ? outline.value.color : '#d14424')
 
   return {
     outlineWidth,

+ 2 - 2
vue.config.js

@@ -12,8 +12,8 @@ module.exports = {
       less: {
         lessOptions: {
           modifyVars: {
-            'primary-color': '#41464b',
-            'link-color': '#41464b',
+            'primary-color': '#d14424',
+            'link-color': '#d14424',
           },
           javascriptEnabled: true,
         },