feat(icons): wire the universal picker into tabbar/floating settings and keep customsvg through their save paths

手机底部Tab and 右侧悬浮按钮 settings pages swap their icon text inputs
for the shared FaIconPicker (with a new IconValue preview component that
renders FA/sprite/custom SVG values in lists and previews). footer.php
tabbar/floating/sub-item icons and the VIP float render through
aksrt_icon_markup so every stored format displays; GlobalControllerPart1
and the VIP helper drop the FA-only regex gate and sanitize icon values
through aksrt_sanitize_icon_value. The picker popover tabs now wrap
instead of overflowing, and FA grid previews use style-only classes.
This commit is contained in:
2026-09-06 14:27:49 +08:00
parent d89752d543
commit 70cba11fb7
8 changed files with 96 additions and 63 deletions
@@ -1,6 +1,6 @@
<template>
<div class="aksrt-fa-icon-picker">
<n-popover trigger="click" placement="bottom-start" :width="400" :style="{ padding: 0 }">
<n-popover trigger="click" placement="bottom-start" :width="460" :style="{ padding: 0 }">
<template #trigger>
<n-input
:value="modelValue"
@@ -10,20 +10,8 @@
@clear="$emit('update:modelValue', '')"
>
<template #prefix>
<!-- FA value -->
<FaIcon v-if="isFaValue(modelValue)" :icon="modelValue" />
<!-- Built-in sprite value -->
<span
v-else-if="isZibsvgValue(modelValue)"
class="aksrt-icon-picker__preview-svg"
v-html="zibsvgMarkup(modelValue)"
></span>
<!-- Inline custom SVG value -->
<span
v-else-if="isCustomSvgValue(modelValue)"
class="aksrt-icon-picker__preview-svg"
v-html="cleanSvg(modelValue.slice(10))"
></span>
<IconValue v-if="modelValue" :value="modelValue" />
<template v-else></template>
</template>
<template #suffix>
<FaIcon icon="fa fas fa-chevron-down" :size="12" />
@@ -80,7 +68,7 @@
:title="icon"
@click="selectIcon(icon)"
>
<i v-if="activeGroup.type === 'fa'" :class="['fa', activeTab, icon]"></i>
<i v-if="activeGroup.type === 'fa'" :class="[activeTab, icon]"></i>
<span
v-else
class="aksrt-icon-picker__preview-svg"
@@ -104,12 +92,10 @@
*/
import { ref, computed, onMounted } from 'vue'
import FaIcon from './FaIcon.vue'
import IconValue from './IconValue.vue'
import api from '@/api/index.js'
import {
cleanSvg,
isFaValue,
isZibsvgValue,
isCustomSvgValue,
zibsvgMarkup,
composeIconValue,
} from '@/utils/icons.js'
@@ -184,6 +170,10 @@ onMounted(async () => {
margin-bottom: 10px;
}
.aksrt-icon-picker__tabs :deep(.n-radio-group) {
flex-wrap: wrap;
}
.aksrt-icon-picker__grid {
display: grid;
grid-template-columns: repeat(8, 1fr);
@@ -0,0 +1,48 @@
<template>
<!-- FA class value -->
<i v-if="isFaValue(value)" :class="faClass" aria-hidden="true"></i>
<!-- Built-in sprite value -->
<span
v-else-if="isZibsvgValue(value)"
class="aksrt-icon-value__svg"
v-html="zibsvgMarkup(value)"
></span>
<!-- Inline custom SVG value -->
<span
v-else-if="isCustomSvgValue(value)"
class="aksrt-icon-value__svg"
v-html="cleanSvg(value.slice(10))"
></span>
</template>
<script setup>
/**
* IconValue — renders any icon-picker value ("fa fas fa-x", "zibsvg-key",
* "customsvg-<svg>") as inline preview markup.
*/
import { computed } from 'vue'
import { cleanSvg, isFaValue, isZibsvgValue, isCustomSvgValue, zibsvgMarkup } from '@/utils/icons.js'
const props = defineProps({
value: { type: String, default: '' },
})
const faClass = computed(() => {
const raw = String(props.value || '').trim()
if (raw.startsWith('fa-')) return `fa fas ${raw}`
return raw
})
</script>
<style scoped>
.aksrt-icon-value__svg {
display: inline-flex;
}
.aksrt-icon-value__svg :deep(svg),
.aksrt-icon-value__svg svg {
width: 1em;
height: 1em;
fill: currentColor;
}
</style>