Merge pull request #109 from nagisa77/codex/add-icon-support-to-dropdown-menu

Support icon classes in dropdown menu
This commit is contained in:
Tim
2025-07-08 11:02:17 +08:00
committed by GitHub
2 changed files with 49 additions and 14 deletions

View File

@@ -4,7 +4,10 @@
<template v-if="multiple">
<span v-if="selectedLabels.length">
<template v-for="(label, idx) in selectedLabels" :key="label.id">
<img v-if="label.icon" :src="label.icon" class="option-icon" />
<template v-if="label.icon">
<img v-if="isImageIcon(label.icon)" :src="label.icon" class="option-icon" />
<i v-else :class="['option-icon', label.icon]"></i>
</template>
<span>{{ label.name }}</span>
<span v-if="idx !== selectedLabels.length - 1">, </span>
</template>
@@ -13,7 +16,10 @@
</template>
<template v-else>
<span v-if="selectedLabels.length">
<img v-if="selectedLabels[0].icon" :src="selectedLabels[0].icon" class="option-icon" />
<template v-if="selectedLabels[0].icon">
<img v-if="isImageIcon(selectedLabels[0].icon)" :src="selectedLabels[0].icon" class="option-icon" />
<i v-else :class="['option-icon', selectedLabels[0].icon]"></i>
</template>
<span>{{ selectedLabels[0].name }}</span>
</span>
<span v-else class="placeholder">{{ placeholder }}</span>
@@ -30,7 +36,10 @@
</div>
<template v-else>
<div class="dropdown-option" v-for="o in filteredOptions" :key="o.id" @click="select(o.id)" :class="{ 'selected': isSelected(o.id) }">
<img v-if="o.icon" :src="o.icon" class="option-icon" />
<template v-if="o.icon">
<img v-if="isImageIcon(o.icon)" :src="o.icon" class="option-icon" />
<i v-else :class="['option-icon', o.icon]"></i>
</template>
<span>{{ o.name }}</span>
</div>
</template>
@@ -130,7 +139,23 @@ export default {
return selectedLabels.value.some(label => label.id === id)
}
return { open, toggle, select, search, filteredOptions, wrapper, selectedLabels, isSelected, loading }
const isImageIcon = icon => {
if (!icon) return false
return /^https?:\/\//.test(icon) || icon.startsWith('/')
}
return {
open,
toggle,
select,
search,
filteredOptions,
wrapper,
selectedLabels,
isSelected,
loading,
isImageIcon
}
}
}
</script>
@@ -200,6 +225,9 @@ export default {
.option-icon {
width: 16px;
height: 16px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.dropdown-loading {

View File

@@ -29,18 +29,11 @@
<h3>管理员设置</h3>
<div class="form-row">
<label>发布规则</label>
<select v-model="publishMode">
<option value="DIRECT">直接发布</option>
<option value="REVIEW">审核后发布</option>
</select>
<Dropdown v-model="publishMode" :fetch-options="fetchPublishModes" />
</div>
<div class="form-row">
<label>密码强度</label>
<select v-model="passwordStrength">
<option value="LOW"></option>
<option value="MEDIUM"></option>
<option value="HIGH"></option>
</select>
<Dropdown v-model="passwordStrength" :fetch-options="fetchPasswordStrengths" />
</div>
</div>
<div class="buttons">
@@ -53,9 +46,10 @@
import { API_BASE_URL, toast } from '../main'
import { getToken, fetchCurrentUser } from '../utils/auth'
import BaseInput from '../components/BaseInput.vue'
import Dropdown from '../components/Dropdown.vue'
export default {
name: 'SettingsPageView',
components: { BaseInput },
components: { BaseInput, Dropdown },
data() {
return {
username: '',
@@ -83,6 +77,19 @@ export default {
onAvatarChange(e) {
this.avatarFile = e.target.files[0]
},
fetchPublishModes() {
return Promise.resolve([
{ id: 'DIRECT', name: '直接发布', icon: 'fas fa-bolt' },
{ id: 'REVIEW', name: '审核后发布', icon: 'fas fa-search' }
])
},
fetchPasswordStrengths() {
return Promise.resolve([
{ id: 'LOW', name: '低', icon: 'fas fa-lock-open' },
{ id: 'MEDIUM', name: '中', icon: 'fas fa-lock' },
{ id: 'HIGH', name: '高', icon: 'fas fa-user-shield' }
])
},
async loadAdminConfig() {
try {
const token = getToken()