mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
fix(web): unify channel icon fallbacks (#397)
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 669 B |
@@ -1,5 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-110 -110 740 740" fill="none">
|
||||
<path fill="#000" d="M13.7 11.9v496.2h35.7V520H0V0h49.4v11.9H13.7Z"/>
|
||||
<path fill="#000" d="M166.3 169.2v25.1h.7c6.7-9.6 14.8-17 24.2-22.2 9.4-5.3 20.3-7.9 32.5-7.9 11.7 0 22.4 2.3 32.1 6.8 9.7 4.5 17 12.6 22.1 24 5.5-8.1 13-15.3 22.4-21.5 9.4-6.2 20.6-9.3 33.5-9.3 9.8 0 18.9 1.2 27.3 3.6 8.4 2.4 15.5 6.2 21.5 11.5 6 5.3 10.6 12.1 14 20.6 3.3 8.5 5 18.7 5 30.7v124.1h-50.9V249.6c0-6.2-.2-12.1-.7-17.6-.5-5.5-1.8-10.3-3.9-14.3-2.2-4.1-5.3-7.3-9.5-9.7-4.2-2.4-9.9-3.6-17-3.6-7.2 0-13 1.4-17.4 4.1-4.4 2.8-7.9 6.3-10.4 10.8-2.5 4.4-4.2 9.4-5 15.1-.8 5.6-1.3 11.3-1.3 17v103.3h-50.9v-104c0-5.5-.1-10.9-.4-16.3-.2-5.4-1.3-10.3-3.1-14.9-1.8-4.5-4.8-8.2-9-10.9-4.2-2.7-10.3-4.1-18.5-4.1-2.4 0-5.6.5-9.5 1.6-3.9 1.1-7.8 3.1-11.5 6.1-3.7 3-6.9 7.3-9.5 12.9-2.6 5.6-3.9 13-3.9 22.1v107.6h-50.9V169.2h50.6Z"/>
|
||||
<path fill="#000" d="M506.3 508.1V11.9h-35.7V0H520v520h-49.4v-11.9h35.7Z"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 970 B |
Binary file not shown.
|
Before Width: | Height: | Size: 6.6 KiB |
@@ -7,6 +7,8 @@
|
||||
/>
|
||||
<span
|
||||
v-else
|
||||
class="inline-flex items-center justify-center font-medium leading-none"
|
||||
:style="fallbackStyle"
|
||||
v-bind="$attrs"
|
||||
>{{ fallback }}</span>
|
||||
</template>
|
||||
@@ -24,7 +26,9 @@ import {
|
||||
Wechatoa,
|
||||
Wecom,
|
||||
Matrix,
|
||||
Misskey,
|
||||
} from '@memohai/icon'
|
||||
import { channelIconFallbackText } from '@/utils/channel-icon-fallback'
|
||||
|
||||
const channelIcons: Record<string, Component> = {
|
||||
qq: Qq,
|
||||
@@ -37,7 +41,7 @@ const channelIcons: Record<string, Component> = {
|
||||
wechatoa: Wechatoa,
|
||||
wecom: Wecom,
|
||||
matrix: Matrix,
|
||||
// misskey: Misskey,
|
||||
misskey: Misskey,
|
||||
dingtalk: Dingtalk,
|
||||
}
|
||||
|
||||
@@ -50,11 +54,19 @@ const props = withDefaults(defineProps<{
|
||||
|
||||
defineOptions({ inheritAttrs: false })
|
||||
|
||||
const normalizedChannel = computed(() =>
|
||||
props.channel.trim().toLowerCase(),
|
||||
)
|
||||
|
||||
const iconComponent = computed<Component | undefined>(() =>
|
||||
channelIcons[props.channel],
|
||||
channelIcons[normalizedChannel.value],
|
||||
)
|
||||
|
||||
const fallback = computed(() =>
|
||||
props.channel.slice(0, 2).toUpperCase(),
|
||||
channelIconFallbackText(props.channel),
|
||||
)
|
||||
|
||||
const fallbackStyle = computed(() => ({
|
||||
fontSize: typeof props.size === 'number' ? `${props.size}px` : props.size,
|
||||
}))
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { channelIconFallbackText } from './channel-icon-fallback'
|
||||
|
||||
describe('channelIconFallbackText', () => {
|
||||
it('returns empty text for empty channel keys', () => {
|
||||
expect(channelIconFallbackText('')).toBe('')
|
||||
expect(channelIconFallbackText(' ')).toBe('')
|
||||
})
|
||||
|
||||
it('uses explicit built-in fallbacks for non-brand channels', () => {
|
||||
expect(channelIconFallbackText('local')).toBe('LC')
|
||||
expect(channelIconFallbackText('cli')).toBe('CLI')
|
||||
expect(channelIconFallbackText('web')).toBe('Web')
|
||||
})
|
||||
|
||||
it('normalizes casing and whitespace', () => {
|
||||
expect(channelIconFallbackText(' Discord ')).toBe('DI')
|
||||
})
|
||||
|
||||
it('creates initials for multi-part unknown channels', () => {
|
||||
expect(channelIconFallbackText('custom-bridge')).toBe('CB')
|
||||
expect(channelIconFallbackText('foo_bar')).toBe('FB')
|
||||
})
|
||||
|
||||
it('uses the first two alphanumeric characters for simple unknown channels', () => {
|
||||
expect(channelIconFallbackText('misskey')).toBe('MI')
|
||||
expect(channelIconFallbackText('qq')).toBe('QQ')
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,20 @@
|
||||
const explicitChannelFallbacks: Record<string, string> = {
|
||||
cli: 'CLI',
|
||||
local: 'LC',
|
||||
web: 'Web',
|
||||
}
|
||||
|
||||
export function channelIconFallbackText(channel: string): string {
|
||||
const normalized = channel.trim().toLowerCase()
|
||||
if (!normalized) return ''
|
||||
|
||||
const explicit = explicitChannelFallbacks[normalized]
|
||||
if (explicit) return explicit
|
||||
|
||||
const parts = normalized.match(/[a-z0-9]+/gi) ?? []
|
||||
if (parts.length > 1) {
|
||||
return parts.slice(0, 2).map((part) => part[0]?.toUpperCase() ?? '').join('')
|
||||
}
|
||||
|
||||
return normalized.replace(/[^a-z0-9]/gi, '').slice(0, 2).toUpperCase()
|
||||
}
|
||||
@@ -23,9 +23,7 @@ var embeddedStaticRoutes = map[string]struct {
|
||||
assetPath string
|
||||
contentType string
|
||||
}{
|
||||
"/logo.png": {assetPath: "logo.png", contentType: "image/png"},
|
||||
"/channels/telegram.webp": {assetPath: "channels/telegram.webp", contentType: "image/webp"},
|
||||
"/channels/feishu.png": {assetPath: "channels/feishu.png", contentType: "image/png"},
|
||||
"/logo.png": {assetPath: "logo.png", contentType: "image/png"},
|
||||
}
|
||||
|
||||
func NewEmbeddedWebHandler(log *slog.Logger) (*EmbeddedWebHandler, error) {
|
||||
|
||||
@@ -51,6 +51,7 @@ export { default as Microsoft } from './icons/Microsoft.vue'
|
||||
export { default as MicrosoftColor } from './icons/MicrosoftColor.vue'
|
||||
export { default as Minimax } from './icons/Minimax.vue'
|
||||
export { default as MinimaxColor } from './icons/MinimaxColor.vue'
|
||||
export { default as Misskey } from './icons/Misskey.vue'
|
||||
export { default as Mistral } from './icons/Mistral.vue'
|
||||
export { default as MistralColor } from './icons/MistralColor.vue'
|
||||
export { default as Moonshot } from './icons/Moonshot.vue'
|
||||
|
||||
Reference in New Issue
Block a user