Browse Source

Fixes: Mobile - "Show password" icons is visible

Vladimir Sheremet 1 year ago
parent
commit
1e7f9f19cc

+ 3 - 4
.cypress/support/index.js

@@ -1,7 +1,9 @@
 // Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
 
+import './prepare.js'
+
 import '#mobile/styles/main.scss'
-import 'virtual:svg-icons-register' // eslint-disable-line import/no-unresolved
+import '#shared/components/CommonIcon/injectIcons.ts'
 
 import './commands.js'
 
@@ -10,9 +12,6 @@ globalThis.process.env = {
   DEBUG_PRINT_LIMIT: 5000,
 }
 
-// eslint-disable-next-line no-underscore-dangle
-window.__ = (str) => str
-
 Cypress.Screenshot.defaults({ capture: 'viewport' })
 
 if (Cypress.env('CY_CI')) {

+ 4 - 0
.cypress/support/prepare.js

@@ -0,0 +1,4 @@
+// Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
+
+// eslint-disable-next-line no-underscore-dangle
+window.__ = (str) => str

+ 1 - 0
app/frontend/apps/mobile/form/theme/global/addAbsoluteFloatingLabel.ts

@@ -53,5 +53,6 @@ export const addAbsoluteFloatingLabel = (classes: Classes = {}) => {
       `),
     arrow: `${arrow} formkit-arrow flex items-center`,
     messages: 'px-2',
+    suffixIcon: 'text-white fill-current flex justify-center items-center',
   }
 }

+ 1 - 0
app/frontend/apps/mobile/form/theme/global/addBlockFloatingLabel.ts

@@ -55,5 +55,6 @@ export const addBlockFloatingLabel = (classes: Classes = {}): Classes => {
     `),
     arrow: `${arrow} formkit-arrow flex items-center formkit-disabled:opacity-30`,
     messages: 'px-2',
+    suffixIcon: 'text-white fill-current flex justify-center items-center',
   }
 }

+ 1 - 1
app/frontend/apps/mobile/initialize.ts

@@ -2,7 +2,7 @@
 
 import type { App } from 'vue'
 
-import 'virtual:svg-icons-register' // eslint-disable-line import/no-unresolved
+import '#shared/components/CommonIcon/injectIcons.ts'
 import '#mobile/styles/main.scss'
 
 import initializeStore from '#shared/stores/index.ts'

+ 46 - 0
app/frontend/build/iconsPlugin.mjs

@@ -0,0 +1,46 @@
+// Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
+
+import { dirname, basename } from 'node:path'
+import { optimize } from 'svgo'
+import SVGCompiler from 'svg-baker'
+import { readFileSync } from 'node:fs'
+
+/**
+ * @param {string} filepath
+ * @returns {string}
+ */
+const optimizeSvg = (filepath) => {
+  // eslint-disable-next-line security/detect-non-literal-fs-filename
+  const content = readFileSync(filepath, 'utf-8')
+  const result = optimize(content, {
+    plugins: [{ name: 'preset-default' }],
+  })
+  return result.data || content
+}
+
+export default () => ({
+  name: 'zammad-plugin-svgo',
+  enforce: 'pre',
+  /**
+   * @param {string} code
+   * @param {string} id
+   * @returns {{code: string}}
+   */
+  async transform(code, id) {
+    if (id.endsWith('.svg?symbol')) {
+      const filepath = id.replace(/\?.*$/, '')
+      const svgContent = optimizeSvg(filepath)
+      const compiler = new SVGCompiler()
+      const dir = basename(dirname(filepath))
+      const name = basename(filepath).split('.')[0]
+      const symbol = await compiler.addSymbol({
+        id: `icon-${dir}-${name}`,
+        content: svgContent,
+        path: filepath,
+      })
+      return {
+        code: `export default \`${symbol.render()}\``,
+      }
+    }
+  },
+})

+ 0 - 5
app/frontend/build/manualChunks.js

