Explorar o código

Updated shadow control to be able to handle "absolute null" situation

Henry Jameson hai 2 meses
pai
achega
aa7a336183

+ 13 - 1
src/components/settings_modal/tabs/theme_tab/theme_tab.js

@@ -314,7 +314,18 @@ export default {
       },
       set (val) {
         if (val) {
-          this.shadowsLocal[this.shadowSelected] = this.currentShadowFallback.map(_ => Object.assign({}, _))
+          this.shadowsLocal[this.shadowSelected] = (this.currentShadowFallback || [])
+            .map(s => ({
+              name: null,
+              x: 0,
+              y: 0,
+              blur: 0,
+              spread: 0,
+              inset: false,
+              color: '#000000',
+              alpha: 1,
+              ...s
+            }))
         } else {
           delete this.shadowsLocal[this.shadowSelected]
         }
@@ -328,6 +339,7 @@ export default {
         return this.shadowsLocal[this.shadowSelected]
       },
       set (v) {
+        console.log('TT', v)
         this.shadowsLocal[this.shadowSelected] = v
       }
     },

+ 4 - 42
src/components/settings_modal/tabs/theme_tab/theme_tab.vue

@@ -937,24 +937,14 @@
               </Select>
             </div>
             <div class="override">
-              <label
-                for="override"
-                class="label"
-              >
-                {{ $t('settings.style.shadows.override') }}
-              </label>
-              {{ ' ' }}
-              <input
+              <Checkbox
                 id="override"
                 v-model="currentShadowOverriden"
                 name="override"
                 class="input-override"
-                type="checkbox"
               >
-              <label
-                class="checkbox-label"
-                for="override"
-              />
+                {{ $t('settings.style.shadows.override') }}
+              </Checkbox>
             </div>
             <button
               class="btn button-default"
@@ -965,38 +955,10 @@
           </div>
           <ShadowControl
             v-model="currentShadow"
-            :ready="!!currentShadowFallback"
+            :separate-inset="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'"
             :fallback="currentShadowFallback"
           />
-          <div v-if="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'">
-            <i18n-t
-              scope="global"
-              keypath="settings.style.shadows.filter_hint.always_drop_shadow"
-              tag="p"
-            >
-              <code>filter: drop-shadow()</code>
-            </i18n-t>
-            <p>{{ $t('settings.style.shadows.filter_hint.avatar_inset') }}</p>
-            <i18n-t
-              scope="global"
-              keypath="settings.style.shadows.filter_hint.drop_shadow_syntax"
-              tag="p"
-            >
-              <code>drop-shadow</code>
-              <code>spread-radius</code>
-              <code>inset</code>
-            </i18n-t>
-            <i18n-t
-              scope="global"
-              keypath="settings.style.shadows.filter_hint.inset_classic"
-              tag="p"
-            >
-              <code>box-shadow</code>
-            </i18n-t>
-            <p>{{ $t('settings.style.shadows.filter_hint.spread_zero') }}</p>
-          </div>
         </div>
-
         <div
           :label="$t('settings.style.fonts._tab_label')"
           class="fonts-container"

+ 65 - 57
src/components/shadow_control/shadow_control.js

