feat(admin): back the SPA icon picker with the server catalog

FaIconPicker drops its duplicated hard-coded FA subset and loads
GET /aksrt/v1/icons/catalog: full solid/regular/brands sets, the
built-in zibsvg sprite tab and an inline custom SVG tab. Props/emit
surface is unchanged; the system-notice title icon schema drift
(input vs icon) is fixed on the JS side.
This commit is contained in:
2026-09-06 12:59:30 +08:00
parent 009f9874c0
commit 5b5db0f8f5
5 changed files with 211 additions and 96 deletions
+62
View File
@@ -0,0 +1,62 @@
/**
* Icon value helpers shared by admin UI.
*
* Supported stored formats:
* "fa fas fa-star" — FA5 class string
* "zibsvg-hot" — theme built-in SVG sprite key (window.aksrt_svgs)
* "customsvg-<svg>" — inline user SVG markup
*/
/** Clean pasted SVG markup: strip authoring leftovers, reject unsafe content. */
export function cleanSvg(raw) {
const text = String(raw || '').trim()
if (!text) return ''
let doc
try {
doc = new DOMParser().parseFromString(text, 'image/svg+xml')
} catch (e) {
return ''
}
if (doc.querySelector('parsererror')) return ''
const svg = doc.querySelector('svg')
if (!svg || svg.querySelector('script, foreignObject, animate')) return ''
;['class', 'id', 'style', 't', 'version', 'p-id'].forEach((attr) => svg.removeAttribute(attr))
Array.from(svg.attributes).forEach((attr) => {
if (attr.name.indexOf('data-') === 0) svg.removeAttribute(attr.name)
})
const keep = new XMLSerializer().serializeToString(svg)
return /<path|<use|<g\b|<circle|<rect|<polygon|<ellipse|<line/i.test(keep) ? keep : ''
}
export function isFaValue(value) {
return /^fa[\s-]/.test(String(value || '').trim())
}
export function isZibsvgValue(value) {
return String(value || '').trim().startsWith('zibsvg-')
}
export function isCustomSvgValue(value) {
return String(value || '').trim().startsWith('customsvg-')
}
/** Sprite key of a zibsvg value, e.g. "zibsvg-hot" → "hot". */
export function zibsvgKey(value) {
return String(value || '')
.trim()
.slice(7)
.replace(/[^a-zA-Z0-9_-]/g, '')
}
/** Inline markup for a zibsvg sprite preview (sprite injected by svg-icon.js). */
export function zibsvgMarkup(value) {
const key = zibsvgKey(value)
return key ? `<svg class="icon" aria-hidden="true"><use xlink:href="#icon-${key}"></use></svg>` : ''
}
/** Value of a picker selection composed from a catalog group + icon name. */
export function composeIconValue(group, name) {
if (group.type === 'fa') return `fa ${group.id} fa-${name}`
if (group.type === 'svg') return `zibsvg-${name}`
return String(name || '')
}