fix: replace vue3-flag-icons with custom CSS-only flag icons

- Remove vue3-flag-icons dependency (was causing slow loading)
- Create custom flag-icons.css with only cn and us flags (inline SVG)
- Update language-change.vue to use CSS-based flag icons
- Delete vue3-flag-icons type declaration file
- Flag icons now load instantly without any JavaScript overhead
This commit is contained in:
2026-05-07 23:21:53 +08:00
parent c816f4d85c
commit 74d030f846
5 changed files with 28 additions and 30 deletions
-1
View File
@@ -65,7 +65,6 @@
"vue-input-otp": "^0.3.2", "vue-input-otp": "^0.3.2",
"vue-router": "^5.0.3", "vue-router": "^5.0.3",
"vue-sonner": "^2.0.9", "vue-sonner": "^2.0.9",
"vue3-flag-icons": "^0.1.4",
"zod": "^4.3.6" "zod": "^4.3.6"
}, },
"devDependencies": { "devDependencies": {
-18
View File
@@ -110,9 +110,6 @@ importers:
vue-sonner: vue-sonner:
specifier: ^2.0.9 specifier: ^2.0.9
version: 2.0.9 version: 2.0.9
vue3-flag-icons:
specifier: ^0.1.4
version: 0.1.4(vue@3.5.32(typescript@5.9.3))
zod: zod:
specifier: ^4.3.6 specifier: ^4.3.6
version: 4.3.6 version: 4.3.6
@@ -2170,9 +2167,6 @@ packages:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'} engines: {node: '>=10'}
flag-icons@7.5.0:
resolution: {integrity: sha512-kd+MNXviFIg5hijH766tt+3x76ele1AXlo4zDdCxIvqWZhKt4T83bOtxUOOMlTx/EcFdUMH5yvQgYlFh1EqqFg==}
flat-cache@4.0.1: flat-cache@4.0.1:
resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==}
engines: {node: '>=16'} engines: {node: '>=16'}
@@ -3404,11 +3398,6 @@ packages:
peerDependencies: peerDependencies:
typescript: '>=5.0.0' typescript: '>=5.0.0'
vue3-flag-icons@0.1.4:
resolution: {integrity: sha512-bJrrZuVHcs5XCW1CiXG3gpZnkzczk3gXlLgVmKt4XTeKRb3U/qt57hNtTP2ybXEXaigE26WxhO9rVXF9gsL7Dg==}
peerDependencies:
vue: ^3.5.0
vue@3.5.32: vue@3.5.32:
resolution: {integrity: sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==} resolution: {integrity: sha512-vM4z4Q9tTafVfMAK7IVzmxg34rSzTFMyIe0UUEijUCkn9+23lj0WRfA83dg7eQZIUlgOSGrkViIaCfqSAUXsMw==}
peerDependencies: peerDependencies:
@@ -5442,8 +5431,6 @@ snapshots:
locate-path: 6.0.0 locate-path: 6.0.0
path-exists: 4.0.0 path-exists: 4.0.0
flag-icons@7.5.0: {}
flat-cache@4.0.1: flat-cache@4.0.1:
dependencies: dependencies:
flatted: 3.4.2 flatted: 3.4.2
@@ -6793,11 +6780,6 @@ snapshots:
'@vue/language-core': 3.2.6 '@vue/language-core': 3.2.6
typescript: 5.9.3 typescript: 5.9.3
vue3-flag-icons@0.1.4(vue@3.5.32(typescript@5.9.3)):
dependencies:
flag-icons: 7.5.0
vue: 3.5.32(typescript@5.9.3)
vue@3.5.32(typescript@5.9.3): vue@3.5.32(typescript@5.9.3):
dependencies: dependencies:
'@vue/compiler-dom': 3.5.32 '@vue/compiler-dom': 3.5.32
+20 -5
View File
@@ -1,5 +1,20 @@
.fib[data-v-c8aad0d0],.fi[data-v-c8aad0d0]{background-size:contain;background-position:50%;background-repeat:no-repeat}.fi[data-v-c8aad0d0]{position:relative;display:inline-block;width:1.333333em;line-height:1em}.fi[data-v-c8aad0d0]:before{content:" "}.fi.fis[data-v-c8aad0d0]{width:1em} .flag-icon {
.fi-cn[data-v-c8aad0d0]{background-image:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%20id='flag-icons-cn'%20viewBox='0%200%20640%20480'%3e%3cdefs%3e%3cpath%20id='cn-a'%20fill='%23ff0'%20d='M-.6.8%200-1%20.6.8-1-.3h2z'/%3e%3c/defs%3e%3cpath%20fill='%23ee1c25'%20d='M0%200h640v480H0z'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(71.9991%200%200%2072%20120%20120)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(-12.33562%20-20.5871%2020.58684%20-12.33577%20240.3%2048)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(-3.38573%20-23.75998%2023.75968%20-3.38578%20288%2095.8)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(6.5991%20-23.0749%2023.0746%206.59919%20288%20168)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(14.9991%20-18.73557%2018.73533%2014.99929%20240%20216)'/%3e%3c/svg%3e")} display: inline-block;
.fi-cn.fis[data-v-c8aad0d0]{background-image:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%20id='flag-icons-cn'%20viewBox='0%200%20512%20512'%3e%3cdefs%3e%3cpath%20id='cn-a'%20fill='%23ff0'%20d='M1-.3-.7.8%200-1%20.6.8-1-.3z'/%3e%3c/defs%3e%3cpath%20fill='%23ee1c25'%20d='M0%200h512v512H0z'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='translate(128%20128)scale(76.8)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='rotate(-121%20142.6%20-47)scale(25.5827)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='rotate(-98.1%20198%20-82)scale(25.6)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='rotate(-74%20272.4%20-114)scale(25.6137)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(16%20-19.968%2019.968%2016%20256%20230.4)'/%3e%3c/svg%3e")} background-size: contain;
.fi-us[data-v-c8aad0d0]{background-image:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20id='flag-icons-us'%20viewBox='0%200%20640%20480'%3e%3cpath%20fill='%23bd3d44'%20d='M0%200h640v480H0'/%3e%3cpath%20stroke='%23fff'%20stroke-width='37'%20d='M0%2055.3h640M0%20129h640M0%20203h640M0%20277h640M0%20351h640M0%20425h640'/%3e%3cpath%20fill='%23192f5d'%20d='M0%200h364.8v258.5H0'/%3e%3cmarker%20id='us-a'%20markerHeight='30'%20markerWidth='30'%3e%3cpath%20fill='%23fff'%20d='m14%200%209%2027L0%2010h28L5%2027z'/%3e%3c/marker%3e%3cpath%20fill='none'%20marker-mid='url(%23us-a)'%20d='m0%200%2016%2011h61%2061%2061%2061%2060L47%2037h61%2061%2060%2061L16%2063h61%2061%2061%2061%2060L47%2089h61%2061%2060%2061L16%20115h61%2061%2061%2061%2060L47%20141h61%2061%2060%2061L16%20166h61%2061%2061%2061%2060L47%20192h61%2061%2060%2061L16%20218h61%2061%2061%2061%2060z'/%3e%3c/svg%3e")} background-position: 50%;
.fi-us.fis[data-v-c8aad0d0]{background-image:url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20id='flag-icons-us'%20viewBox='0%200%20512%20512'%3e%3cpath%20fill='%23bd3d44'%20d='M0%200h512v512H0'/%3e%3cpath%20stroke='%23fff'%20stroke-width='40'%20d='M0%2058h512M0%20137h512M0%20216h512M0%20295h512M0%20374h512M0%20453h512'/%3e%3cpath%20fill='%23192f5d'%20d='M0%200h390v275H0z'/%3e%3cmarker%20id='us-a'%20markerHeight='30'%20markerWidth='30'%3e%3cpath%20fill='%23fff'%20d='m15%200%209.3%2028.6L0%2011h30L5.7%2028.6'/%3e%3c/marker%3e%3cpath%20fill='none'%20marker-mid='url(%23us-a)'%20d='m0%200%2018%2011h65%2065%2065%2065%2066L51%2039h65%2065%2065%2065L18%2066h65%2065%2065%2065%2066L51%2094h65%2065%2065%2065L18%20121h65%2065%2065%2065%2066L51%20149h65%2065%2065%2065L18%20177h65%2065%2065%2065%2066L51%20205h65%2065%2065%2065L18%20232h65%2065%2065%2065%2066z'/%3e%3c/svg%3e")} background-repeat: no-repeat;
position: relative;
vertical-align: middle;
}
.flag-icon::before {
content: "\00a0";
}
.flag-icon-cn {
background-image: url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%20id='flag-icons-cn'%20viewBox='0%200%20640%20480'%3e%3cdefs%3e%3cpath%20id='cn-a'%20fill='%23ff0'%20d='M-.6.8%200-1%20.6.8-1-.3h2z'/%3e%3c/defs%3e%3cpath%20fill='%23ee1c25'%20d='M0%200h640v480H0z'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(71.9991%200%200%2072%20120%20120)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(-12.33562%20-20.5871%2020.58684%20-12.33577%20240.3%2048)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(-3.38573%20-23.75998%2023.75968%20-3.38578%20288%2095.8)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(6.5991%20-23.0749%2023.0746%206.59919%20288%20168)'/%3e%3cuse%20xlink:href='%23cn-a'%20width='30'%20height='20'%20transform='matrix(14.9991%20-18.73557%2018.73533%2014.99929%20240%20216)'/%3e%3c/svg%3e");
}
.flag-icon-us {
background-image: url("data:image/svg+xml,%3csvg%20xmlns='http://www.w3.org/2000/svg'%20id='flag-icons-us'%20viewBox='0%200%20640%20480'%3e%3cpath%20fill='%23bd3d44'%20d='M0%200h640v480H0'/%3e%3cpath%20stroke='%23fff'%20stroke-width='37'%20d='M0%2055.3h640M0%20129h640M0%20203h640M0%20277h640M0%20351h640M0%20425h640'/%3e%3cpath%20fill='%23192f5d'%20d='M0%200h364.8v258.5H0'/%3e%3cmarker%20id='us-a'%20markerHeight='30'%20markerWidth='30'%3e%3cpath%20fill='%23fff'%20d='m14%200%209%2027L0%2010h28L5%2027z'/%3e%3c/marker%3e%3cpath%20fill='none'%20marker-mid='url(%23us-a)'%20d='m0%200%2016%2011h61%2061%2061%2061%2060L47%2037h61%2061%2060%2061L16%2063h61%2061%2061%2061%2060L47%2089h61%2061%2060%2061L16%20115h61%2061%2061%2061%2060L47%20141h61%2061%2060%2061L16%20166h61%2061%2061%2061%2060L47%20192h61%2061%2060%2061L16%20218h61%2061%2061%2061%2060z'/%3e%3c/svg%3e");
}
+8 -5
View File
@@ -3,7 +3,6 @@ import type { AcceptableValue } from 'reka-ui'
import { computed } from 'vue' import { computed } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import FlagIcon from 'vue3-flag-icons'
import type { Language } from '@/plugins/i18n' import type { Language } from '@/plugins/i18n'
@@ -35,8 +34,12 @@ const currentFlagCode = computed(() => {
<UiDropdownMenu> <UiDropdownMenu>
<UiDropdownMenuTrigger as-child> <UiDropdownMenuTrigger as-child>
<UiButton variant="ghost" size="icon" class="h-9 w-9"> <UiButton variant="ghost" size="icon" class="h-9 w-9">
<FlagIcon :code="currentFlagCode" :size="20" /> <span
<span class="sr-only">切换语言</span> class="flag-icon"
:class="`flag-icon-${currentFlagCode}`"
:style="{ width: '20px', height: '15px' }"
/>
<span class="sr-only">{{ $t('changeLanguage') }}</span>
</UiButton> </UiButton>
</UiDropdownMenuTrigger> </UiDropdownMenuTrigger>
<UiDropdownMenuContent align="end"> <UiDropdownMenuContent align="end">
@@ -47,11 +50,11 @@ const currentFlagCode = computed(() => {
@update:model-value="handleLocaleChange" @update:model-value="handleLocaleChange"
> >
<UiDropdownMenuRadioItem value="en"> <UiDropdownMenuRadioItem value="en">
<FlagIcon code="us" :size="18" /> <span class="flag-icon flag-icon-us" :style="{ width: '18px', height: '13.5px' }" />
<span class="ml-2">English</span> <span class="ml-2">English</span>
</UiDropdownMenuRadioItem> </UiDropdownMenuRadioItem>
<UiDropdownMenuRadioItem value="zh"> <UiDropdownMenuRadioItem value="zh">
<FlagIcon code="cn" :size="18" /> <span class="flag-icon flag-icon-cn" :style="{ width: '18px', height: '13.5px' }" />
<span class="ml-2">中文</span> <span class="ml-2">中文</span>
</UiDropdownMenuRadioItem> </UiDropdownMenuRadioItem>
</UiDropdownMenuRadioGroup> </UiDropdownMenuRadioGroup>
-1
View File
@@ -1 +0,0 @@
declare module 'vue3-flag-icons/styles'