Переработал обработчик иконок для гиперссылок
This commit is contained in:
parent
418892b3a4
commit
df54426a75
5 changed files with 143 additions and 104 deletions
|
@ -1,57 +1,11 @@
|
|||
<script lang="ts">
|
||||
import { tryGetIcon } from '$lib/util/IconResolver';
|
||||
import HoverIcon from './HoverIcon.svelte';
|
||||
|
||||
export let href: string;
|
||||
let className: string = '';
|
||||
export { className as class };
|
||||
export let customIcon: string | null = null;
|
||||
|
||||
let url: URL;
|
||||
let host: string;
|
||||
|
||||
const icons: Record<string, string> = {
|
||||
none: 'material-symbols:link',
|
||||
'steamcommunity.com': 'simple-icons:steam',
|
||||
'twitter.com': 'simple-icons:x',
|
||||
'x.com': 'simple-icons:x',
|
||||
'github.com': 'simple-icons:github',
|
||||
'youtube.com': 'simple-icons:youtube',
|
||||
'itch.io': 'simple-icons:itchdotio',
|
||||
'discord.gg': 'simple-icons:discord',
|
||||
'gamebanana.com': 'simple-icons:gamebanana',
|
||||
// https://хамяк.рф
|
||||
'xn--80auf8a2c.xn--p1ai': 'fluent-emoji-high-contrast:hamster',
|
||||
'teasanctuary.ru': '/icons/tea-sanctuary.svg',
|
||||
'hl.teasanctuary.ru': '/icons/half-life.svg',
|
||||
localhost: '/icons/tea-sanctuary.svg',
|
||||
email: 'material-symbols:alternate-email'
|
||||
};
|
||||
|
||||
function getHost(url: URL) {
|
||||
const isEmail = url.href.startsWith('mailto:');
|
||||
const hostname = isEmail ? 'email' : url.hostname;
|
||||
// const split = hostname.split('.');
|
||||
// const name = split[Math.max(split.length - 2, 0)];
|
||||
// if (split.length > 1) return `${name}.${split[split.length - 1]}`;
|
||||
|
||||
// return name;
|
||||
return hostname;
|
||||
}
|
||||
|
||||
function tryGetIcon(link: string) {
|
||||
try {
|
||||
url = new URL(link);
|
||||
host = getHost(url).replace(/\.com$/, '');
|
||||
} catch {
|
||||
return icons['none'];
|
||||
}
|
||||
|
||||
let domain = getHost(url).toLocaleLowerCase();
|
||||
let key = Object.keys(icons).find((key) => key == domain);
|
||||
if (key == null) return icons['none'];
|
||||
|
||||
return icons[key];
|
||||
}
|
||||
</script>
|
||||
|
||||
<a
|
||||
|
@ -60,7 +14,7 @@
|
|||
target="_blank"
|
||||
>
|
||||
<div class="shrink-0 rounded-l-xl bg-slate-800 p-2">
|
||||
<HoverIcon src={customIcon ?? tryGetIcon(href)} class="text-sm uppercase" text={host} />
|
||||
<HoverIcon src={customIcon ?? tryGetIcon(href)} class="text-sm uppercase" text={href} />
|
||||
</div>
|
||||
<div
|
||||
class="flex shrink-0 grow flex-nowrap items-center justify-center rounded-r-xl bg-slate-100 p-2 text-2xl text-nowrap text-slate-950"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { MediaQuery } from 'svelte/reactivity';
|
||||
import HoverIcon from './HoverIcon.svelte';
|
||||
import { tryGetIcon } from '$lib/util/IconResolver';
|
||||
|
||||
export let href: string;
|
||||
let className: string = '';
|
||||
|
@ -8,60 +9,13 @@
|
|||
export let customIcon: string | null = null;
|
||||
|
||||
const sm = new MediaQuery('width >= 40rem', false);
|
||||
|
||||
let url: URL;
|
||||
let host: string;
|
||||
|
||||
const icons: Record<string, string> = {
|
||||
none: 'material-symbols:link',
|
||||
'steamcommunity.com': 'simple-icons:steam',
|
||||
'twitter.com': 'simple-icons:x',
|
||||
'x.com': 'simple-icons:x',
|
||||
'github.com': 'simple-icons:github',
|
||||
'youtube.com': 'simple-icons:youtube',
|
||||
'itch.io': 'simple-icons:itchdotio',
|
||||
'discord.gg': 'simple-icons:discord',
|
||||
'gamebanana.com': 'simple-icons:gamebanana',
|
||||
// https://хамяк.рф
|
||||
'xn--80auf8a2c.xn--p1ai': 'fluent-emoji-high-contrast:hamster',
|
||||
'teasanctuary.ru': '/icons/tea-sanctuary.svg',
|
||||
'hl.teasanctuary.ru': '/icons/half-life.svg',
|
||||
localhost: '/icons/tea-sanctuary.svg',
|
||||
email: 'material-symbols:alternate-email'
|
||||
};
|
||||
|
||||
function getHost(url: URL) {
|
||||
const isEmail = url.href.startsWith('mailto:');
|
||||
const hostname = isEmail ? 'email' : url.hostname;
|
||||
// const split = hostname.split('.');
|
||||
// const name = split[Math.max(split.length - 2, 0)];
|
||||
// if (split.length > 1) return `${name}.${split[split.length - 1]}`;
|
||||
|
||||
// return name;
|
||||
return hostname;
|
||||
}
|
||||
|
||||
function tryGetIcon(link: string) {
|
||||
try {
|
||||
url = new URL(link);
|
||||
host = getHost(url).replace(/\.com$/, '');
|
||||
} catch {
|
||||
return icons['none'];
|
||||
}
|
||||
|
||||
let domain = getHost(url).toLocaleLowerCase();
|
||||
let key = Object.keys(icons).find((key) => key == domain);
|
||||
if (key == null) return icons['none'];
|
||||
|
||||
return icons[key];
|
||||
}
|
||||
</script>
|
||||
|
||||
<a {href} class="{className} inline-block group" target="_blank">
|
||||
<span class="inline-block {sm.current ? 'size-8 rounded-xl p-1' : 'size-6 rounded-sm p-0.5'} bg-emerald-800 align-bottom transition-all group-hover:scale-110">
|
||||
<HoverIcon
|
||||
src={customIcon ?? tryGetIcon(href)}
|
||||
text={host}
|
||||
text={href}
|
||||
size={sm.current ? 24 : 20}
|
||||
/>
|
||||
</span>
|
||||
|
|
65
src/lib/util/IconResolver.ts
Normal file
65
src/lib/util/IconResolver.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
const icons: Record<string, string> = {
|
||||
none: 'material-symbols:link',
|
||||
'steamcommunity.com': 'simple-icons:steam',
|
||||
'twitter.com': 'simple-icons:x',
|
||||
'x.com': 'simple-icons:x',
|
||||
'github.com': 'simple-icons:github',
|
||||
'youtube.com': 'simple-icons:youtube',
|
||||
'itch.io': 'simple-icons:itchdotio',
|
||||
'discord.gg': 'simple-icons:discord',
|
||||
'gamebanana.com': 'simple-icons:gamebanana',
|
||||
'bsky.app': 'simple-icons:bluesky',
|
||||
'bsky.social': 'simple-icons:bluesky',
|
||||
// https://хамяк.рф
|
||||
'xn--80auf8a2c.xn--p1ai': 'fluent-emoji-high-contrast:hamster',
|
||||
'teasanctuary.ru': '/icons/tea-sanctuary-white.svg',
|
||||
'hl.teasanctuary.ru': '/icons/half-life.svg',
|
||||
'git.teasanctuary.ru': 'devicon-plain:git',
|
||||
localhost: '/icons/tea-sanctuary-white.svg',
|
||||
email: 'material-symbols:alternate-email'
|
||||
};
|
||||
|
||||
// Особые случаи, когда одним доменом второго уровня не ограничишься (например, randomtrash.itch.io)
|
||||
const specialResolvers: Record<string, (url: URL) => string> = {
|
||||
'teasanctuary.ru': (url) => {
|
||||
// Домены третьего уровня и выше
|
||||
const prefix = url.hostname.split('.').toReversed();
|
||||
prefix.shift();
|
||||
prefix.shift();
|
||||
if (prefix[0] === "hl") {
|
||||
return 'hl.teasanctuary.ru';
|
||||
}
|
||||
if (prefix[0] === "git" || url.pathname.split('/')[1] == "git") {
|
||||
return 'git.teasanctuary.ru';
|
||||
}
|
||||
return 'teasanctuary.ru';
|
||||
},
|
||||
// Игнорируем имя пользователя
|
||||
'bsky.app': (url) => 'bsky.app',
|
||||
'bsky.social': (url) => 'bsky.social',
|
||||
'itch.io': (url) => 'itch.io'
|
||||
}
|
||||
|
||||
function getIconFromUrl(url: URL): string | undefined {
|
||||
const href = url.href;
|
||||
if (href.startsWith('mailto:'))
|
||||
return 'email';
|
||||
|
||||
const hostname = url.hostname;
|
||||
const secondLevel = hostname.match(/(([A-Za-z0-9\-])+\.([A-Za-z0-9\-])+)$/)?.at(0) ?? '';
|
||||
if (specialResolvers[secondLevel])
|
||||
return icons[specialResolvers[secondLevel](url)];
|
||||
|
||||
return icons[hostname];
|
||||
}
|
||||
|
||||
export function tryGetIcon(link: string): string {
|
||||
let url: URL;
|
||||
try {
|
||||
url = new URL(link);
|
||||
} catch {
|
||||
return icons['none'];
|
||||
}
|
||||
|
||||
return getIconFromUrl(url) ?? icons['none'];
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue