129 lines
4.0 KiB
Vue
129 lines
4.0 KiB
Vue
<script>
|
|
// 操作系统图标依次尝试显式地址、图标地址和内置映射,加载失败后切换下一候选。
|
|
import "~/assets/styles/OsIcon.CAi4Iz2S.css";
|
|
import { watch } from "vue";
|
|
import { createBlock } from "vue";
|
|
import { ref } from "vue";
|
|
import { computed } from "vue";
|
|
import { createElementBlock } from "vue";
|
|
import { unref } from "vue";
|
|
import { defineComponent } from "vue";
|
|
import { openBlock } from "vue";
|
|
import { normalizeStyle } from "vue";
|
|
import { Icon } from "#components";
|
|
import { t as _plugin_vue_export_helper_t } from "~/lib/_plugin-vue_export-helper.js";
|
|
import { n as modules_n } from "~/lib/modules.js";
|
|
var f = [`src`, `width`, `height`],
|
|
p = Object.assign(
|
|
_plugin_vue_export_helper_t(
|
|
defineComponent({
|
|
__name: `OsIcon`,
|
|
props: {
|
|
url: {},
|
|
name: {},
|
|
icon: {},
|
|
size: {
|
|
default: 24,
|
|
},
|
|
},
|
|
setup(o) {
|
|
let u = o,
|
|
p = ref([]);
|
|
watch(
|
|
() => [u.url, u.name, u.icon],
|
|
() => {
|
|
p.value = [];
|
|
},
|
|
{
|
|
flush: `sync`,
|
|
},
|
|
);
|
|
// 仅接收站内绝对路径或无认证信息的 HTTP(S) 地址,拒绝控制字符和反斜杠。
|
|
function m(e) {
|
|
let t = String(e ?? ``).trim();
|
|
// eslint-disable-next-line no-control-regex -- 安全边界:拒绝图标 URL 内的控制字符。
|
|
if (!t || /[\u0000-\u0020\u007f\\]/.test(t)) return ``;
|
|
if (/^\/(?!\/)/.test(t)) return t;
|
|
try {
|
|
let e = new URL(t.startsWith(`//`) ? `https:${t}` : t);
|
|
return /^(https?:)$/.test(e.protocol) &&
|
|
!e.username &&
|
|
!e.password
|
|
? t
|
|
: ``;
|
|
} catch {
|
|
return ``;
|
|
}
|
|
}
|
|
let h = computed(() =>
|
|
modules_n(m(u.icon) ? `` : u.icon, void 0, u.name),
|
|
),
|
|
g = computed(
|
|
() =>
|
|
[m(u.url), m(u.icon), h.value].find(
|
|
(e) => e && !p.value.includes(e),
|
|
) || ``,
|
|
),
|
|
_ = computed(() =>
|
|
h.value.endsWith(`/Windows.svg`)
|
|
? `lucide:monitor`
|
|
: /(?:FreeBSD|ESXi|XenServer)\.svg$/.test(h.value)
|
|
? `lucide:hard-drive`
|
|
: `lucide:terminal`,
|
|
);
|
|
// 只记录当前候选的失败事件,避免前一张图片的迟到事件污染新图标。
|
|
function v(e) {
|
|
let t = e.target?.getAttribute(`src`);
|
|
t && t === g.value && p.value.push(t);
|
|
}
|
|
return (e, n) => {
|
|
let r = Icon;
|
|
return unref(g)
|
|
? (openBlock(),
|
|
createElementBlock(
|
|
`img`,
|
|
{
|
|
key: unref(g),
|
|
src: unref(g),
|
|
width: o.size,
|
|
height: o.size,
|
|
alt: ``,
|
|
"aria-hidden": `true`,
|
|
class: `os-icon`,
|
|
loading: `lazy`,
|
|
onError: v,
|
|
},
|
|
null,
|
|
40,
|
|
f,
|
|
))
|
|
: (openBlock(),
|
|
createBlock(
|
|
r,
|
|
{
|
|
key: 1,
|
|
name: unref(_),
|
|
"aria-hidden": `true`,
|
|
class: `os-icon-fallback`,
|
|
style: normalizeStyle({
|
|
width: `${o.size * 0.8}px`,
|
|
height: `${o.size * 0.8}px`,
|
|
}),
|
|
},
|
|
null,
|
|
8,
|
|
[`name`, `style`],
|
|
));
|
|
};
|
|
},
|
|
}),
|
|
[[`__scopeId`, `data-v-01907ce4`]],
|
|
),
|
|
{
|
|
__name: `OsIcon`,
|
|
},
|
|
);
|
|
export {};
|
|
export default p;
|
|
</script>
|