@@ -1,8 +1,9 @@
-import ColorInput from '../color_input/color_input.vue'
-import OpacityInput from '../opacity_input/opacity_input.vue'
-import Select from '../select/select.vue'
-import Checkbox from '../checkbox/checkbox.vue'
-import { getCssShadow } from '../../services/theme_data/theme_data.service.js'
+import ColorInput from 'src/components/color_input/color_input.vue'
+import OpacityInput from 'src/components/opacity_input/opacity_input.vue'
+import Select from 'src/components/select/select.vue'
+import Checkbox from 'src/components/checkbox/checkbox.vue'
+import Popover from 'src/components/popover/popover.vue'
+import { getCssShadow, getCssShadowFilter } from '../../services/theme_data/theme_data.service.js'
 import { hex2rgb } from '../../services/color_convert/color_convert.js'
 import { library } from '@fortawesome/fontawesome-svg-core'
 import {
@@ -31,12 +32,8 @@ const toModel = (object = {}) => ({
 })
 
 export default {
-  // 'modelValue' and 'Fallback' can be undefined, but if they are
-  // initially vue won't detect it when they become something else
-  // therefore i'm using "ready" which should be passed as true when
-  // data becomes available
   props: [
-    'modelValue', 'fallback', 'ready'
+    'modelValue', 'fallback', 'separateInset'
   ],
   emits: ['update:modelValue'],
   data () {
@@ -51,75 +48,86 @@ export default {
     ColorInput,
     OpacityInput,
     Select,
-    Checkbox
-  },
-  methods: {
-    add () {
-      this.cValue.push(toModel(this.selected))
-      this.selectedId = this.cValue.length - 1
-    },
-    del () {
-      this.cValue.splice(this.selectedId, 1)
-      this.selectedId = this.cValue.length === 0 ? undefined : Math.max(this.selectedId - 1, 0)
-    },
-    moveUp () {
-      const movable = this.cValue.splice(this.selectedId, 1)[0]
-      this.cValue.splice(this.selectedId - 1, 0, movable)
-      this.selectedId -= 1
-    },
-    moveDn () {
-      const movable = this.cValue.splice(this.selectedId, 1)[0]
-      this.cValue.splice(this.selectedId + 1, 0, movable)
-      this.selectedId += 1
-    }
+    Checkbox,
+    Popover
   },
   beforeUpdate () {
-    this.cValue = this.modelValue || this.fallback
+    this.cValue = (this.modelValue || this.fallback || []).map(toModel)
   },
   computed: {
+    selected () {
+      const selected = this.cValue[this.selectedId]
+      if (selected) {
+        return { ...selected }
+      }
+      return null
+    },
+    present () {
+      return this.selected != null && !this.usingFallback
+    },
+    shadowsAreNull () {
+      return this.modelValue == null
+    },
     anyShadows () {
       return this.cValue.length > 0
     },
     anyShadowsFallback () {
       return this.fallback.length > 0
     },
-    selected () {
-      if (this.ready && this.anyShadows) {
-        return this.cValue[this.selectedId]
-      } else {
-        return toModel({})
-      }
-    },
     currentFallback () {
-      if (this.ready && this.anyShadowsFallback) {
-        return this.fallback[this.selectedId]
-      } else {
-        return toModel({})
-      }
+      return this.fallback?.[this.selectedId]
     },
     moveUpValid () {
-      return this.ready && this.selectedId > 0
+      return this.selectedId > 0
     },
     moveDnValid () {
-      return this.ready && this.selectedId < this.cValue.length - 1
-    },
-    present () {
-      return this.ready &&
-        typeof this.cValue[this.selectedId] !== 'undefined' &&
-        !this.usingFallback
+      return this.selectedId < this.cValue.length - 1
     },
     usingFallback () {
-      return typeof this.modelValue === 'undefined'
+      return this.modelValue == null
     },
     rgb () {
       return hex2rgb(this.selected.color)
     },
     style () {
-      return this.ready
-        ? {
-            boxShadow: getCssShadow(this.fallback)
-          }
-        : {}
+      if (!this.ready) return {}
+      if (this.separateInset) {
+        return {
+          filter: getCssShadowFilter(this.fallback),
+          boxShadow: getCssShadow(this.fallback, true)
+        }
+      }
+      return {
+        boxShadow: getCssShadow(this.fallback)
+      }
+    }
+  },
+  methods: {
+    updateProperty (prop, value) {
+      this.cValue[this.selectedId][prop] = value
+      this.$emit('update:modelValue', this.cValue)
+    },
+    add () {
+      this.cValue.push(toModel(this.selected))
+      this.selectedId = Math.max(this.cValue.length - 1, 0)
+      this.$emit('update:modelValue', this.cValue)
+    },
+    del () {
+      this.cValue.splice(this.selectedId, 1)
+      this.selectedId = this.cValue.length === 0 ? undefined : Math.max(this.selectedId - 1, 0)
+      this.$emit('update:modelValue', this.cValue)
+    },
+    moveUp () {
+      const movable = this.cValue.splice(this.selectedId, 1)[0]
+      this.cValue.splice(this.selectedId - 1, 0, movable)
+      this.selectedId -= 1
+      this.$emit('update:modelValue', this.cValue)
+    },
+    moveDn () {
+      const movable = this.cValue.splice(this.selectedId, 1)[0]
+      this.cValue.splice(this.selectedId + 1, 0, movable)
+      this.selectedId += 1
+      this.$emit('update:modelValue', this.cValue)
     }
   }
 }

+ 16 - 1
src/components/shadow_control/shadow_control.scss

@@ -69,6 +69,16 @@
     }
   }
 
