83 lines
No EOL
3 KiB
TypeScript
83 lines
No EOL
3 KiB
TypeScript
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") {
|
|
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'];
|
|
}
|
|
|
|
/**
|
|
* Проверка на "локальность" ссылки - принадлежность её этому сайту. Используется, например,
|
|
* в социальных ссылках, чтобы не открывать новую вкладку для страниц сайта.
|
|
* @param link Локальная либо глобальная ссылка
|
|
* @returns true, если ссылка не ведёт за пределы сайта
|
|
*/
|
|
export function isLinkLocal(link: string): boolean {
|
|
let url: URL;
|
|
try {
|
|
url = new URL(link);
|
|
} catch {
|
|
return true;
|
|
}
|
|
|
|
// Поддомены teasanctuary.ru должны всегда быть "внешними"
|
|
return url.hostname === "" || url.hostname === "teasanctuary.ru";
|
|
} |