Sfoglia il codice sorgente

1.语音矩阵问题修复 2.选择题增加显示效果刷新

dsy 1 mese fa
parent
commit
6552ed3a46

+ 1 - 1
.env

@@ -11,4 +11,4 @@ VUE_APP_BookWebSI = '/GCLSBookWebSI/ServiceInterface'
 VUE_APP_EepServer = '/EEPServer/SI'
 
 #version
-VUE_APP_VERSION = '2026.07.17'
+VUE_APP_VERSION = '2026.07.22'

+ 11 - 0
main.js

@@ -28,6 +28,9 @@ const createWindow = () => {
     },
   });
 
+  // 每次启动时重置缩放为 100%
+  win.webContents.setZoomLevel(0);
+
   win.loadURL(
     url.format({
       pathname: path.join(__dirname, './dist', 'index.html'),
@@ -37,7 +40,15 @@ const createWindow = () => {
     }),
   );
 
+  // 页面加载完成后再次确保缩放为 100%(防止持久化缩放覆盖)
+  win.webContents.on('did-finish-load', () => {
+    // 立即重置一次
+    win.webContents.setZoomLevel(0);
+  });
+
+  // 当窗口准备好显示时,最大化并显示窗口
   win.once('ready-to-show', () => {
+    win.webContents.setZoomLevel(0);
     win.maximize();
     win.show();
   });

+ 1 - 1
package-lock.json

@@ -16,7 +16,7 @@
         "core-js": "^3.47.0",
         "dompurify": "^3.1.5",
         "element-ui": "^2.15.14",
-        "hanzi-writer": "^3.7.0",
+        "hanzi-writer": "^3.1.0",
         "js-audio-recorder": "^1.0.7",
         "mathjax": "^3.2.2",
         "md5": "^2.3.0",

+ 33 - 3
packages/BookEep.vue

@@ -1,9 +1,13 @@
 <template>
-  <div class="common-preview">
+  <div class="common-preview" :class="{ 'is-mobile': isMobile }">
     <div class="audit-content">
       <div ref="previewMain" class="main-container">
         <main :class="['preview-main', 'no-audit']" :style="computedCommonPreviewStyle">
-          <div class="preview-left" :style="{ backgroundColor: background.background?.is_global ? '' : '#fff' }"></div>
+          <div
+            v-if="!isMobile"
+            class="preview-left"
+            :style="{ backgroundColor: background.background?.is_global ? '' : '#fff' }"
+          ></div>
           <CoursewarePreview
             ref="courseware"
             :is-show-group="false"
@@ -17,11 +21,16 @@
             :show-remark="false"
             :component-remark-obj="{}"
             :project="project"
+            :is-mobile="isMobile"
             @editNote="handEditNote"
             @saveCollect="saveCollect"
             @getTranslate="getTranslate"
           />
-          <div class="preview-right" :style="{ backgroundColor: background.background?.is_global ? '' : '#fff' }"></div>
+          <div
+            v-if="!isMobile"
+            class="preview-right"
+            :style="{ backgroundColor: background.background?.is_global ? '' : '#fff' }"
+          ></div>
         </main>
       </div>
     </div>
@@ -120,6 +129,7 @@ export default {
     },
   },
   data() {
+    const isMobile = /android|iphone|ipad|ipod/i.test(navigator.userAgent || navigator.vendor || window.opera);
     return {
       background: this.bookBackground.length > 0 ? JSON.parse(this.bookBackground) : {},
       groupRowList: this.contentGroupRowList.length > 0 ? JSON.parse(this.contentGroupRowList) : [],
@@ -158,6 +168,7 @@ export default {
       selectedInfo: null,
       allFeedbackList: [],
       drawerType: 1,
+      isMobile,
     };
   },
   computed: {
@@ -646,6 +657,25 @@ $total-width: $courseware-width + $courseware-left-margin + $courseware-right-ma
 .common-preview {
   min-width: calc($total-width);
 
+  // 移动端适配
+  &.is-mobile {
+    min-width: 100%;
+
+    .main-container {
+      min-width: 100%;
+    }
+
+    .audit-content {
+      min-width: 100%;
+    }
+
+    main.preview-main {
+      width: 100%;
+      min-width: 100%;
+      max-width: 100%;
+    }
+  }
+
   .main-container {
     position: relative;
     flex: 1;

+ 2 - 0
packages/index.js

@@ -7,6 +7,8 @@ import 'element-ui/lib/theme-chalk/index.css';
 
 import '@/icons';
 import '@/utils/directive';
+import '@/styles/index.scss';
+import '@/utils/filter';
 
 import '@/utils/mathjax'; // 必须在引入mathjax前引入mathjax的配置文件
 import 'mathjax/es5/tex-mml-svg';

+ 1 - 1
packages/package.json

@@ -1,6 +1,6 @@
 {
   "name": "eep-ui",
-  "version": "0.0.23",
+  "version": "0.0.26",
   "main": "eep/eep-ui.umd.js",
   "style": "eep/eep-ui.css",
   "exports": {

+ 14 - 5
src/common/SvgIcon/index.vue

@@ -1,6 +1,11 @@
 <template>
-  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners"></div>
-  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
+  <div
+    v-if="isExternal"
+    :style="[svgStyle, styleExternalIcon]"
+    class="svg-external-icon svg-icon"
+    v-on="$listeners"
+  ></div>
+  <svg v-else :style="svgStyle" :class="svgClass" aria-hidden="true" v-on="$listeners">
     <use :xlink:href="iconName" />
   </svg>
 </template>
@@ -53,6 +58,12 @@ export default {
       }
       return classes.join(' ');
     },
+    svgStyle() {
+      return {
+        width: this._width,
+        height: this._height,
+      };
+    },
     styleExternalIcon() {
       return {
         mask: `url(${this.iconClass}) no-repeat 50% 50%`,
@@ -67,7 +78,7 @@ export default {
      * @param {String|Number} size
      */
     _getSize(value, size) {
-      if (size) {
+      if (size !== null && size !== '') {
         if (isNumber(size)) return `${size}px`;
         return size;
       }
@@ -82,8 +93,6 @@ export default {
 
 <style scoped>
 .svg-icon {
-  width: v-bind(_width);
-  height: v-bind(_height);
   overflow: hidden;
   vertical-align: -0.15em;
   fill: currentColor;

+ 8 - 1
src/components/PinyinText.vue

@@ -457,7 +457,7 @@ export default {
   methods: {
     // 统一处理点击事件
     handleWordClick(item, pIndex, sIndex, wIndex) {
-      if (item) {
+      if (item && this.isShowPinyin) {
         this.visible = true;
         this.selectContent = item;
         this.paragraph_index = pIndex;
@@ -692,11 +692,18 @@ export default {
         sentenceStyle.paddingLeft = styleObj.paddingLeft;
         delete styleObj.paddingLeft;
       }
+      // 提取 lineHeight 用于行高,从 styleObj 中移除
+      if (styleObj && styleObj.lineHeight) {
+        sentenceStyle.lineHeight = styleObj.lineHeight;
+        delete styleObj.lineHeight;
+      }
+
       let parentStyle = {};
       if (styleObj && styleObj.textAlign === 'center') {
         parentStyle['text-align'] = 'center';
         parentStyle['display'] = 'block';
       }
+
       return {
         type: 'text',
         word_list: item.word_list,

+ 17 - 4
src/views/book/courseware/create/components/CreateCanvas.vue

@@ -878,7 +878,11 @@ export default {
       const prevWidth = Number(prevGrid.replace('fr', ''));
       const width = Number(row.width_list[j].replace('fr', ''));
       const max = prevWidth + width - 10;
-      if (prevWidth + offsetX < 10 || prevWidth + offsetX > max || width - offsetX > max || width - offsetX < 10) {
+      // 当 min_width 不为 1 且拖动后宽度小于 10 或大于最大宽度时,直接返回
+      if (
+        min_width !== 1 &&
+        (prevWidth + offsetX < 10 || prevWidth + offsetX > max || width - offsetX > max || width - offsetX < 10)
+      ) {
         return;
       }
       // 计算拖动的距离与总宽度的比例
@@ -907,7 +911,10 @@ export default {
       const prevWidth = Number(prevGrid.width.replace('fr', ''));
       const width = Number(grid.width.replace('fr', ''));
       const max = prevWidth + width - 10;
-      if (prevWidth + offsetX < 10 || prevWidth + offsetX > max || width - offsetX > max || width - offsetX < 10) {
+      if (
+        min_width !== 1 &&
+        (prevWidth + offsetX < 10 || prevWidth + offsetX > max || width - offsetX > max || width - offsetX < 10)
+      ) {
         return;
       }
       // 计算拖动的距离与总宽度的比例
@@ -934,7 +941,10 @@ export default {
       const nextWidth = Number(nextGrid.replace('fr', ''));
       const width = Number(row.width_list[j].replace('fr', ''));
       const max = nextWidth + width - 10;
-      if (nextWidth - offsetX < 10 || nextWidth - offsetX > max || width + offsetX > max || width + offsetX < 10) {
+      if (
+        min_width !== 1 &&
+        (nextWidth - offsetX < 10 || nextWidth - offsetX > max || width + offsetX > max || width + offsetX < 10)
+      ) {
         return;
       }
       const ratio = (offsetX / document.querySelector('.row').offsetWidth) * 100;
@@ -961,7 +971,10 @@ export default {
       const nextWidth = Number(nextGrid.width.replace('fr', ''));
       const width = Number(grid.width.replace('fr', ''));
       const max = nextWidth + width - 10;
-      if (nextWidth - offsetX < 10 || nextWidth - offsetX > max || width + offsetX > max || width + offsetX < 10) {
+      if (
+        min_width !== 1 &&
+        (nextWidth - offsetX < 10 || nextWidth - offsetX > max || width + offsetX > max || width + offsetX < 10)
+      ) {
         return;
       }
       const ratio = (offsetX / document.querySelector('.row').offsetWidth) * 100;

+ 3 - 3
src/views/book/courseware/create/components/base/common/CorrectPinyin.vue

@@ -34,9 +34,9 @@
         <SvgIcon icon-class="strikethrough" title="删除线" size="20" @click="setActiveTextStyle('line-through')" />
       </span>
     </div>
-    <span v-show="isEnable(dataContent.showPinyin)" class="tone-pinyin">{{
-      dataContent.pinyin.replace(/ /g, '')
-    }}</span>
+    <span v-show="isEnable(dataContent.showPinyin)" class="tone-pinyin">
+      {{ dataContent.pinyin?.replace(/ /g, '') }}
+    </span>
     <span class="content-text" :style="dataContent.activeTextStyle">{{ dataContent.text }}</span>
 
     <div class="pinyin-row">

+ 1 - 0
src/views/book/courseware/create/components/base/rich_text/RichText.vue

@@ -360,6 +360,7 @@ export default {
             // ✅ Vue2 响应式安全赋值
             this.$set(this.data, 'rich_text_list', richTextList);
           }
+
           if (parsed_text) {
             const mergedData = parsed_text.paragraph_list.map((outerArr, i) =>
               outerArr.map((innerArr, j) =>

+ 33 - 8
src/views/book/courseware/create/components/question/fill/Fill.vue

@@ -36,7 +36,7 @@
             icon="el-icon-refresh"
             title="刷新"
             class="refresh-pinyin-btn"
-            @click.native="parsedContentPinyin"
+            @click.native="parsedContentPinyin(true)"
           />
         </el-divider>
         <div class="pinyin-wrapper">
@@ -74,7 +74,7 @@
         </template>
 
         <div>
-          <el-button @click="parsedContentPinyin">识别</el-button>
+          <el-button @click="parsedContentPinyin()">识别</el-button>
           <el-button @click="openMultilingual">多语言</el-button>
         </div>
 
@@ -119,7 +119,7 @@ import PinyinText from '@/components/PinyinText.vue';
 import AddWord from './components/AddWord.vue';
 
 import { getFillData, arrangeTypeList, fillTypeList } from '@/views/book/courseware/data/fill';
-import { addTone, handleToneValue } from '@/views/book/courseware/data/common';
+import { addTone, handleToneValue, mergePunctuationToWords } from '@/views/book/courseware/data/common';
 import { getRandomNumber } from '@/utils';
 import { TextToAudioFile } from '@/api/app';
 import { sanitizeHTML } from '@/utils/common';
@@ -168,7 +168,22 @@ export default {
     },
   },
   methods: {
-    async parsedContentPinyin() {
+    /**
+     * 解析文本内容,生成分词和拼音
+     * @param {boolean} isPrompt 是否为提示操作,默认为 false
+     */
+    async parsedContentPinyin(isPrompt = false) {
+      if (isPrompt) {
+        try {
+          await this.$confirm('刷新将会重置填空和拼音,是否刷新?', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+          });
+        } catch (e) {
+          return;
+        }
+      }
       this.loading = true;
       PinyinBuild_OldFormat({
         text: this.data.content,
@@ -178,10 +193,20 @@ export default {
         is_rich_text: 'true',
       })
         .then(({ rich_text }) => {
-          if (rich_text) {
-            this.rich_text_list = rich_text.text_list;
-            this.data.model_essay = this.parseRichText();
-          }
+          if (!rich_text) return;
+          if (!Array.isArray(rich_text.text_list)) return;
+
+          this.rich_text_list = rich_text.text_list.map((item) => {
+            // 非 word_list 项,原样返回
+            if (item.is_style === 'true' || !Array.isArray(item.word_list)) {
+              return item;
+            }
+            return {
+              ...item,
+              word_list: mergePunctuationToWords(item.word_list),
+            };
+          });
+          this.data.model_essay = this.parseRichText();
         })
         .finally(() => {
           this.loading = false;

+ 0 - 1
src/views/book/courseware/create/components/question/image_text/CheckStyle.vue

@@ -224,7 +224,6 @@ export default {
       this.dialogFlag = false;
     },
     saveStyle() {
-      console.log(this.itemActive);
       this.$emit(
         'saveStyle',
         this.itemActive.fontFamily,

+ 95 - 63
src/views/book/courseware/create/components/question/select/Select.vue

@@ -1,56 +1,67 @@
 <template>
   <ModuleBase ref="base" :type="data.type">
     <template #content>
-      <ul class="option-list">
-        <li v-for="(item, i) in data.option_list" :key="item.mark" class="option-item">
-          <span
-            v-if="!('enable_serial' in data.property) || isEnable(data.property.enable_serial)"
-            class="serial-number"
-            >{{ computedOptionNumber(i) }}.</span
-          >
-          <div class="option-contnet">
+      <div v-loading="loading" class="select-wrapper">
+        <ul class="option-list">
+          <li v-for="(item, i) in data.option_list" :key="item.mark" class="option-item">
             <span
-              :class="[isSingle ? 'radio' : 'checkbox', { active: isAnswer(item.mark) }]"
-              @click="selectAnswer(item.mark)"
+              v-if="!('enable_serial' in data.property) || isEnable(data.property.enable_serial)"
+              class="serial-number"
+              >{{ computedOptionNumber(i) }}.</span
             >
-              <SvgIcon icon-class="check-mark" width="10" height="7" />
+            <div class="option-contnet">
+              <span
+                :class="[isSingle ? 'radio' : 'checkbox', { active: isAnswer(item.mark) }]"
+                @click="selectAnswer(item.mark)"
+              >
+                <SvgIcon icon-class="check-mark" width="10" height="7" />
+              </span>
+              <RichText
+                v-if="property.isGetContent"
+                ref="richText"
+                v-model="item.content"
+                :font-size="data?.unified_attrib?.font_size"
+                :font-family="data?.unified_attrib?.font"
+                :font-color="data?.unified_attrib?.text_color"
+                placeholder="输入内容"
+                :inline="true"
+                :height="32"
+              />
+            </div>
+            <span class="multilingual" @click="openMultilingual(i)">
+              <SvgIcon icon-class="multilingual" class-name="multilingual" width="12" height="12" />
             </span>
-            <RichText
-              v-if="property.isGetContent"
-              ref="richText"
-              v-model="item.content"
-              :font-size="data?.unified_attrib?.font_size"
-              :font-family="data?.unified_attrib?.font"
-              :font-color="data?.unified_attrib?.text_color"
-              placeholder="输入内容"
-              :inline="true"
-              :height="32"
-            />
-          </div>
-          <span class="multilingual" @click="openMultilingual(i)">
-            <SvgIcon icon-class="multilingual" class-name="multilingual" width="12" height="12" />
-          </span>
-          <span class="delete" @click="deleteOption(i)">
-            <SvgIcon icon-class="delete-2" width="12" height="12" />
-          </span>
-        </li>
-      </ul>
-      <div class="add">
-        <SvgIcon icon-class="add-circle" width="14" height="14" />
-        <span class="add-button" @click="addOption">增加选项</span>
-      </div>
+            <span class="delete" @click="deleteOption(i)">
+              <SvgIcon icon-class="delete-2" width="12" height="12" />
+            </span>
+          </li>
+        </ul>
+        <div class="add">
+          <SvgIcon icon-class="add-circle" width="14" height="14" />
+          <span class="add-button" @click="addOption">增加选项</span>
+        </div>
 
-      <el-divider v-if="isEnable(data.property.view_pinyin)" content-position="left">拼音效果</el-divider>
-      <PinyinText
-        v-for="(item, i) in data.option_list"
-        v-show="isEnable(data.property.view_pinyin)"
-        :key="i"
-        ref="PinyinText"
-        :paragraph-list="item.paragraph_list"
-        :rich-text-list="item.rich_text_list"
-        :pinyin-position="data.property.pinyin_position"
-        @fillCorrectPinyin="fillCorrectPinyin($event, i)"
-      />
+        <el-divider v-if="isEnable(data.property.view_pinyin)" content-position="left">
+          <span>显示效果</span>
+          <el-button
+            type="text"
+            icon="el-icon-refresh"
+            title="刷新"
+            class="refresh-pinyin-btn"
+            @click.native="handleViewPinyin(true)"
+          />
+        </el-divider>
+        <PinyinText
+          v-for="(item, i) in data.option_list"
+          v-show="isEnable(data.property.view_pinyin)"
+          :key="i"
+          ref="PinyinText"
+          :paragraph-list="item.paragraph_list"
+          :rich-text-list="item.rich_text_list"
+          :pinyin-position="data.property.pinyin_position"
+          @fillCorrectPinyin="fillCorrectPinyin($event, i)"
+        />
+      </div>
 
       <MultilingualFill
         v-if="curSelectIndex !== -1"
@@ -89,6 +100,7 @@ export default {
     return {
       data: getSelectData(),
       curSelectIndex: -1,
+      loading: false,
     };
   },
   computed: {
@@ -100,24 +112,11 @@ export default {
     'data.property.arrange_type': 'handlerMindMap',
     'data.answer.answer_list': 'handlerMindMap',
     'data.property': {
-      handler({ view_pinyin }) {
-        if (!this.isEnable(view_pinyin)) {
-          this.data.option_list.forEach((item) => {
-            item.paragraph_list = [];
-            item.paragraph_list_parameter = {
-              text: '',
-              pinyin_proofread_word_list: [],
-            };
-          });
-          return;
+      handler(val) {
+        if (this.property.isSilentPropertyWatch) return;
+        if (val.view_pinyin === 'true') {
+          this.handleViewPinyin();
         }
-        if (this.data.option_list.length > 0 && this.data.option_list[0].paragraph_list.length > 0) return;
-        this.data.option_list.forEach((item, i) => {
-          const text = item.content;
-          if (!text) return;
-          item.paragraph_list_parameter.text = text;
-          this.createParsedTextInfoPinyin(text, i);
-        });
       },
       deep: true,
     },
@@ -130,6 +129,39 @@ export default {
     },
   },
   methods: {
+    async handleViewPinyin(isPrompt = false) {
+      if (isPrompt) {
+        try {
+          await this.$confirm('刷新将会重置分词和拼音,是否刷新?', '提示', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning',
+          });
+        } catch (e) {
+          return;
+        }
+      }
+      this.loading = true;
+      if (!this.isEnable(this.data.property.view_pinyin)) {
+        this.data.option_list.forEach((item) => {
+          item.paragraph_list = [];
+          item.paragraph_list_parameter = {
+            text: '',
+            pinyin_proofread_word_list: [],
+          };
+        });
+        this.loading = false;
+        return;
+      }
+      if (this.data.option_list.length > 0 && this.data.option_list[0].paragraph_list.length > 0) return;
+      this.data.option_list.forEach((item, i) => {
+        const text = item.content;
+        if (!text) return;
+        item.paragraph_list_parameter.text = text;
+        this.createParsedTextInfoPinyin(text, i);
+      });
+      this.loading = false;
+    },
     computedOptionNumber(number) {
       let type = serialNumberTypeList.find((item) => item.value === this.data.property.option_serial_type)?.value;
       if (!type) return number + 1;

+ 1 - 1
src/views/book/courseware/data/common.js

@@ -347,6 +347,7 @@ function cloneWord(word, type) {
   // 如果type==1,则在pinyin_list开头加一个全角空格,如果type==2,则在pinyin_list末尾加一个全角空格
   if (type === 1) {
     result.pinyin_list.unshift(' ');
+    // eslint-disable-next-line no-irregular-whitespace
     result.pinyin = ` ${result.pinyin}`;
   } else if (type === 2) {
     result.pinyin_list.push(' ');
@@ -433,6 +434,5 @@ export function mergePunctuationToWords(wordList) {
     result.push(cloned);
     lastWord = cloned;
   }
-  console.log('result', result);
   return result;
 }

+ 1 - 0
src/views/book/courseware/data/divider.js

@@ -8,6 +8,7 @@ export function getDividerData() {
       color: '#FF0000',
       width: 920,
     },
+    min_width: 1,
   };
 }
 

+ 5 - 0
src/views/book/courseware/preview/CoursewarePreview.vue

@@ -37,6 +37,7 @@
                   gridArea: grid.grid_area,
                   height: grid.height,
                 }"
+                :is-mobile="isMobile"
                 @click.native="selectedComponent(grid.id)"
                 @contextmenu.native.prevent="handleContextMenu($event, grid.id)"
                 @handleHeightChange="handleHeightChange"
@@ -237,6 +238,10 @@ export default {
       type: String,
       default: '',
     },
+    isMobile: {
+      type: Boolean,
+      default: false,
+    },
   },
   data() {
     return {

+ 16 - 3
src/views/book/courseware/preview/components/fill/FillPreview.vue

@@ -99,8 +99,8 @@
       <SoundRecord
         v-if="isEnable(data.property.is_enable_voice_answer)"
         ref="record"
-        type="normal"
-        class="record-box"
+        type="pro"
+        :class="['record-box', 'sound-record-wrapper', isHorizontal ? 'horizontal' : 'vertical']"
         :attrib="data.unified_attrib"
         :answer-record-list="data.record_list"
         :task-model="isJudgingRightWrong ? 'ANSWER' : ''"
@@ -198,6 +198,9 @@ export default {
     isHasFill() {
       return this.data.model_essay.some((li) => li.type === 'input');
     },
+    isHorizontal() {
+      return this.data.property.arrange_type === arrangeTypeList[0].value;
+    },
   },
   watch: {
     'data.model_essay': {
@@ -341,7 +344,7 @@ export default {
 
         if (isEnableVoice) {
           areaRows.push('"record"');
-          templateRows.push('32px');
+          templateRows.push('56px');
         }
 
         if (this.showLang) {
@@ -612,12 +615,22 @@ export default {
 
   .record-box {
     padding: 6px 12px;
+    vertical-align: bottom;
     background-color: $fill-color;
 
     :deep .record-time {
       width: 100px;
     }
   }
+
+  .sound-record-wrapper {
+    width: 200px;
+    max-width: 200px;
+
+    &.vertical {
+      margin: 24px 0 0 16px;
+    }
+  }
 }
 </style>
 

+ 1 - 1
src/views/book/courseware/preview/components/voice_matrix/VoiceMatrixPreview.vue

@@ -38,7 +38,7 @@
       <!-- 语音矩阵 -->
       <div
         class="voice-matrix-container"
-        :style="{ height: isEnable(data.property.is_enable_record) ? 'calc(100% - 80px)' : 'auto' }"
+        :style="{ height: isEnable(data.property.is_enable_record) ? 'calc(100% - 135px)' : 'auto' }"
       >
         <div
           v-if="data.option_list.length > 0"

+ 0 - 1
stylelint.config.js

@@ -78,7 +78,6 @@ module.exports = {
       ],
       rules: {
         'keyframes-name-pattern': null,
-        'declaration-property-value-no-unknown': [true, { ignoreProperties: { '/.+/': '/(v-bind(.*))|($.*)/' } }],
         'selector-pseudo-element-no-unknown': true,
       },
     },