// TODO: чашки на иконках выглядят страшненько, пока что пусть лучше будет голая ссылка const icons: Record = { none: 'material-symbols:link', 'steamcommunity.com': 'simple-icons:steam', 'steampowered.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.com': 'simple-icons:discord', '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', rss: 'material-symbols:rss-feed' }; // Особые случаи, когда одним доменом второго уровня не ограничишься (например, randomtrash.itch.io) const specialResolvers: Record 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'; } // Особый случай: приглашение в Discord if (url.pathname.startsWith('/discord')) { return 'discord.gg'; } return 'teasanctuary.ru'; }, // Игнорируем имя пользователя 'bsky.app': (url) => 'bsky.app', 'bsky.social': (url) => 'bsky.social', 'itch.io': (url) => 'itch.io', 'steamcommunity.com': (url) => 'steamcommunity.com', 'steampowered.com': (url) => 'steampowered.com', } function getIconFromUrl(url: URL): string | undefined { const href = url.href; if (href.startsWith('mailto:')) return 'email'; if (href.endsWith('/rss.xml') || href.endsWith('/atom.rss') || href.endsWith('.atom')) return 'rss'; const hostname = url.hostname; const secondLevel = hostname.match(/(([A-Za-z0-9\-])+\.([A-Za-z0-9\-])+)$/)?.at(0) ?? ''; if (specialResolvers[secondLevel]) return specialResolvers[secondLevel](url); return hostname; } export function tryGetIcon(link: string): string { let url: URL; try { url = new URL(link, document.baseURI); } catch { return icons['none']; } return icons[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"; }