Начальный коммит

This commit is contained in:
Иван Кузьменко 2025-02-28 05:02:25 +03:00
commit 203b2d8403
42 changed files with 5183 additions and 0 deletions

View file

@ -0,0 +1,27 @@
<script lang="ts">
import Icon from '@iconify/svelte';
let className: string = '';
export { className as class };
export let src: string | null = null;
export let text: string;
export let size: number = 32;
let isUrl;
$: isUrl = src?.startsWith('/') || src?.startsWith('http');
</script>
<div class="{className} fill-slate-50 text-sm uppercase transition-all">
{#if src}
{#if isUrl}
<img {src} alt={text} width={size} height={size} />
{:else}
<Icon width={size} height={size} icon={src} color="#f8fafc" />
{/if}
{:else}
{text}
{/if}
</div>
<style>
</style>

View file

@ -0,0 +1,73 @@
<script lang="ts">
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
{href}
class="{className} drop-shadow-2xl flex flex-row transition-all hover:scale-110"
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} />
</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"
>
<slot />
</div>
</a>
<style>
</style>

View file

@ -0,0 +1,70 @@
<script lang="ts">
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 {href} class="{className} inline-block ml-1 mr-1 group" target="_blank">
<span class="inline-block size-8 shrink-0 rounded-xl bg-emerald-800 p-1 align-bottom transition-all group-hover:scale-110">
<HoverIcon
src={customIcon ?? tryGetIcon(href)}
text={host}
size={24}
/>
</span>
<span class="items-center justify-center rounded-r-xl text-emerald-900 underline">
<slot />
</span>
</a>
<style></style>