Browse Source

update: 签名面板外观

wzl 5 tháng trước cách đây
mục cha
commit
99f70ed3a0

+ 3 - 3
packages/core/src/signatures.js

@@ -1,5 +1,5 @@
 import { getInitialPoint } from './annotation/utils';
-import { isMobileDevice } from './ui_utils';
+import { isMobile } from './ui_utils';
 
 class Signatures {
   constructor({ pdfViewer, eventBus, type }) {
@@ -45,7 +45,7 @@ class Signatures {
 
     //计算鼠标在画布的距离
     let disX, disY
-    if (isMobileDevice) { // 横屏
+    if (isMobile && this.type) { // 横屏
       disX = clientY - this.canvas.getBoundingClientRect().top
       disY = this.canvas.height - (clientX - this.canvas.getBoundingClientRect().left)
     } else {
@@ -79,7 +79,7 @@ class Signatures {
     const clientY = e.clientY || e.changedTouches[0].clientY
 
     let disX, disY
-    if (isMobileDevice) { // 横屏
+    if (isMobile && this.type) { // 横屏
       disX = clientY - this.canvas.getBoundingClientRect().top
       disY = this.canvas.height - (clientX - this.canvas.getBoundingClientRect().left)
     } else {

+ 3 - 1
packages/core/src/ui_utils.js

@@ -73,6 +73,7 @@ const isIOS =
   }
 })();
 const isMobileDevice = isIOS || isAndroid || /webOS|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
+const isMobile = window.innerWidth < 640;
 
 // Used by `PDFViewerApplication`, and by the API unit-tests.
 const AutoPrintRegExp = /\bprint\s*\(/;
@@ -1945,5 +1946,6 @@ export {
   toDateObject,
   setCss,
   isMobileDevice,
-  convertColorToRGB
+  convertColorToRGB,
+  isMobile
 };

+ 1 - 1
packages/webview/index.html

@@ -5,7 +5,7 @@
     <link rel="icon" href="/favicon.ico">
     <!-- <link rel="stylesheet" data-hid="stylesheet" href="https://fonts.googleapis.com/css?family=Courier|Times|Courier:b,i,bi|Times:b,i,bi"> -->
     <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
-    <meta name="apple-mobile-web-app-capable" content="yes">
+    <meta name="mobile-web-app-capable" content="yes">
     <title>ComPDFKit Web Viewer</title>
   </head>
   <body>

+ 54 - 10
packages/webview/src/components/Dialogs/SignatureAppearanceDialog.vue

@@ -370,7 +370,8 @@ const openDrawPanel = () => {
 
   .dialog-container {
     padding: 15px 23px;
-    width: 628px;
+    max-width: 628px;
+    width: 100%;
     border-radius: 0;
     position: relative;
 
@@ -637,9 +638,8 @@ const openDrawPanel = () => {
   }
 }
 
-@media screen and (max-width: 628px) {
+@media screen and (min-width: 500px) and (max-width: 628px) {
   .signature-appearance-dialog .dialog-container {
-    width: 100%;
 
     footer {
       margin-top: 0;
@@ -661,14 +661,58 @@ const openDrawPanel = () => {
   }
 }
 
-@media screen and (max-width: 465px) {
-  .signature-appearance-dialog .configurations .text-align {
-    flex-direction: column;
-    align-items: normal;
+@media screen and (max-width: 499px) {
+  .signature-appearance-dialog .appearance-dialog {
+
+    .dialog-container {
+      padding: 15px 0;
+
+      header {
+        padding-left: 23px;
+        padding-right: 23px;
+      }
+
+      main {
+        margin-bottom: 0;
+        padding-left: 23px;
+        padding-right: 23px;
+      }
+
+      footer {
+        border-top: 1px solid #ccc;
+        margin-top: 0;
+        padding-top: 8px;
+
+        > div:last-child {
+          margin-right: 23px;
+        }
+      }
+    }
+
+    .configurations {
+      flex-direction: column;
+      height: 152px;
+      overflow: auto;
+      padding-bottom: 16px;
+
+      .right {
+        margin-top: 16px;
+        width: 100%;
+
+        .text-align {
+          flex-direction: column;
+          align-items: normal;
 
-    .buttons {
-      margin-left: 0;
-      margin-top: 4px;
+          .buttons {
+            margin-left: 0;
+            margin-top: 4px;
+          }
+        }
+
+        .addition > div {
+          margin-top: 8px;
+        }
+      }
     }
   }
 }

+ 6 - 0
packages/webview/src/components/SignatureToolBar/SignatureToolBar.vue

@@ -116,5 +116,11 @@
     }
   }
 }
+
+@media screen and (max-width: 670px) {
+  .signature-tool {
+    width: 100%;
+  }
+}
 </style>
 

+ 27 - 46
packages/webview/src/components/Signatures/DigitalSignCreatePanel.vue

@@ -1,5 +1,5 @@
 <template>
-  <Dialog class="digital-signature-dialog" :show="true" :dialogName="dialogName">
+  <Dialog class="digital-signature-dialog trackpad" :show="true" :dialogName="dialogName">
     <template #header>
       <CloseB class="close" @click="close" />
     </template>
@@ -21,7 +21,7 @@ import { computed, watch, ref, nextTick } from 'vue'
 import { useViewerStore } from '@/stores/modules/viewer'
 import { useDocumentStore } from '@/stores/modules/document'
 import core from '@/core'
-import { isMobileDevice } from '@/helpers/device'
+import { isMobile } from '@/helpers/device'
 
 const emits = defineEmits(['modifyImage'])
 const dialogName = 'digitalSignCreatePanel'
@@ -32,12 +32,12 @@ const useDocument = useDocumentStore()
 const show = computed(() => useViewer.isElementOpen(dialogName))
 
 const canvasWidth = ref(578)
-const canvasHeight = ref(270)
+const canvasHeight = ref(isMobile ? 0 : 270)
 const paintContainer = ref()
 
 watch(() => show.value, (newValue, oldValue) => {
   if (newValue) {
-    if (isMobileDevice) {
+    if (isMobile) {
       nextTick(() => {
         const { clientWidth, clientHeight } = paintContainer.value
         clientWidth && canvasWidth.value !== clientWidth && (canvasWidth.value = clientWidth)
@@ -71,42 +71,6 @@ const save = () => {
 <style lang="scss">
 .digital-signature-dialog {
 
-  .dialog-container {
-    padding: 15px 23px;
-    width: 628px;
-    border-radius: 0;
-    position: relative;
-
-    header {
-      p {
-        font-size: 14px;
-        line-height: 16px;
-        font-weight: 400;
-        color: var(--c-right-side-header-text);
-      }
-
-      .close {
-        position: absolute;
-        top: 8px;
-        right: 8px;
-        margin: 0;
-        cursor: pointer;
-      }
-    }
-
-    main {
-      margin-top: 24px;
-      margin-bottom: 20px;
-    }
-
-    footer {
-
-      .rect-button {
-        border-radius: 4px;
-      }
-    }
-  }
-
   .dialog-container {
     padding: 16px 24px;
 
@@ -132,7 +96,7 @@ const save = () => {
     display: flex;
     justify-content: center;
     align-items: center;
-    height: 240px;
+    height: 270px;
     background-color: #F2F3F5;
 
     canvas {
@@ -149,12 +113,29 @@ const save = () => {
   }
 }
 
-@media screen and (max-width: 628px) {
-  .digital-signature-dialog .dialog-container {
-    width: 100%;
+@media screen and (max-width: 640px) {
 
-    footer {
-      margin-top: 0;
+  .digital-signature-dialog.trackpad {
+
+    .dialog-container {
+      display: flex;
+      flex-direction: column;
+      width: 90vh;
+      height: 90vw;
+      transform: rotate(90deg);
+      -ms-transform: rotate(90deg);
+      -moz-transform: rotate(90deg);
+      -webkit-transform: rotate(90deg);
+      -o-transform: rotate(90deg);
+
+      main {
+        flex: 1;
+
+        .paint-container {
+          width: 100%;
+          height: 100%;
+        }
+      }
     }
   }
 }

+ 105 - 104
packages/webview/src/components/Signatures/SignCreatePanel.vue

@@ -1,12 +1,27 @@
 <template>
-  <div class="signatures-popup" :class="{ mobile: isMobileDevice }">
+  <div class="signatures-popup">
     <div class="sign-popup-header">
       <div @click="changeActiveSignWay('trackpad')" :class="{ active: activeSignWay === 'trackpad' }">{{ $t('signatures.trackpad') }}</div>
       <div @click="changeActiveSignWay('keyboard')" :class="{ active: activeSignWay === 'keyboard' }">{{ $t('signatures.keyboard') }}</div>
       <div @click="changeActiveSignWay('image')" :class="{ active: activeSignWay === 'image' }">{{ $t('signatures.image') }}</div>
+    </div>
+
+    <div :class="{ mobile: isMobile }">
+      <div class="paint-container" ref="paintContainer">
+        <canvas v-show="activeSignWay === 'trackpad'" id="electronicTrackpadCanvas" :width="canvasWidth" :height="canvasHeight"></canvas>
+
+        <div class="keyboard-paint" v-show="activeSignWay === 'keyboard'">
+          <input type="text" :placeholder="$t('signatures.signHere')" v-model="textSgin" name="signature">
+        </div>
+
+        <div class="image-paint" v-show="activeSignWay === 'image'">
+          <a>{{ $t('signatures.selectFile') }}<input type="file" id="signImageInput" @change="handleFile" accept=".png, .jpg, .jpeg" @click="clickUpload" name="signature"></a>
+        </div>
+      </div>
 
-      <div v-if="isMobileDevice" class="property-container">
+      <div class="property-container" v-show="['trackpad', 'keyboard'].includes(activeSignWay)">
         <div v-show="activeSignWay === 'trackpad'" class="width-tool">
+          <span v-if="!isMobile">{{ $t('signatures.lineWidth') }}</span>
           <n-slider v-model:value="widthValue" :step="1" :max="10" :min="1" class="width-slider">
             <template #thumb>
               <Slider />
@@ -16,7 +31,7 @@
         </div>
 
         <div v-show="activeSignWay === 'keyboard'" class="font-tool">
-          <span>{{ $t('font') }}</span>
+          <span v-if="!isMobile">{{ $t('font') }}</span>
           <select id="fontFamily" v-model="fontFamily"  v-on:change="handleFontChange">
             <option value="Arial">Arial</option>
             <option value="Courier New">Courier New</option>
@@ -25,81 +40,39 @@
         </div>
 
         <div v-show="activeSignWay === 'trackpad' || activeSignWay === 'keyboard'" class="color-tool">
+          <span v-if="!isMobile">{{ $t('color') }}</span>
           <div class="colors-container">
             <span class="cell-container">
-              <span class="cell-outer" :class="{ active: fontColor === '#FF0000' }" @click="setActiveToolColor('#FF0000')">
+              <span class="cell-outer" :class="{ active: areColorsSimilar(fontColor, 'rgb(255, 0, 0)') }" @click="setActiveToolColor('rgb(255, 0, 0)')">
                 <span class="cell red"></span></span>
             </span>
             <span class="cell-container">
-              <span class="cell-outer" :class="{ active: fontColor === '#000000' }" @click="setActiveToolColor('#000000')">
+              <span class="cell-outer" :class="{ active: areColorsSimilar(fontColor, 'rgb(0, 0, 0)') }" @click="setActiveToolColor('rgb(0, 0, 0)')">
                 <span class="cell black"></span></span>
             </span>
             <span class="cell-container">
-              <span class="cell-outer" :class="{ active: fontColor === '#2D77FA' }" @click="setActiveToolColor('#2D77FA')">
+              <span class="cell-outer" :class="{ active: areColorsSimilar(fontColor, 'rgb(45, 119, 250)') }" @click="setActiveToolColor('rgb(45, 119, 250)')">
                 <span class="cell blue"></span></span>
             </span>
+            <div class="color-picker">
+              <div class="preview" :style="{ backgroundColor: colorPickerValue }"></div>
+              <n-color-picker
+                to=".signatures-popup"
+                @complete="onColorPickerComplete"
+                @update:value="onColorPickerUpdate"
+                :value="colorPickerValue"
+                :show-alpha="false"
+              >
+                <template #label><img src="../Icon/colorful.svg" alt="colorPicker"></template>
+              </n-color-picker>
+            </div>
           </div>
         </div>
       </div>
     </div>
 
-    <div class="paint-container" ref="paintContainer">
-      <canvas v-show="activeSignWay === 'trackpad'" id="electronicTrackpadCanvas" :width="canvasWidth" :height="canvasHeight"></canvas>
-
-      <div class="keyboard-paint" v-show="activeSignWay === 'keyboard'">
-        <input type="text" :placeholder="$t('signatures.signHere')" v-model="textSgin" name="signature">
-      </div>
-
-      <div class="image-paint" v-show="activeSignWay === 'image'">
-        <a>{{ $t('signatures.selectFile') }}<input type="file" id="signImageInput" @change="handleFile" accept=".png, .jpg, .jpeg" @click="clickUpload" name="signature"></a>
-      </div>
-    </div>
-
-    <div v-if="!isMobileDevice" class="property-container">
-      <div v-show="activeSignWay === 'trackpad'" class="width-tool">
-        <span>{{ $t('signatures.lineWidth') }}</span>
-        <n-slider v-model:value="widthValue" :step="1" :max="10" :min="1" class="width-slider">
-          <template #thumb>
-            <Slider />
-          </template>
-        </n-slider>
-        <input v-model="widthValue" type="text" pattern="\d*" onkeypress="return (/[\d]/.test(String.fromCharCode(event.keyCode)))" @blur="handleBlur" name="signature">
-      </div>
-
-      <div v-show="activeSignWay === 'keyboard'" class="font-tool">
-        <span>{{ $t('font') }}</span>
-        <select id="fontFamily" v-model="fontFamily"  v-on:change="handleFontChange">
-          <option value="Arial">Arial</option>
-          <option value="Courier New">Courier New</option>
-          <option value="Times New Roman">Times New Roman</option>
-        </select>
-      </div>
-
-      <div v-show="activeSignWay === 'trackpad' || activeSignWay === 'keyboard'" class="color-tool">
-        <span>{{ $t('color') }}</span>
-        <div class="colors-container">
-          <!-- <span class="cell-container">
-            <span class="cell-outer" :class="{ active: fontColor === '#000000' }" @click="setActiveToolColor('#000000')">
-            <div class="box cell"><div class="box-outer"></div><div class="box-inner"></div></div></span>
-          </span> -->
-          <span class="cell-container">
-            <span class="cell-outer" :class="{ active: fontColor === '#FF0000' }" @click="setActiveToolColor('#FF0000')">
-              <span class="cell red"></span></span>
-          </span>
-          <span class="cell-container">
-            <span class="cell-outer" :class="{ active: fontColor === '#000000' }" @click="setActiveToolColor('#000000')">
-              <span class="cell black"></span></span>
-          </span>
-          <span class="cell-container">
-            <span class="cell-outer" :class="{ active: fontColor === '#2D77FA' }" @click="setActiveToolColor('#2D77FA')">
-              <span class="cell blue"></span></span>
-          </span>
-        </div>
-      </div>
-    </div>
-
     <div class="buttons-container">
-      <div class="button" @click="clearData">{{ $t('signatures.clear') }}</div>
+      <div class="clear" :class="{ 'button': !isMobile }" @click="clearData">{{ $t('signatures.clear') }}</div>
       <div class="right-btns">
         <div class="button" @click="closePanel('cancel')">{{ $t('cancel') }}</div>
         <div class="button blue" @click="save">{{ $t('signatures.save') }}</div>
@@ -114,8 +87,9 @@ import { useViewerStore } from '@/stores/modules/viewer'
 import { useDocumentStore } from '@/stores/modules/document'
 import core from '@/core'
 import MessageError from '@/assets/icons/icon-message-error.svg'
-import { NSlider } from 'naive-ui'
-import { isMobileDevice } from '@/helpers/device'
+import { NSlider, NColorPicker } from 'naive-ui'
+import { isMobile } from '@/helpers/device'
+import { areColorsSimilar } from '@/helpers/utils'
 
 const instance = getCurrentInstance().appContext.app.config.globalProperties
 
@@ -135,6 +109,7 @@ const fontFamily = ref('Courier New')
 const paintContainer = ref()
 const canvasWidth = ref(578)
 const canvasHeight = ref(270)
+const colorPickerValue = ref('rgb(0, 0, 0)')
 
 watch(() => toolMode.value, (newValue, oldValue) => {
   if (!(oldValue === 'sign' && newValue === 'view') && newValue !== oldValue) {
@@ -169,6 +144,7 @@ watch(() => fontColor.value, (newValue, oldValue) => {
   })
 
   if (activeSignWay.value === "keyboard") {
+    colorPickerValue.value = fontColor.value
     let inputElement = document.querySelector(".keyboard-paint input")
     if (inputElement) {
       inputElement.style.color = fontColor.value
@@ -178,7 +154,7 @@ watch(() => fontColor.value, (newValue, oldValue) => {
 
 watch(() => show.value, (newValue, oldValue) => {
   if (newValue) {
-    if (isMobileDevice) {
+    if (isMobile) {
       nextTick(() => {
         const { clientWidth, clientHeight } = paintContainer.value
         clientWidth && canvasWidth.value !== clientWidth && (canvasWidth.value = clientWidth)
@@ -418,6 +394,16 @@ const handleFontChange = (evt) => {
     inputElement.style.fontFamily = evt.target.value
   }
 }
+
+// 颜色选择器选中颜色事件
+const onColorPickerComplete = (value) => {
+  if (!areColorsSimilar(value, fontColor.value)) setActiveToolColor(value)
+}
+
+// 颜色选择器颜色改变事件
+const onColorPickerUpdate = (value) => {
+  colorPickerValue.value = value
+}
 </script>
 
 <style lang="scss">
@@ -555,13 +541,13 @@ const handleFontChange = (evt) => {
               height: 24px;
             }
             .red {
-              background-color: #FF0000;
+              background-color: rgb(255, 0, 0);
             }
             .black {
-              background-color: #000;
+              background-color: rgb(0, 0, 0);
             }
             .blue {
-              background-color: #2D77FA;
+              background-color: rgb(45, 119, 250);
             }
           }
           & + .cell-container {
@@ -647,52 +633,67 @@ const handleFontChange = (evt) => {
   }
 }
 
-.signatures-popup.mobile {
-  display: flex;
-  flex-direction: column;
-  justify-content: space-between;
-  width: 100vh;
-  height: 100vw;
-  transform: rotate(90deg);
-  -ms-transform: rotate(90deg);
-  -moz-transform: rotate(90deg);
-  -webkit-transform: rotate(90deg);
-  -o-transform: rotate(90deg);
+@media screen and (max-width: 640px) {
+  .signatures-popup {
+    width: calc(100% - 40px);
+    border-radius: 4px;
 
-  .sign-popup-header {
-    padding: 2px 16px;
-    background-color: var(--c-bg);
-  }
+    .sign-popup-header {
+      padding: 0;
+      background-color: var(--c-bg);
+    }
 
-  .property-container {
-    flex: 1;
-    flex-direction: row-reverse;
-    justify-content: flex-start;
-    margin: auto 0;
+    .mobile {
+      display: flex;
+      flex-direction: column-reverse;
+    }
 
-    .color-tool {
-      margin-right: 30px;
+    .property-container {
+      margin: 24px 25px 0;
+      flex-direction: row-reverse;
+
+      .color-tool .colors-container {
+        margin-left: 0;
+      }
     }
-  }
 
-  .paint-container {
-    flex: 1;
-    margin: 0;
-    background-color: var(--c-header-bg);
+    .paint-container {
+      margin: 24px 20px;
+      background-color: var(--c-side-bg);
+      border: 1px solid var(--c-header-border);
+      border-radius: 4px;
+
+      .keyboard-paint input {
+        font-family: Segoe UI;
+        font-size: 30px;
+
+        &::placeholder {
+          color: rgba(0, 0, 0, 0.3);
+        }
+      }
+    }
+
+    .buttons-container {
+      margin: 0 20px 16px;
+      align-items: center;
+
+      .clear {
+        font-size: 14px;
+      }
+    }
   }
 }
 
-@media screen and (max-width: 628px) {
-  .signatures-popup:not(.mobile) {
-    width: calc(100% - 40px);
+@media screen and (max-width: 450px) {
+  .signatures-popup .property-container .color-tool .colors-container {
 
-    .property-container {
-      flex-direction: column;
-      align-items: flex-start;
+    span {
+      display: none;
+    }
 
-      .color-tool {
-        margin-top: 10px;
-      }
+    .color-picker {
+      margin-left: 0;
+      height: 30px;
     }
   }
 }

+ 1 - 1
packages/webview/src/helpers/device.js

@@ -1,6 +1,6 @@
 export const isDesktop = () => window.innerWidth > 900;
 export const isTabletOrMobile = () => window.innerWidth <= 900;
-export const isMobile = () => window.innerWidth < 640;
+export const isMobile = window.innerWidth < 640;
 export const isIEEdge = navigator.userAgent.indexOf('Edge') > -1;
 export const isIEEdgeChromium = navigator.userAgent.indexOf('Edg/') > -1;
 export const isIE11 = navigator.userAgent.indexOf('Trident/7.0') > -1;