+  .inset-alert {
+    padding: 0.25em 0.5em;
+  }
+
+  &.disabled {
+    .inset-alert {
+      opacity: 0.2;
+    }
+  }
+
   .shadow-preview {
     order: 2;
     flex: 3 3 15em;
@@ -94,7 +104,7 @@
 
     .input-light-grid {
       grid-area: options;
-      justify-self: end;
+      justify-self: center;
     }
 
     .input-number {
@@ -176,3 +186,8 @@
     }
   }
 }
+
+.inset-tooltip {
+  padding: 0.5em;
+  max-width: 30em;
+}

+ 79 - 24
src/components/shadow_control/shadow_control.vue

@@ -11,20 +11,22 @@
         {{ $t('settings.style.shadows.offset') }}
       </label>
       <input
-        v-model="selected.y"
+        :value="selected?.y"
         :disabled="!present"
         :class="{ disabled: !present }"
         class="input input-number y-shift-number"
         type="number"
+        @input="e => updateProperty('y', e.target.value)"
       >
       <input
-        v-model="selected.y"
+        :value="selected?.y"
         :disabled="!present"
         :class="{ disabled: !present }"
         class="input input-range y-shift-slider"
         type="range"
         max="20"
         min="-20"
+        @input="e => updateProperty('y', e.target.value)"
       >
       <div
         class="preview-window"
@@ -36,20 +38,22 @@
         />
       </div>
       <input
-        v-model="selected.x"
+        :value="selected?.x"
         :disabled="!present"
         :class="{ disabled: !present }"
         class="input input-number x-shift-number"
         type="number"
+        @input="e => updateProperty('x', e.target.value)"
       >
       <input
-        v-model="selected.x"
+        :value="selected?.x"
         :disabled="!present"
         :class="{ disabled: !present }"
         class="input input-range x-shift-slider"
         type="range"
         max="20"
         min="-20"
+        @input="e => updateProperty('x', e.target.value)"
       >
       <Checkbox
         id="inset"
@@ -67,7 +71,7 @@
         v-model="selectedId"
         class="shadow-list"
         size="10"
-        :disabled="!ready || usingFallback"
+        :disabled="shadowsAreNull"
       >
         <option
           v-for="(shadow, index) in cValue"
@@ -75,28 +79,26 @@
           :value="index"
           :class="{ '-active': index === Number(selectedId) }"
         >
-          {{ shadow.name ?? $t('settings.style.shadows.shadow_id', { value: index }) }}
+          {{ shadow?.name ?? $t('settings.style.shadows.shadow_id', { value: index }) }}
         </option>
       </Select>
       <div
-        :disabled="usingFallback"
         class="id-control arrange-buttons"
       >
         <button
           class="btn button-default"
-          :disabled="!ready || !present"
-          :class="{ disabled: !present }"
-          @click="del"
+          :disabled="shadowsAreNull"
+          @click="add"
         >
           <FAIcon
             fixed-width
-            icon="times"
+            icon="plus"
           />
         </button>
         <button
           class="btn button-default"
           :disabled="!moveUpValid"
-          :class="{ disabled: !present }"
+          :class="{ disabled: !moveUpValid }"
           @click="moveUp"
         >
           <FAIcon
@@ -107,6 +109,7 @@
         <button
           class="btn button-default"
           :disabled="!moveDnValid"
+          :class="{ disabled: !moveDnValid }"
           @click="moveDn"
         >
           <FAIcon
@@ -116,12 +119,13 @@
         </button>
         <button
           class="btn button-default"
-          :disabled="usingFallback || !present"
-          @click="add"
+          :disabled="!present"
+          :class="{ disabled: !present }"
+          @click="del"
         >
           <FAIcon
             fixed-width
-            icon="plus"
+            icon="times"
           />
         </button>
       </div>
@@ -141,11 +145,12 @@
         </label>
         <input
           id="name"
-          v-model="selected.name"
+          :value="selected?.name"
           :disabled="!present"
           :class="{ disabled: !present }"
           name="name"
           class="input input-string"
+          @input="e => updateProperty('name', e.target.value)"
         >
       </div>
       <div
@@ -154,10 +159,11 @@
       >
         <Checkbox
           id="inset"
-          v-model="selected.inset"
+          :value="selected?.inset"
           :disabled="!present"
           name="inset"
           class="input-inset input-boolean"
+          @input="e => updateProperty('inset', e.target.value)"
         >
           <template #before>
             {{ $t('settings.style.shadows.inset') }}
