Skip to content

Commit 95a08bc

Browse files
authored
feat: auto-import icon components (#681)
Signed-off-by: Bob Du <i@bobdu.cc>
1 parent 80cd9be commit 95a08bc

22 files changed

Lines changed: 212 additions & 156 deletions

File tree

AGENTS.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@
2525
- ESLint is the source of truth; run `pnpm lint:fix` before commit.
2626
- Commit hooks are managed by Husky (`pnpm bootstrap`).
2727

28+
## Icons (unplugin-icons)
29+
- Use `Icon*` components (e.g., `<IconRiDownload2Line />`) in templates; they are auto-imported.
30+
- In script/render functions, `Icon*` components are also auto-imported via `unplugin-auto-import`; avoid manual `~icons/...` imports.
31+
- If an icon name fails, switch to a valid icon in the same collection (e.g., `ri`), then rerun the app.
32+
- Loader note: `@iconify/utils` uses `searchForIcon()` with `getPossibleIconNames()`, so numeric names like `settings4-line` can resolve to `settings-4-line` at load time.
33+
- Rule: always use the `Icon*` component form (e.g., `<IconRiSettings4Line />`) for icons going forward.
34+
2835
## i18n Keys & Usage
2936
- Locale files live in `src/locales/` (`en-US.json`, `zh-CN.json`, `zh-TW.json`, `ko-KR.json`).
3037
- `en-US.json` is the canonical schema; add new keys there first, then mirror them in other locales.

auto-imports.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@
77
export {}
88
declare global {
99
const EffectScope: typeof import('vue').EffectScope
10+
const IconIcOutlineCode: typeof import('~icons/ic/outline-code').default
11+
const IconIcOutlineCodeOff: typeof import('~icons/ic/outline-code-off').default
12+
const IconMdiFormatVerticalAlignBottom: typeof import('~icons/mdi/format-vertical-align-bottom').default
13+
const IconMdiFormatVerticalAlignTop: typeof import('~icons/mdi/format-vertical-align-top').default
14+
const IconMdiReorderHorizontal: typeof import('~icons/mdi/reorder-horizontal').default
15+
const IconRiContrastLine: typeof import('~icons/ri/contrast-line').default
16+
const IconRiDeleteBinLine: typeof import('~icons/ri/delete-bin-line').default
17+
const IconRiExternalLinkLine: typeof import('~icons/ri/external-link-line').default
18+
const IconRiFileCopy2Line: typeof import('~icons/ri/file-copy2-line').default
19+
const IconRiMoonFoggyLine: typeof import('~icons/ri/moon-foggy-line').default
20+
const IconRiSunFoggyLine: typeof import('~icons/ri/sun-foggy-line').default
1021
const acceptHMRUpdate: typeof import('pinia').acceptHMRUpdate
1122
const computed: typeof import('vue').computed
1223
const createApp: typeof import('vue').createApp

components.d.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,51 @@ export {}
1111
/* prettier-ignore */
1212
declare module 'vue' {
1313
export interface GlobalComponents {
14+
IconIcOutlineChat: typeof import('~icons/ic/outline-chat')['default']
15+
IconMageBoxUpload: typeof import('~icons/mage/box-upload')['default']
16+
IconMdiFormatVerticalAlignBottom: typeof import('~icons/mdi/format-vertical-align-bottom')['default']
17+
IconMdiFormatVerticalAlignTop: typeof import('~icons/mdi/format-vertical-align-top')['default']
18+
IconMdiGift: typeof import('~icons/mdi/gift')['default']
19+
IconMdiLightbulbOutline: typeof import('~icons/mdi/lightbulb-outline')['default']
20+
IconMdiReorderHorizontal: typeof import('~icons/mdi/reorder-horizontal')['default']
21+
IconMdiWeb: typeof import('~icons/mdi/web')['default']
22+
IconRiAddFill: typeof import('~icons/ri/add-fill')['default']
23+
IconRiAlignJustify: typeof import('~icons/ri/align-justify')['default']
24+
IconRiAlignRight: typeof import('~icons/ri/align-right')['default']
25+
IconRiArrowDownSLine: typeof import('~icons/ri/arrow-down-s-line')['default']
26+
IconRiBarChartBoxLine: typeof import('~icons/ri/bar-chart-box-line')['default']
27+
IconRiBubbleChartFill: typeof import('~icons/ri/bubble-chart-fill')['default']
28+
IconRiChatDownloadLine: typeof import('~icons/ri/chat-download-line')['default']
29+
IconRiChatHistoryLine: typeof import('~icons/ri/chat-history-line')['default']
30+
IconRiChatQuoteLine: typeof import('~icons/ri/chat-quote-line')['default']
31+
IconRiChatUploadLine: typeof import('~icons/ri/chat-upload-line')['default']
32+
IconRiCloseCircleLine: typeof import('~icons/ri/close-circle-line')['default']
33+
IconRiDeleteBack2Fill: typeof import('~icons/ri/delete-back2-fill')['default']
34+
IconRiDeleteBinLine: typeof import('~icons/ri/delete-bin-line')['default']
35+
IconRiDownload2Fill: typeof import('~icons/ri/download2-fill')['default']
36+
IconRiDownload2Line: typeof import('~icons/ri/download2-line')['default']
37+
IconRiDownloadLine: typeof import('~icons/ri/download-line')['default']
38+
IconRiEditLine: typeof import('~icons/ri/edit-line')['default']
39+
IconRiEqualizerLine: typeof import('~icons/ri/equalizer-line')['default']
40+
IconRiFileUserLine: typeof import('~icons/ri/file-user-line')['default']
41+
IconRiImageEditLine: typeof import('~icons/ri/image-edit-line')['default']
42+
IconRiInboxLine: typeof import('~icons/ri/inbox-line')['default']
43+
IconRiKey2Line: typeof import('~icons/ri/key2-line')['default']
44+
IconRiLink: typeof import('~icons/ri/link')['default']
45+
IconRiListSettingsLine: typeof import('~icons/ri/list-settings-line')['default']
46+
IconRiMailLine: typeof import('~icons/ri/mail-line')['default']
47+
IconRiMessage3Line: typeof import('~icons/ri/message3-line')['default']
48+
IconRiMore2Fill: typeof import('~icons/ri/more2-fill')['default']
49+
IconRiQuestionAnswerLine: typeof import('~icons/ri/question-answer-line')['default']
50+
IconRiRestartLine: typeof import('~icons/ri/restart-line')['default']
51+
IconRiSaveLine: typeof import('~icons/ri/save-line')['default']
52+
IconRiSendPlaneFill: typeof import('~icons/ri/send-plane-fill')['default']
53+
IconRiSettings4Line: typeof import('~icons/ri/settings4-line')['default']
54+
IconRiSettingsLine: typeof import('~icons/ri/settings-line')['default']
55+
IconRiStopCircleLine: typeof import('~icons/ri/stop-circle-line')['default']
56+
IconRiUpload2Fill: typeof import('~icons/ri/upload2-fill')['default']
57+
IconRiUser5Line: typeof import('~icons/ri/user5-line')['default']
58+
IconUilExit: typeof import('~icons/uil/exit')['default']
1459
NAutoComplete: typeof import('naive-ui')['NAutoComplete']
1560
NAvatar: typeof import('naive-ui')['NAvatar']
1661
NButton: typeof import('naive-ui')['NButton']

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"@antfu/eslint-config": "^6.3.0",
2828
"@commitlint/cli": "^20.1.0",
2929
"@commitlint/config-conventional": "^20.0.0",
30-
"@iconify/vue": "^5.0.0",
30+
"@iconify/json": "^2.2.397",
3131
"@tailwindcss/vite": "^4.1.17",
3232
"@types/katex": "^0.16.7",
3333
"@types/markdown-it": "^14.1.2",
@@ -56,6 +56,7 @@
5656
"tailwindcss": "^4.1.17",
5757
"typescript": "~5.9.3",
5858
"unplugin-auto-import": "^20.3.0",
59+
"unplugin-icons": "^22.5.0",
5960
"unplugin-vue-components": "^30.0.0",
6061
"vite": "^7.2.6",
6162
"vue": "^3.5.25",

pnpm-lock.yaml

Lines changed: 54 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/common/PromptStore/index.vue

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { UserPrompt } from '@/components/common/Setting/model'
66
import { useBasicLayout } from '@/hooks/useBasicLayout'
77
import { useAuthStoreWithout, usePromptStore } from '@/store'
88
import { rankBetween } from '@/utils/lexorank'
9-
import { SvgIcon } from '..'
109
import PromptRecommend from '../../../assets/recommend.json'
1110
1211
const props = defineProps<Props>()
@@ -477,7 +476,7 @@ function createColumns(): DataTableColumns<DataProps> {
477476
draggingId.value = null
478477
},
479478
},
480-
{ default: () => h(SvgIcon, { icon: 'mdi:reorder-horizontal' }) },
479+
{ default: () => h(IconMdiReorderHorizontal) },
481480
),
482481
default: () => t('store.drag'),
483482
},
@@ -494,7 +493,7 @@ function createColumns(): DataTableColumns<DataProps> {
494493
disabled,
495494
onClick: () => moveToTop(row),
496495
},
497-
{ default: () => h(SvgIcon, { icon: 'mdi:format-vertical-align-top' }) },
496+
{ default: () => h(IconMdiFormatVerticalAlignTop) },
498497
),
499498
default: () => t('store.moveTop'),
500499
},
@@ -511,7 +510,7 @@ function createColumns(): DataTableColumns<DataProps> {
511510
disabled,
512511
onClick: () => moveToBottom(row),
513512
},
514-
{ default: () => h(SvgIcon, { icon: 'mdi:format-vertical-align-bottom' }) },
513+
{ default: () => h(IconMdiFormatVerticalAlignBottom) },
515514
),
516515
default: () => t('store.moveBottom'),
517516
},
@@ -768,7 +767,7 @@ async function handleGetUserPromptList() {
768767
@dragstart="handleMobileDragStart($event, item)"
769768
@dragend="handleMobileDragEnd"
770769
>
771-
<SvgIcon icon="mdi:reorder-horizontal" />
770+
<IconMdiReorderHorizontal />
772771
</NButton>
773772
</template>
774773
{{ t('store.drag') }}
@@ -781,7 +780,7 @@ async function handleGetUserPromptList() {
781780
:disabled="ordering || isSearchActive"
782781
@click="moveToTop(item)"
783782
>
784-
<SvgIcon icon="mdi:format-vertical-align-top" />
783+
<IconMdiFormatVerticalAlignTop />
785784
</NButton>
786785
</template>
787786
{{ t('store.moveTop') }}
@@ -794,7 +793,7 @@ async function handleGetUserPromptList() {
794793
:disabled="ordering || isSearchActive"
795794
@click="moveToBottom(item)"
796795
>
797-
<SvgIcon icon="mdi:format-vertical-align-bottom" />
796+
<IconMdiFormatVerticalAlignBottom />
798797
</NButton>
799798
</template>
800799
{{ t('store.moveBottom') }}
@@ -848,11 +847,11 @@ async function handleGetUserPromptList() {
848847
:href="info.url"
849848
target="_blank"
850849
>
851-
<SvgIcon class="text-xl" icon="ri:link" />
850+
<IconRiLink class="text-xl" />
852851
</a>
853852
</NButton>
854853
<NButton text @click="setDownloadURL(info.downloadUrl) ">
855-
<SvgIcon class="text-xl" icon="ri:add-fill" />
854+
<IconRiAddFill class="text-xl" />
856855
</NButton>
857856
</div>
858857
</template>

src/components/common/Setting/BuiltInPrompt.vue

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import { fetchBuiltInPromptList, fetchDeleteBuiltInPrompt, fetchUpsertBuiltInPro
55
import { BuiltInPrompt } from '@/components/common/Setting/model'
66
import { useBasicLayout } from '@/hooks/useBasicLayout'
77
import { rankBetween } from '@/utils/lexorank'
8-
import { SvgIcon } from '..'
98
109
const { t } = useI18n()
1110
const message = useMessage()
@@ -236,7 +235,7 @@ function createColumns(): DataTableColumns<BuiltInPrompt> {
236235
draggingId.value = null
237236
},
238237
},
239-
{ default: () => h(SvgIcon, { icon: 'mdi:reorder-horizontal' }) },
238+
{ default: () => h(IconMdiReorderHorizontal) },
240239
),
241240
default: () => t('store.drag'),
242241
},
@@ -253,7 +252,7 @@ function createColumns(): DataTableColumns<BuiltInPrompt> {
253252
disabled,
254253
onClick: () => moveToTop(row),
255254
},
256-
{ default: () => h(SvgIcon, { icon: 'mdi:format-vertical-align-top' }) },
255+
{ default: () => h(IconMdiFormatVerticalAlignTop) },
257256
),
258257
default: () => t('store.moveTop'),
259258
},
@@ -270,7 +269,7 @@ function createColumns(): DataTableColumns<BuiltInPrompt> {
270269
disabled,
271270
onClick: () => moveToBottom(row),
272271
},
273-
{ default: () => h(SvgIcon, { icon: 'mdi:format-vertical-align-bottom' }) },
272+
{ default: () => h(IconMdiFormatVerticalAlignBottom) },
274273
),
275274
default: () => t('store.moveBottom'),
276275
},

src/components/common/Setting/ChatRecord.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
<script setup lang="ts">
22
import { NButton } from 'naive-ui'
33
import { fetchGetChatHistory, fetchGetChatRoomsCount, fetchGetUsers } from '@/api'
4-
import { SvgIcon } from '@/components/common'
54
import { useBasicLayout } from '@/hooks/useBasicLayout'
65
import Message from '@/views/chat/components/Message/index.vue'
76
@@ -168,7 +167,7 @@ onMounted(async () => {
168167
<NSpin :show="chatLoading">
169168
<template v-if="!dataSources.length">
170169
<div class="flex items-center justify-center mt-4 text-center text-neutral-300">
171-
<SvgIcon icon="ri:bubble-chart-fill" class="mr-2 text-3xl" />
170+
<IconRiBubbleChartFill class="mr-2 text-3xl" />
172171
<span>Aha~</span>
173172
</div>
174173
</template>

0 commit comments

Comments
 (0)