Initial Code Commit
140
.gitignore
vendored
@@ -1,138 +1,8 @@
|
|||||||
# ---> Node
|
.svelte-kit/
|
||||||
# Logs
|
|
||||||
logs
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
lerna-debug.log*
|
|
||||||
.pnpm-debug.log*
|
|
||||||
|
|
||||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
|
||||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
|
||||||
|
|
||||||
# Runtime data
|
|
||||||
pids
|
|
||||||
*.pid
|
|
||||||
*.seed
|
|
||||||
*.pid.lock
|
|
||||||
|
|
||||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
|
||||||
lib-cov
|
|
||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
|
||||||
coverage
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# nyc test coverage
|
|
||||||
.nyc_output
|
|
||||||
|
|
||||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
|
||||||
.grunt
|
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
|
||||||
bower_components
|
|
||||||
|
|
||||||
# node-waf configuration
|
|
||||||
.lock-wscript
|
|
||||||
|
|
||||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
|
||||||
build/Release
|
|
||||||
|
|
||||||
# Dependency directories
|
|
||||||
node_modules/
|
node_modules/
|
||||||
jspm_packages/
|
bun.lockb
|
||||||
|
build/
|
||||||
# Snowpack dependency directory (https://snowpack.dev/)
|
|
||||||
web_modules/
|
|
||||||
|
|
||||||
# TypeScript cache
|
|
||||||
*.tsbuildinfo
|
|
||||||
|
|
||||||
# Optional npm cache directory
|
|
||||||
.npm
|
|
||||||
|
|
||||||
# Optional eslint cache
|
|
||||||
.eslintcache
|
|
||||||
|
|
||||||
# Optional stylelint cache
|
|
||||||
.stylelintcache
|
|
||||||
|
|
||||||
# Microbundle cache
|
|
||||||
.rpt2_cache/
|
|
||||||
.rts2_cache_cjs/
|
|
||||||
.rts2_cache_es/
|
|
||||||
.rts2_cache_umd/
|
|
||||||
|
|
||||||
# Optional REPL history
|
|
||||||
.node_repl_history
|
|
||||||
|
|
||||||
# Output of 'npm pack'
|
|
||||||
*.tgz
|
|
||||||
|
|
||||||
# Yarn Integrity file
|
|
||||||
.yarn-integrity
|
|
||||||
|
|
||||||
# dotenv environment variable files
|
|
||||||
.env
|
.env
|
||||||
.env.development.local
|
package-lock.json
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
.env.local
|
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
|
||||||
.cache
|
|
||||||
.parcel-cache
|
|
||||||
|
|
||||||
# Next.js build output
|
|
||||||
.next
|
|
||||||
out
|
|
||||||
|
|
||||||
# Nuxt.js build / generate output
|
|
||||||
.nuxt
|
|
||||||
dist
|
|
||||||
|
|
||||||
# Gatsby files
|
|
||||||
.cache/
|
|
||||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
|
||||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
|
||||||
# public
|
|
||||||
|
|
||||||
# vuepress build output
|
|
||||||
.vuepress/dist
|
|
||||||
|
|
||||||
# vuepress v2.x temp and cache directory
|
|
||||||
.temp
|
|
||||||
.cache
|
|
||||||
|
|
||||||
# vitepress build output
|
|
||||||
**/.vitepress/dist
|
|
||||||
|
|
||||||
# vitepress cache directory
|
|
||||||
**/.vitepress/cache
|
|
||||||
|
|
||||||
# Docusaurus cache and generated files
|
|
||||||
.docusaurus
|
|
||||||
|
|
||||||
# Serverless directories
|
|
||||||
.serverless/
|
|
||||||
|
|
||||||
# FuseBox cache
|
|
||||||
.fusebox/
|
|
||||||
|
|
||||||
# DynamoDB Local files
|
|
||||||
.dynamodb/
|
|
||||||
|
|
||||||
# TernJS port file
|
|
||||||
.tern-port
|
|
||||||
|
|
||||||
# Stores VSCode versions used for testing VSCode extensions
|
|
||||||
.vscode-test
|
|
||||||
|
|
||||||
# yarn v2
|
|
||||||
.yarn/cache
|
|
||||||
.yarn/unplugged
|
|
||||||
.yarn/build-state.yml
|
|
||||||
.yarn/install-state.gz
|
|
||||||
.pnp.*
|
|
||||||
|
|
||||||
|
bun.lock
|
||||||
103
CustomTheme.ts
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
|
||||||
|
import type { CustomThemeConfig } from '@skeletonlabs/tw-plugin';
|
||||||
|
|
||||||
|
export const myCustomTheme: CustomThemeConfig = {
|
||||||
|
name: 'my-custom-theme',
|
||||||
|
properties: {
|
||||||
|
// =~= Theme Properties =~=
|
||||||
|
"--theme-font-family-base": `Montserrat`,
|
||||||
|
"--theme-font-family-heading": `Montserrat`,
|
||||||
|
"--theme-font-color-base": "0 0 0",
|
||||||
|
"--theme-font-color-dark": "255 255 255",
|
||||||
|
"--theme-rounded-base": "4px",
|
||||||
|
"--theme-rounded-container": "8px",
|
||||||
|
"--theme-border-base": "1px",
|
||||||
|
// =~= Theme On-X Colors =~=
|
||||||
|
"--on-primary": "255 255 255",
|
||||||
|
"--on-secondary": "255 255 255",
|
||||||
|
"--on-tertiary": "0 0 0",
|
||||||
|
"--on-success": "0 0 0",
|
||||||
|
"--on-warning": "0 0 0",
|
||||||
|
"--on-error": "255 255 255",
|
||||||
|
"--on-surface": "255 255 255",
|
||||||
|
// =~= Theme Colors =~=
|
||||||
|
// primary | #2b273f
|
||||||
|
"--color-primary-50": "223 223 226", // #dfdfe2
|
||||||
|
"--color-primary-100": "213 212 217", // #d5d4d9
|
||||||
|
"--color-primary-200": "202 201 207", // #cac9cf
|
||||||
|
"--color-primary-300": "170 169 178", // #aaa9b2
|
||||||
|
"--color-primary-400": "107 104 121", // #6b6879
|
||||||
|
"--color-primary-500": "43 39 63", // #2b273f
|
||||||
|
"--color-primary-600": "39 35 57", // #272339
|
||||||
|
"--color-primary-700": "32 29 47", // #201d2f
|
||||||
|
"--color-primary-800": "26 23 38", // #1a1726
|
||||||
|
"--color-primary-900": "21 19 31", // #15131f
|
||||||
|
// secondary | #454545
|
||||||
|
"--color-secondary-50": "227 227 227", // #e3e3e3
|
||||||
|
"--color-secondary-100": "218 218 218", // #dadada
|
||||||
|
"--color-secondary-200": "209 209 209", // #d1d1d1
|
||||||
|
"--color-secondary-300": "181 181 181", // #b5b5b5
|
||||||
|
"--color-secondary-400": "125 125 125", // #7d7d7d
|
||||||
|
"--color-secondary-500": "69 69 69", // #454545
|
||||||
|
"--color-secondary-600": "62 62 62", // #3e3e3e
|
||||||
|
"--color-secondary-700": "52 52 52", // #343434
|
||||||
|
"--color-secondary-800": "41 41 41", // #292929
|
||||||
|
"--color-secondary-900": "34 34 34", // #222222
|
||||||
|
// tertiary | #0EA5E9
|
||||||
|
"--color-tertiary-50": "219 242 252", // #dbf2fc
|
||||||
|
"--color-tertiary-100": "207 237 251", // #cfedfb
|
||||||
|
"--color-tertiary-200": "195 233 250", // #c3e9fa
|
||||||
|
"--color-tertiary-300": "159 219 246", // #9fdbf6
|
||||||
|
"--color-tertiary-400": "86 192 240", // #56c0f0
|
||||||
|
"--color-tertiary-500": "14 165 233", // #0EA5E9
|
||||||
|
"--color-tertiary-600": "13 149 210", // #0d95d2
|
||||||
|
"--color-tertiary-700": "11 124 175", // #0b7caf
|
||||||
|
"--color-tertiary-800": "8 99 140", // #08638c
|
||||||
|
"--color-tertiary-900": "7 81 114", // #075172
|
||||||
|
// success | #00b336
|
||||||
|
"--color-success-50": "217 244 225", // #d9f4e1
|
||||||
|
"--color-success-100": "204 240 215", // #ccf0d7
|
||||||
|
"--color-success-200": "191 236 205", // #bfeccd
|
||||||
|
"--color-success-300": "153 225 175", // #99e1af
|
||||||
|
"--color-success-400": "77 202 114", // #4dca72
|
||||||
|
"--color-success-500": "0 179 54", // #00b336
|
||||||
|
"--color-success-600": "0 161 49", // #00a131
|
||||||
|
"--color-success-700": "0 134 41", // #008629
|
||||||
|
"--color-success-800": "0 107 32", // #006b20
|
||||||
|
"--color-success-900": "0 88 26", // #00581a
|
||||||
|
// warning | #EAB308
|
||||||
|
"--color-warning-50": "252 244 218", // #fcf4da
|
||||||
|
"--color-warning-100": "251 240 206", // #fbf0ce
|
||||||
|
"--color-warning-200": "250 236 193", // #faecc1
|
||||||
|
"--color-warning-300": "247 225 156", // #f7e19c
|
||||||
|
"--color-warning-400": "240 202 82", // #f0ca52
|
||||||
|
"--color-warning-500": "234 179 8", // #EAB308
|
||||||
|
"--color-warning-600": "211 161 7", // #d3a107
|
||||||
|
"--color-warning-700": "176 134 6", // #b08606
|
||||||
|
"--color-warning-800": "140 107 5", // #8c6b05
|
||||||
|
"--color-warning-900": "115 88 4", // #735804
|
||||||
|
// error | #db004d
|
||||||
|
"--color-error-50": "250 217 228", // #fad9e4
|
||||||
|
"--color-error-100": "248 204 219", // #f8ccdb
|
||||||
|
"--color-error-200": "246 191 211", // #f6bfd3
|
||||||
|
"--color-error-300": "241 153 184", // #f199b8
|
||||||
|
"--color-error-400": "230 77 130", // #e64d82
|
||||||
|
"--color-error-500": "219 0 77", // #db004d
|
||||||
|
"--color-error-600": "197 0 69", // #c50045
|
||||||
|
"--color-error-700": "164 0 58", // #a4003a
|
||||||
|
"--color-error-800": "131 0 46", // #83002e
|
||||||
|
"--color-error-900": "107 0 38", // #6b0026
|
||||||
|
// surface | #272835
|
||||||
|
"--color-surface-50": "223 223 225", // #dfdfe1
|
||||||
|
"--color-surface-100": "212 212 215", // #d4d4d7
|
||||||
|
"--color-surface-200": "201 201 205", // #c9c9cd
|
||||||
|
"--color-surface-300": "169 169 174", // #a9a9ae
|
||||||
|
"--color-surface-400": "104 105 114", // #686972
|
||||||
|
"--color-surface-500": "39 40 53", // #272835
|
||||||
|
"--color-surface-600": "35 36 48", // #232430
|
||||||
|
"--color-surface-700": "29 30 40", // #1d1e28
|
||||||
|
"--color-surface-800": "23 24 32", // #171820
|
||||||
|
"--color-surface-900": "19 20 26", // #13141a
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
40
package.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "btsw-api6",
|
||||||
|
"version": "6.2.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"start": "vite build && bun ./server/server.js",
|
||||||
|
"dev": "vite dev --host",
|
||||||
|
"build": "vite build",
|
||||||
|
"server": "bun ./server/server.js"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@skeletonlabs/skeleton": "2.10.2",
|
||||||
|
"@skeletonlabs/tw-plugin": "^0.4.1",
|
||||||
|
"@sveltejs/adapter-auto": "^3.3.1",
|
||||||
|
"@sveltejs/kit": "^2.48.4",
|
||||||
|
"@sveltejs/vite-plugin-svelte": "^3.1.2",
|
||||||
|
"@tailwindcss/forms": "^0.5.10",
|
||||||
|
"@types/node": "22.7.5",
|
||||||
|
"autoprefixer": "10.4.20",
|
||||||
|
"postcss": "8.4.47",
|
||||||
|
"svelte": "^4.2.20",
|
||||||
|
"svelte-check": "^4.3.3",
|
||||||
|
"tailwindcss": "3.4.14",
|
||||||
|
"typescript": "^5.9.3",
|
||||||
|
"vite": "^5.4.21",
|
||||||
|
"vite-plugin-tailwind-purgecss": "0.3.3"
|
||||||
|
},
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"@floating-ui/dom": "^1.7.4",
|
||||||
|
"@iconify/json": "^2.2.403",
|
||||||
|
"@iconify/tailwind": "^1.2.0",
|
||||||
|
"@sveltejs/adapter-node": "^5.4.0",
|
||||||
|
"btsw-api6": "file:",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"dotenv": "^16.6.1",
|
||||||
|
"express": "^4.21.2",
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
6
postcss.config.cjs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
18
server/server.js
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { handler } from '../build/handler.js';
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
import http from 'http';
|
||||||
|
import express from 'express';
|
||||||
|
import cors from 'cors';
|
||||||
|
|
||||||
|
dotenv.config();
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const server = http.Server(app);
|
||||||
|
|
||||||
|
app.use(cors());
|
||||||
|
|
||||||
|
app.use(handler);
|
||||||
|
|
||||||
|
server.listen(process.env.PORT, () => {
|
||||||
|
console.log('listening on port http://localhost:' + process.env.PORT);
|
||||||
|
});
|
||||||
9
src/app.d.ts
vendored
Normal 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
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
65
src/lib/components/BlobPFP.svelte
Normal 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>
|
||||||
49
src/lib/components/EngineerCard.svelte
Normal 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>
|
||||||
11
src/lib/components/Footer.svelte
Normal 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>
|
||||||
100
src/lib/components/HackCard.svelte
Normal 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>
|
||||||
87
src/lib/components/NavBar.svelte
Normal 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
BIN
src/lib/images/logo.png
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
src/lib/images/tgs-start.jpeg
Normal file
|
After Width: | Height: | Size: 127 KiB |
1
src/lib/ts/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
// place files you want to import through the `$lib` alias in this folder.
|
||||||
3
src/routes/+error.svelte
Normal 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
@@ -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
@@ -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>
|
||||||
79
src/routes/hackathons/+page.svelte
Normal 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>
|
||||||
18
src/routes/models/+page.server.ts
Normal 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 };
|
||||||
|
}
|
||||||
55
src/routes/models/+page.svelte
Normal 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>
|
||||||
103
src/routes/portfolio/+page.svelte
Normal 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>
|
||||||
13
src/routes/portfolio/ContactChip.svelte
Normal 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>
|
||||||
8
src/routes/portfolio/LangChip.svelte
Normal 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>
|
||||||
27
src/routes/portfolio/OrgCard.svelte
Normal 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>
|
||||||
25
src/routes/portfolio/ProjectCard.svelte
Normal 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>
|
||||||
5
src/routes/portfolio/RoleChip.svelte
Normal 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>
|
||||||
BIN
static/ChakraPetch-Regular.ttf
Normal file
BIN
static/Froggy_bois_2.gif
Normal file
|
After Width: | Height: | Size: 286 KiB |
BIN
static/blob_nerd.png
Normal file
|
After Width: | Height: | Size: 706 KiB |
BIN
static/favicon.ico
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
static/favicon.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
27
static/favicon.svg
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="200.000000pt" height="200.000000pt" viewBox="0 0 200.000000 200.000000"
|
||||||
|
preserveAspectRatio="xMidYMid meet">
|
||||||
|
|
||||||
|
<g transform="translate(0.000000,200.000000) scale(0.100000,-0.100000)"
|
||||||
|
fill="#000000" stroke="none">
|
||||||
|
<path d="M175 1608 c-3 -7 -6 -231 -7 -498 l-3 -485 -75 -3 c-44 -2 -78 -8
|
||||||
|
-82 -15 -14 -22 -8 -87 11 -126 11 -21 36 -52 56 -69 l36 -32 887 0 887 0 37
|
||||||
|
25 c20 13 45 44 57 68 24 49 28 119 8 135 -7 6 -44 12 -82 14 l-70 3 -5 495
|
||||||
|
-5 495 -823 3 c-653 2 -824 0 -827 -10z m1575 -528 l0 -460 -750 0 -750 0 0
|
||||||
|
460 0 460 750 0 750 0 0 -460z m-943 -560 c24 -18 41 -20 203 -20 163 0 179 2
|
||||||
|
203 20 25 20 38 20 367 18 l341 -3 -23 -35 -24 -35 -862 -3 c-581 -1 -869 1
|
||||||
|
-882 8 -11 6 -27 24 -35 40 l-16 30 352 0 c336 0 352 -1 376 -20z"/>
|
||||||
|
<path d="M1066 1308 c-8 -13 -69 -133 -136 -268 -78 -157 -119 -251 -115 -262
|
||||||
|
8 -20 32 -30 54 -23 9 3 75 122 149 270 110 221 131 269 122 285 -15 27 -56
|
||||||
|
26 -74 -2z"/>
|
||||||
|
<path d="M627 1161 c-53 -54 -97 -105 -97 -112 0 -8 47 -61 104 -118 84 -84
|
||||||
|
107 -102 124 -97 12 4 24 16 28 28 5 16 -9 36 -70 97 -42 42 -76 81 -76 86 0
|
||||||
|
6 34 44 75 85 75 74 86 95 63 118 -27 27 -55 11 -151 -87z"/>
|
||||||
|
<path d="M1187 1253 c-4 -3 -7 -18 -7 -32 0 -18 21 -47 75 -101 l75 -75 -75
|
||||||
|
-75 c-74 -74 -88 -103 -63 -128 7 -7 18 -12 26 -12 24 0 212 191 212 215 0 28
|
||||||
|
-188 215 -216 215 -11 0 -24 -3 -27 -7z"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
BIN
static/models/BakePotato.glb
Normal file
BIN
static/models/Soda.glb
Normal file
BIN
static/tgs-start.jpeg
Normal file
|
After Width: | Height: | Size: 127 KiB |
BIN
static/tgs/game-settings.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
static/tgs/game-start.png
Normal file
|
After Width: | Height: | Size: 760 KiB |
BIN
static/tgs/game.jpg
Normal file
|
After Width: | Height: | Size: 196 KiB |
22
svelte.config.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import adapter from '@sveltejs/adapter-node';
|
||||||
|
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
|
||||||
|
|
||||||
|
/** @type {import('@sveltejs/kit').Config} */
|
||||||
|
const config = {
|
||||||
|
extensions: ['.svelte'],
|
||||||
|
tsconfigFile: "./tsconfig.json",
|
||||||
|
compilerOptions: {
|
||||||
|
enableSourcemap: true,
|
||||||
|
},
|
||||||
|
preprocess: [vitePreprocess({
|
||||||
|
sourceMap: true
|
||||||
|
})],
|
||||||
|
kit: {
|
||||||
|
adapter: adapter()
|
||||||
|
},
|
||||||
|
csrf: {
|
||||||
|
origin: process.env.PUBLIC_HOST,
|
||||||
|
checkOrigin: false,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export default config;
|
||||||
32
tailwind.config.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import { join } from 'path'
|
||||||
|
import type { Config } from 'tailwindcss'
|
||||||
|
import { skeleton } from '@skeletonlabs/tw-plugin'
|
||||||
|
|
||||||
|
import { myCustomTheme } from './CustomTheme';
|
||||||
|
|
||||||
|
import { addDynamicIconSelectors } from '@iconify/tailwind';
|
||||||
|
import forms from '@tailwindcss/forms';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
darkMode: 'selector',
|
||||||
|
content: ['./src/**/*.{html,js,svelte,ts}', join(require.resolve('@skeletonlabs/skeleton'), '../**/*.{html,js,svelte,ts}')],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
forms,
|
||||||
|
skeleton({
|
||||||
|
themes: {
|
||||||
|
custom: [
|
||||||
|
myCustomTheme
|
||||||
|
]
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
addDynamicIconSelectors({
|
||||||
|
prefix: 'icon',
|
||||||
|
scale: 2,
|
||||||
|
iconSets: {},
|
||||||
|
customise: (content, name, prefix) => content
|
||||||
|
})
|
||||||
|
],
|
||||||
|
} satisfies Config;
|
||||||
19
tsconfig.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"extends": "./.svelte-kit/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"strict": true,
|
||||||
|
"moduleResolution": "bundler"
|
||||||
|
}
|
||||||
|
// Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
|
||||||
|
// except $lib which is handled by https://kit.svelte.dev/docs/configuration#files
|
||||||
|
//
|
||||||
|
// If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes
|
||||||
|
// from the referenced tsconfig.json - TypeScript does not merge them in
|
||||||
|
}
|
||||||
7
vite.config.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import { purgeCss } from 'vite-plugin-tailwind-purgecss';
|
||||||
|
import { sveltekit } from '@sveltejs/kit/vite';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
plugins: [sveltekit(), purgeCss()]
|
||||||
|
});
|
||||||