@@ -178,7 +184,7 @@
         </label>
         <input
           id="blur"
-          v-model="selected.blur"
+          :value="selected?.blur"
           :disabled="!present"
           :class="{ disabled: !present }"
           name="blur"
@@ -186,14 +192,16 @@
           type="range"
           max="20"
           min="0"
+          @input="e => updateProperty('blur', e.target.value)"
         >
         <input
-          v-model="selected.blur"
+          :value="selected?.blur"
           :disabled="!present"
           :class="{ disabled: !present }"
           class="input input-number"
           type="number"
           min="0"
+          @input="e => updateProperty('blur', e.target.value)"
         >
       </div>
       <div
@@ -210,7 +218,7 @@
         </label>
         <input
           id="spread"
-          v-model="selected.spread"
+          :value="selected?.spread"
           :disabled="!present"
           :class="{ disabled: !present }"
           name="spread"
@@ -218,26 +226,30 @@
           type="range"
           max="20"
           min="-20"
+          @input="e => updateProperty('spread', e.target.value)"
         >
         <input
-          v-model="selected.spread"
+          :value="selected?.spread"
           :disabled="!present"
           :class="{ disabled: !present }"
           class="input input-number"
           type="number"
+          @input="e => updateProperty('spread', e.target.value)"
         >
       </div>
       <ColorInput
-        v-model="selected.color"
+        :modelValue="selected?.color"
         :disabled="!present"
         :label="$t('settings.style.common.color')"
-        :fallback="currentFallback.color"
+        :fallback="currentFallback?.color"
         :show-optional-tickbox="false"
         name="shadow"
+        @update:modelValue="e => updateProperty('color', e.target.value)"
       />
       <OpacityInput
-        v-model="selected.alpha"
+        :modelValue="selected?.alpha"
         :disabled="!present"
+        @update:modelValue="e => updateProperty('alpha', e.target.value)"
       />
       <i18n-t
         scope="global"
@@ -247,6 +259,49 @@
       >
         <code>--variable,mod</code>
       </i18n-t>
+      <Popover
+        trigger="hover"
+        v-if="separateInset"
+      >
+        <template #trigger>
+          <div
+            class="inset-alert alert warning"
+          >
+            <FAIcon icon="exclamation-triangle" />
+            &nbsp;
+            {{ $t('settings.style.shadows.filter_hint.avatar_inset_short') }}
+          </div>
+        </template>
+        <template #content>
+          <div class="inset-tooltip">
+            <i18n-t
+              scope="global"
+              keypath="settings.style.shadows.filter_hint.always_drop_shadow"
+              tag="p"
+            >
+              <code>filter: drop-shadow()</code>
+            </i18n-t>
+            <p>{{ $t('settings.style.shadows.filter_hint.avatar_inset') }}</p>
+            <i18n-t
+              scope="global"
+              keypath="settings.style.shadows.filter_hint.drop_shadow_syntax"
+              tag="p"
+            >
+              <code>drop-shadow</code>
+              <code>spread-radius</code>
+              <code>inset</code>
+            </i18n-t>
+            <i18n-t
+              scope="global"
+              keypath="settings.style.shadows.filter_hint.inset_classic"
+              tag="p"
+            >
+              <code>box-shadow</code>
+            </i18n-t>
+            <p>{{ $t('settings.style.shadows.filter_hint.spread_zero') }}</p>
+          </div>
+        </template>
+      </Popover>
     </div>
   </div>
 </template>

+ 1 - 0
src/i18n/en.json

@@ -880,6 +880,7 @@
         "filter_hint": {
           "always_drop_shadow": "Warning, this shadow always uses {0} when browser supports it.",
           "drop_shadow_syntax": "{0} does not support {1} parameter and {2} keyword.",
+          "avatar_inset_short": "Separate inset shadow",
           "avatar_inset": "Please note that combining both inset and non-inset shadows on avatars might give unexpected results with transparent avatars.",
           "spread_zero": "Shadows with spread > 0 will appear as if it was set to zero",
           "inset_classic": "Inset shadows will be using {0}"

+ 1 - 1
src/services/theme_data/theme_data.service.js

@@ -452,7 +452,7 @@ export const getCssShadow = (input, usesDropShadow) => {
     ]).join(' ')).join(', ')
 }
 
-const getCssShadowFilter = (input) => {
+export const getCssShadowFilter = (input) => {
   if (input.length === 0) {
     return 'none'
   }