@@ -14,11 +14,6 @@ const matchers = [
     matcher: (id) => id.includes('commonjsHelpers.js'),
     chunk: 'commonjsHelpers',
   },
-  {
-    vendor: false,
-    matcher: (id) => id === 'virtual:svg-icons-register',
-    chunk: 'icons',
-  },
   {
     vendor: false,
     matcher: (id) => id.includes('vite/preload-helper'),

+ 5 - 5
app/frontend/shared/components/CommonIcon/CommonIcon.story.vue

@@ -1,15 +1,15 @@
 <!-- Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/ -->
 
 <script setup lang="ts">
-import 'virtual:svg-icons-register' // eslint-disable-line import/no-unresolved
-import icons from 'virtual:svg-icons-names' // eslint-disable-line import/no-unresolved
+import '#shared/components/CommonIcon/injectIcons.ts'
 import { type Ref, ref, computed } from 'vue'
 import CommonIcon from './CommonIcon.vue'
 import type { Animations, Sizes } from './types.ts'
+import { useIcons } from './useIcons.ts'
 
-const iconNames = computed(() =>
-  icons.map((icon) => icon.slice('icon-'.length)),
-)
+const { symbols } = useIcons()
+
+const iconNames = computed(() => symbols.map(([icon]) => icon))
 
 const size: Ref<Sizes | undefined> = ref()
 const sizes = ['xs', 'tiny', 'small', 'base', 'medium', 'large']

+ 28 - 0
app/frontend/shared/components/CommonIcon/injectIcons.ts

@@ -0,0 +1,28 @@
+// Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
+
+import { useIcons } from './useIcons.ts'
+
+const loadSvg = () => {
+  const { body } = document
+  let svgDom = document.getElementById('__svg__icons__dom__') as unknown as
+    | SVGSVGElement
+    | undefined
+  if (!svgDom) {
+    svgDom = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
+    svgDom.style.position = 'absolute'
+    svgDom.style.width = '0'
+    svgDom.style.height = '0'
+    svgDom.id = '__svg__icons__dom__'
+    svgDom.setAttribute('xmlns', 'http://www.w3.org/2000/svg')
+    svgDom.setAttribute('xmlns:link', 'http://www.w3.org/1999/xlink')
+  }
+  const { symbols } = useIcons()
+  const html = symbols.map((symb) => symb[1]).join('\n')
+  svgDom.innerHTML = html
+  body.insertBefore(svgDom, body.lastChild)
+}
+if (document.readyState === 'loading') {
+  document.addEventListener('DOMContentLoaded', loadSvg)
+} else {
+  loadSvg()
+}

+ 35 - 0
app/frontend/shared/components/CommonIcon/useIcons.ts

@@ -0,0 +1,35 @@
+// Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
+
+import { useRawHTMLIcon } from './useRawHTMLIcon.ts'
+
+const renameIcons = (icons: [string, { default: string }][]) => {
+  const iconsMap: [string, string][] = []
+  for (const [icon, svg] of icons) {
+    const name = icon.match(/([\w-]+\/[\w-]+)\.svg/)
+    if (!name) throw new Error(`Icon name not found for ${icon}`)
+    const iconName = name[1].replace(/\//, '-')
+    iconsMap.push([iconName, svg.default])
+  }
+  return iconsMap
+}
+
+const iconsSymbolsList = Object.entries(
+  import.meta.glob<{ default: string }>('./assets/**/*.svg', {
+    eager: true,
+    as: 'symbol',
+  }),
+)
+
+const iconsSymbols = renameIcons(iconsSymbolsList)
+const iconsContent: Record<string, string> = {}
+for (const [name] of iconsSymbols) {
+  const htmlIcon = useRawHTMLIcon({ name, size: 'base' })
+  iconsContent[name] = htmlIcon
+}
+
+export const useIcons = () => {
+  return {
+    icons: iconsContent,
+    symbols: iconsSymbols,
+  }
+}

Some files were not shown because too many files changed in this diff