Initial Code Commit

This commit is contained in:
2025-11-03 19:51:59 +00:00
parent cfd3ccbdbb
commit b84eb2db3d
45 changed files with 1078 additions and 138 deletions

9
src/app.d.ts vendored Normal file
View File

@@ -0,0 +1,9 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
// and what to do when importing types
declare namespace App {
// interface Locals {}
// interface PageData {}
// interface Error {}
// interface Platform {}
}

12
src/app.html Normal file
View File

@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en" class="dark">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover" data-theme="my-custom-theme">
<div style="display: contents" class="h-full overflow-hidden">%sveltekit.body%</div>
</body>
</html>

25
src/app.postcss Normal file
View File

@@ -0,0 +1,25 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind variants;
html,
body {
@apply h-full overflow-hidden;
}
.insta-gradient {
@apply bg-gradient-to-r from-[#f09433] to-[#c90076];
}
.profile-gradient {
@apply bg-gradient-to-r from-[#10d3ff] to-[#008cac];
}
.projects-gradient {
@apply bg-gradient-to-r from-[#ffe299] to-[#ffb700];
}
.btn-no-bordeer {
@apply border-none;
}

View File

@@ -0,0 +1,65 @@
<script lang="ts">
// image source is configurable via prop; default points to a common images folder
export let src: string = '/src/lib/images/profile.png';
export let alt: string = 'Profile picture';
</script>
<figure class="mx-auto">
<section class="img-bg" />
<img src={src} alt={alt} class="fill-token rounded-full object-cover object-center" loading="lazy" />
</figure>
<style lang="postcss">
figure {
@apply flex relative flex-col;
}
figure img,
.img-bg {
@apply w-40 h-40 md:w-44 md:h-44 my-10;
}
.img-bg {
@apply absolute z-[-1] rounded-full blur-[50px] transition-all;
/* default (light mode): darker blue glow */
animation: pulse 5s cubic-bezier(0, 0, 0, 0.5) infinite,
glow-light 5s linear infinite;
}
/* In dark mode use the original multi-color glow */
:global(.dark) .img-bg {
animation: pulse 5s cubic-bezier(0, 0, 0, 0.5) infinite,
glow-dark 5s linear infinite;
}
@keyframes glow-dark {
0% {
@apply bg-primary-400/50;
}
33% {
@apply bg-secondary-400/50;
}
66% {
@apply bg-tertiary-400/50;
}
100% {
@apply bg-primary-400/50;
}
}
@keyframes glow-light {
/* darker blues for light mode */
0% {
@apply bg-primary-700/50;
}
33% {
@apply bg-primary-600/50;
}
66% {
@apply bg-primary-800/50;
}
100% {
@apply bg-primary-700/50;
}
}
@keyframes pulse {
50% {
transform: scale(1.5);
}
}
</style>

View File

@@ -0,0 +1,49 @@
<script lang="ts">
import { Avatar } from "@skeletonlabs/skeleton";
export let totalassets;
export let username;
export let bio;
export let avatar;
export let roles;
export let contributions;
// const popupHover = {
// event: 'hover',
// target: 'popupHover',
// placement: 'top'
// };
</script>
<div class="grid col card bg-initial card-hover overflow-hidden {$$restProps.class}">
<header class="mx-auto my-5">
<div class="relative inline-block">
<span class="badge-icon variant-filled-error absolute -top-0 -right-0 z-10 w-fit p-1">-{Math.round((contributions/totalassets)*100)}%</span>
<Avatar src={avatar} width="w-32" />
</div>
</header>
<div class="p-4 space-y-4">
<h3 class="h3" data-toc-ignore>{username}</h3>
<article>
{ #each roles as role}
<span class="badge variant-ghost-primary my-1 mx-1">{role}</span>
{/each}
<br><br>
<p>{bio}</p>
</article>
</div>
<hr class="opacity-50" />
<footer class="p-4 mx-auto flex justify-start items-center space-x-4">
<button type="button" class="chip variant-soft hover:variant-filled">
<span class="icon-[flowbite--user-circle-solid] profile-gradient"></span>
</button>
<button type="button" class="chip variant-soft hover:variant-filled">
<span class="icon-[flowbite--lightbulb-outline] projects-gradient"></span>
</button>
<button type="button" class="chip variant-soft hover:variant-filled">
<span class="icon-[lets-icons--insta] insta-gradient"></span>
</button>
</footer>
</div>

View File

@@ -0,0 +1,11 @@
<script lang="ts">
import { AppBar } from '@skeletonlabs/skeleton';
</script>
<AppBar class="flex justify-center items-center mx-auto p-4">
<div class="grid grid-cols-1">
<div class="grid mx-auto">
<span class="text-lg">Made with ❤️ by Sir Blob</span>
</div>
</div>
</AppBar>

View File

@@ -0,0 +1,100 @@
<script lang="ts">
export let title: string = "Project Title";
export let description: string =
"Short project description that explains what the project does in one or two lines.";
export let image: string = "/src/lib/images/project.png";
export let link: string = "";
export let repo: string = "";
export let date: string = "";
export let tags: string[] = [];
export let featured: boolean = false;
</script>
<article
class="card bg-surface-300 dark:bg-surface-700 rounded-xl overflow-hidden shadow-lg text-slate-900 dark:text-slate-100 min-h-[220px] flex flex-col"
>
<!-- small image badge in the top-left -->
<div
class="absolute -top-8 left-6 w-20 h-20 rounded-full overflow-hidden ring-4 ring-slate-200/30 bg-white dark:ring-white/5 dark:bg-slate-700"
>
<img
src={image}
alt={title}
class="w-full h-full object-cover"
loading="lazy"
/>
</div>
<div class="p-6 pt-12 flex flex-col flex-1">
<div class="flex items-start justify-between gap-4">
<div class="max-w-[70%]">
<h3 class="text-xl md:text-2xl font-bold leading-tight fit-text-in-div">
{title}
</h3>
{#if date}
<p class="text-xs text-slate-500 dark:text-slate-400 mt-1">{date}</p>
{/if}
</div>
{#if featured}
<span
class="ml-auto inline-flex items-center text-xs font-semibold bg-amber-500 text-amber-900 px-2 py-1 rounded"
>Featured</span
>
{/if}
</div>
<p class="mt-4 text-sm text-slate-700 dark:text-slate-300 flex-grow">{description}</p>
<div class="mt-4 flex items-center justify-between">
<div class="flex flex-wrap gap-2">
{#each tags as tag}
<span class="chip variant-filled text-xs">{tag}</span>
{/each}
</div>
<div class="flex items-center gap-2">
{#if repo}
<a
href={repo}
target="_blank"
rel="noreferrer"
class="btn btn-sm variant-ghost">Repo</a
>
{/if}
{#if link}
<a
href={link}
target="_blank"
rel="noreferrer"
class="btn btn-sm btn-primary">Live</a
>
{/if}
</div>
</div>
</div>
</article>
<style lang="postcss">
article {
@apply w-full;
}
/* note: using project surface tokens (bg-surface-300 / dark:bg-surface-700)
removed the old .bg-card-alt fallback to avoid unused selector warnings */
/* fit text helper (copied from ProjectCard) */
.fit-text-in-div {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
max-width: 14rem;
margin: 0;
}
/* ensure image badge doesn't collapse */
.ring-4 {
box-shadow: 0 0 0 4px rgba(0, 0, 0, 0.08);
}
</style>

View File

@@ -0,0 +1,87 @@
<script lang="ts">
import { AppBar } from '@skeletonlabs/skeleton';
import { LightSwitch } from '@skeletonlabs/skeleton';
let logoElement: HTMLElement;
function onMobileMenuClick() {
const navbar = document.getElementById('navbar-default');
const button = document.querySelector('[data-collapse-toggle="navbar-default"]');
if (navbar) {
const expanded = navbar.getAttribute('aria-expanded') === 'true';
navbar.setAttribute('aria-expanded', String(!expanded));
button?.setAttribute('aria-expanded', String(!expanded));
navbar.style.display = expanded ? 'none' : 'block';
}
}
</script>
<!-- svelte-ignore a11y-missing-attribute -->
<AppBar class="bg-slate-400">
<svelte:fragment slot="lead">
<strong bind:this={logoElement} class="text-xl uppercase">
<a href="/">
<!-- svelte-ignore a11y-missing-attribute -->
<img src="/blob_nerd.png" class="rounded-md" style="width: 50px; height: auto;" alt="Logo" />
</a>
</strong>
</svelte:fragment>
<svelte:fragment slot="trail">
<button on:click={onMobileMenuClick} data-collapse-toggle="navbar-default" type="button" class="inline-flex items-center p-2 w-10 h-10 justify-center text-sm text-gray-500 rounded-lg md:hidden hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-gray-200 dark:text-gray-400 dark:hover:bg-gray-700 dark:focus:ring-gray-600" aria-controls="navbar-default" aria-expanded="false">
<span class="sr-only">Open main menu</span>
<svg class="w-5 h-5" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 17 14">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M1 1h15M1 7h15M1 13h15"/>
</svg>
</button>
<div class="hidden w-full md:block md:w-auto" id="navbar-default">
<ul class="font-medium flex flex-col p-4 md:p-0 mt-4 border md:flex-row md:space-x-6 rtl:space-x-reverse md:mt-0 md:border-0">
<li>
<a
class="btn hover:variant-ghost-surface center-nav"
href="/portfolio"
rel="noreferrer">
<strong>Portfolio</strong>
</a>
</li>
<li>
<a
class="btn hover:variant-ghost-surface center-nav"
href="/hackathons"
rel="noreferrer">
<strong>Hackathons</strong>
</a>
</li>
<!-- <li>
<a
class="btn hover:variant-ghost-surface center-nav"
href="/projects"
rel="noreferrer">
<strong>Projects</strong>
</a>
</li>
<li>
<a
class="btn hover:variant-ghost-surface center-nav"
href="/game"
rel="noreferrer">
<strong>Games</strong>
</a>
</li> -->
<li>
<a class="btn btn-sm">
<LightSwitch class="flex mx-auto items-center"/>
</a>
</li>
</ul>
</div>
</svelte:fragment>
</AppBar>
<style lang="postcss">
.center-nav {
@apply flex justify-center items-center;
}
</style>

0
src/lib/css/style.css Normal file
View File

BIN
src/lib/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

1
src/lib/ts/index.ts Normal file
View File

@@ -0,0 +1 @@
// place files you want to import through the `$lib` alias in this folder.

3
src/routes/+error.svelte Normal file
View File

@@ -0,0 +1,3 @@
<section class="container flex h-full p-8 mx-auto">
<h1 class="text-4xl font-bold h1">404 or 500 or idk :(</h1>
</section>

31
src/routes/+layout.svelte Normal file
View File

@@ -0,0 +1,31 @@
<script lang="ts">
import '../app.postcss';
import { initializeStores, Modal } from '@skeletonlabs/skeleton';
import { AppShell } from '@skeletonlabs/skeleton';
import Footer from '$lib/components/Footer.svelte';
import NavBar from '$lib/components/NavBar.svelte';
initializeStores();
</script>
<svelte:head>
<title>Sir Blob</title>
<link rel="icon" href="https://i.ibb.co/Q6sTVs2/icon.png">
<meta name="description" content="Sir Blob's personal website and portfolio.">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500,700&display=swap" />
</svelte:head>
<Modal />
<AppShell>
<svelte:fragment slot="header">
<NavBar />
</svelte:fragment>
<slot />
<!-- <svelte:fragment slot="footer">
<Footer />
</svelte:fragment> -->
</AppShell>

70
src/routes/+page.svelte Normal file
View File

@@ -0,0 +1,70 @@
<script lang="ts">
import BlobPFP from "$lib/components/BlobPFP.svelte";
</script>
<section class="grid container h-full mx-auto justify-center">
<div class="my-8 grid-cols-1 gap-2 items-center">
<div class="flex items-center">
<BlobPFP src="/blob_nerd.png" alt="Blob PFP" />
</div>
<div class="grid my-4 text-center ">
<h1 class="bts-h1">Sir Blob</h1>
<br>
<p class="h-fit text-2xl typewriter anim-typewriter">Projects, Games, API, and More</p>
</div>
<div class="my-4 text-center flex-col">
<button type="button" class="mx-2 my-2 btn variant-ghost-tertiary">
<a
href="/portfolio"
rel="noreferrer">
Portfolio
</a>
</button>
<!-- <button type="button" class="mx-2 my-2 btn variant-ghost-warning">Projects</button>
<button type="button" class="mx-2 my-2 btn variant-ghost-success">TGS</button> -->
<!-- <button type="button" class="mx-2 my-2 btn variant-ghost-error">Models</button> -->
<button type="button" class="mx-4 my-4 btn variant-ghost-secondary">
<a
href="https://github.com/SirBlobby"
target="_blank"
rel="noreferrer">
<span class="icon-[mdi--github] size-6">.</span>
</a>
</button>
</div>
</div>
</section>
<style lang="postcss">
.bts-h1 {
@apply my-auto text-center;
font-size: 50px;
}
.typewriter {
margin-left: auto;
margin-right: auto;
margin-top: 10px;
margin-bottom: 10px;
width: 50%;
border-right: 3.5px solid rgba(255,255,255,.75);
text-align: center;
white-space: nowrap;
overflow: hidden;
}
.anim-typewriter {
animation: typewriter 3s steps(44) 1s 1 normal both, blinkTextCursor 500ms steps(44) infinite normal;
}
@keyframes typewriter {
from{width: 0;}
to{width: 16em;}
}
@keyframes blinkTextCursor {
from{border-right-color: rgba(230, 118, 14, 0.75);}
to{border-right-color: transparent;}
}
</style>

View File

@@ -0,0 +1,79 @@
<script lang="ts">
import HackCard from "$lib/components/HackCard.svelte";
type Card = {
title: string;
description: string;
image?: string;
link?: string;
repo?: string;
date?: string;
tags?: string[];
featured?: boolean;
};
// Sample data — replace or enhance as you add real entries
const cards: Card[] = [
{
title: "QuickMap — Live Mapping",
description:
"Realtime map-sharing tool built during the 48h MapHack. Streamlined tile sync and offline caching.",
image: "/src/lib/images/project-map.png",
link: "https://example.com/quickmap",
repo: "https://github.com/SirBlobby/quickmap",
date: "Aug 2024",
tags: ["JS", "PWA", "Maps"],
featured: true,
},
{
title: "BlobChat — Minimal Chatbot",
description:
"A tiny chat UI and embeddable bot for community sites. Built with accessibility in mind.",
image: "/src/lib/images/project-chat.png",
repo: "https://github.com/SirBlobby/blobchat",
date: "Nov 2023",
tags: ["Svelte", "Accessibility"],
},
{
title: "GameJam Runner",
description:
"Competition runner for quick prototyping. Handles assets, scoring, and results publishing.",
image: "/src/lib/images/project-game.png",
link: "https://example.com/gamejam-runner",
date: "May 2025",
tags: ["Game", "Tooling"],
},
];
</script>
<section class="container mx-auto py-12 px-4">
<div class="grid p-4 w-full h-fit">
<main>
<div
class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8 items-stretch"
>
{#each cards as c}
<div class="h-full">
<HackCard
title={c.title}
description={c.description}
image={c.image}
link={c.link}
repo={c.repo}
date={c.date}
tags={c.tags}
featured={c.featured}
/>
</div>
{/each}
</div>
</main>
</div>
</section>
<style lang="postcss">
/* page-level tweaks */
.container {
max-width: 1200px;
}
</style>

View File

@@ -0,0 +1,18 @@
import fs from 'fs';
/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
let files = [];
const models = fs.readdirSync(`./static/models`).filter(file => file.endsWith('.glb'));
for(let model of models) {
let obj = {
path: "/models/" + model,
name: model.split('.')[0]
}
files.push(obj);
}
return { files };
}

View File

@@ -0,0 +1,55 @@
<svelte:head>
<script type="module" src="https://unpkg.com/@google/model-viewer/dist/model-viewer.min.js"></script>
</svelte:head>
<script lang="ts">
// @ts-nocheck
import { page } from '$app/stores';
import { onMount } from "svelte";
import { getModalStore } from '@skeletonlabs/skeleton';
const modalStore = getModalStore();
let container, row, modelViewer, modelViewerTitle, modelViewerBtn;
// const modal: ModalSettings = {
// type: 'alert',
// // Data
// title: 'Example Alert',
// body: 'This is an example modal.',
// image: 'https://i.imgur.com/WOgTG96.gif',
// };
// modalStore.trigger(modal);
onMount(() => {
modelViewerTitle = document.querySelector("#model-viewer-bts-title");
for(let i = 0; i < $page.data.files.length; i++) {
console.log($page.data.files[i]);
}
});
function download() {
modelViewerBtn.disabled = true;
modelViewerBtn.innerHTML = "Downloading...";
modelViewer.exportScene("glb").then((blob) => {
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = modelViewerTitle.innerText + ".glb";
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
modelViewerBtn.disabled = false;
modelViewerBtn.innerHTML = "Download";
});
}
</script>
<section class="h-full mx-auto justify-center p-10">
</section>

View File

@@ -0,0 +1,103 @@
<script>
import { Avatar } from "@skeletonlabs/skeleton";
import RoleChips from "./RoleChip.svelte";
import ContactChip from "./ContactChip.svelte";
import LangChip from "./LangChip.svelte";
import ProjectCard from "./ProjectCard.svelte";
import OrgCard from "./OrgCard.svelte";
</script>
<section class="h-full mx-auto justify-center p-5 container">
<div class="grid card p-4 w-full h-fit">
<div class="grid grid-cols-1 md:grid-cols-2 my-2 p-4 h-fit">
<div>
<div class="h-fit inline">
<h1 class="my-4 text-2xl font-bold">Sir Blob</h1>
<div class="my-4 h-fit inline font-bold">
<RoleChips role="College Student" />
<RoleChips role="USA" />
<RoleChips role="Computer Science" />
<RoleChips role="Engineering" />
</div>
<p class="my-4 text-lg">
Hi, I am Sir Blob (aka GamerBoss101) a developer that loves making things.
My passion is using Computer Science with practical Engineering to bring “Forgotten” technology into the future.
Therefore, I do fun coding projects, Game Jams, and Hackathons.
I like to play video games, like Minecraft and Pokémon TCG Live.
</p>
<ContactChip link="https://github.com/GamerBoss101" icon="icon-[mdi--github]" />
<ContactChip link="https://devpost.com/Sir_Blob_" icon="icon-[simple-icons--devpost]" />
<ContactChip link="https://www.linkedin.com/in/gmanjunatha/" icon="icon-[mdi--linkedin]" />
</div>
</div>
<div class="h-fit">
<Avatar class="my-auto mx-auto" width="w-1/2" rounded="rounded-xl" src="https://avatars.githubusercontent.com/u/76974209?v=4" />
</div>
</div>
<div class="grid my-2 h-fit">
<h1 class="text-xl font-bold my-2">Programming Languages</h1>
<div class="inline my-4">
<LangChip icon="icon-[devicon--python]" />
<LangChip icon="icon-[devicon--javascript]" />
<LangChip icon="icon-[devicon--typescript]" />
<LangChip icon="icon-[devicon--c]" />
<LangChip icon="icon-[mdi--language-cpp]" />
<LangChip icon="icon-[devicon--java]" />
<LangChip icon="icon-[devicon--nodejs]" />
</div>
<h1 class="my-2 text-xl font-bold">Applications</h1>
<div class="inline my-4">
<LangChip icon="icon-[simple-icons--windows]" />
<LangChip icon="icon-[simple-icons--linux]" />
<LangChip icon="icon-[simple-icons--apple]" />
<LangChip icon="icon-[devicon--intellij]" />
<LangChip icon="icon-[devicon--vscode]" />
<LangChip icon="icon-[simple-icons--git]" />
<LangChip icon="icon-[logos--blender]"/>
<LangChip icon="icon-[devicon--godot]" />
</div>
<h1 class="my-2 text-xl font-bold">Frameworks</h1>
<div class="inline my-4">
<LangChip icon="icon-[devicon--arduino]" />
<LangChip icon="icon-[devicon--bootstrap]" />
<LangChip icon="icon-[devicon--tailwindcss]" />
<LangChip icon="icon-[devicon--discordjs]" />
<LangChip icon="icon-[devicon--react]" />
<LangChip icon="icon-[devicon--electron]" />
<LangChip icon="icon-[devicon--svelte]" />
<LangChip icon="icon-[devicon--mongodb]" />
</div>
<h1 class="text-xl font-bold my-2">Projects</h1>
<div class="grid grid-cols-1 my-4 lg:grid-cols-4 gap-4">
<ProjectCard
name="PokemonTCGAPI"
icon="https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/1200px-Npm-logo.svg.png"
link="https://www.npmjs.com/package/@bosstop/pokemontcgapi"
/>
<ProjectCard
name="MCSS TS API"
icon="https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/1200px-Npm-logo.svg.png"
link="https://www.npmjs.com/package/@mcserversoft/mcss-api"
/>
<ProjectCard
name="MCP Selenium"
icon="https://upload.wikimedia.org/wikipedia/commons/thumb/d/db/Npm-logo.svg/1200px-Npm-logo.svg.png"
link="https://www.npmjs.com/package/@sirblob/mcp-selenium"
/>
<ProjectCard
name="Pkit"
icon="https://icons.veryicon.com/png/o/business/vscode-program-item-icon/rust-1.png"
link="https://github.com/dead-projects-inc/pkit-cli"
/>
</div>
<!-- <h1 class="text-xl font-bold my-2">Organizations / Servers</h1>
<div class="grid grid-cols-1 my-4 md:grid-cols-4 gap-4">
<OrgCard
name="ASME"
icon="https://acc2022.a2c2.org/wp-content/uploads/sites/45/2021/03/asme-logo-300x178.png"
link=""
/>
</div> -->
</div>
</div>
</section>

View File

@@ -0,0 +1,13 @@
<script lang="ts">
export let link: string;
export let icon: string;
</script>
<span class="mx-2 my-2 w-fit btn variant-filled">
<a
href="{link}"
target="_blank"
rel="noreferrer">
<span class="{icon}">.</span>
</a>
</span>

View File

@@ -0,0 +1,8 @@
<script lang="ts">
export let icon: string;
export let content: string = "";
</script>
<span class="mx-2 my-2 w-fit btn variant-filled text-lg font-bold">
<span class="{icon}">{content}</span>
</span>

View File

@@ -0,0 +1,27 @@
<script lang="ts">
import { Avatar } from "@skeletonlabs/skeleton";
export let name: string;
export let icon: string;
export let link: string;
</script>
<div class="grid grid-cols-1 sm:grid-cols-2 card p-4 bg-card-alt">
<Avatar class="w-fit md:w-24" alt="{name} Icon" src="{icon}" />
<p class="my-auto mx-auto p-2 fit-text-in-div font-bold text-center text-white">
<a href="{link}">{name}</a>
</p>
</div>
<style lang="postcss">
.bg-card-alt {
background-color: #1a202c;
}
.fit-text-in-div {
padding: 0;
font-size: 125%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>

View File

@@ -0,0 +1,25 @@
<script lang="ts">
export let name: string;
export let icon: string;
export let link: string;
</script>
<div class="card bg-card-alt rounded-xl shadow-lg flex items-center gap-4 px-4 py-1 w-full max-w-sm mx-auto">
<img class="w-16 h-16 object-contain rounded-md" alt="{name} Icon" src="{icon}" />
<a class="font-bold text-white fit-text-in-div text-lg md:text-xl" href="{link}">{name}</a>
</div>
<style lang="postcss">
.bg-card-alt {
background-color: #1a202c;
}
.fit-text-in-div {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
max-width: 14rem;
margin: 0;
}
</style>

View File

@@ -0,0 +1,5 @@
<script lang="ts">
export let role: string;
</script>
<span class="font-bold mx-1 my-1 w-fit chip variant-filled">{role}</span>