[READ-ONLY] Mirror of https://github.com/flo-bit/flo-bit.github.io. my personal website, w/ astro, svelte, tailwind, typescript, threlte flo-bit.dev/
portfolio portfolio-website svelte sveltekit tailwind threejs threlte typescript
0

Configure Feed

Select the types of activity you want to include in your feed.

add project pages, add shmup

+911 -201
+73 -2
package-lock.json
··· 12 12 "@melt-ui/svelte": "^0.67.0", 13 13 "@sveltejs/adapter-static": "^3.0.1", 14 14 "@tailwindcss/aspect-ratio": "^0.4.2", 15 + "@tailwindcss/typography": "^0.5.14", 15 16 "@threlte/rapier": "^2.0.1", 16 17 "@threlte/xr": "^0.1.4", 17 18 "alea": "^1.0.1", 18 19 "autoprefixer": "^10.4.16", 20 + "clsx": "^2.1.1", 19 21 "most-visible": "^2.0.0", 20 22 "postcss": "^8.4.32", 21 23 "postprocessing": "^6.33.4", 22 24 "simplex-noise": "^4.0.1", 25 + "tailwind-merge": "^2.5.2", 26 + "tailwind-variants": "^0.2.1", 23 27 "tailwindcss": "^3.4.0", 24 28 "threlte-uikit": "^0.4.2", 25 29 "vite-imagetools": "^6.2.9" ··· 1519 1523 "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" 1520 1524 } 1521 1525 }, 1526 + "node_modules/@tailwindcss/typography": { 1527 + "version": "0.5.14", 1528 + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.14.tgz", 1529 + "integrity": "sha512-ZvOCjUbsJBjL9CxQBn+VEnFpouzuKhxh2dH8xMIWHILL+HfOYtlAkWcyoon8LlzE53d2Yo6YO6pahKKNW3q1YQ==", 1530 + "dependencies": { 1531 + "lodash.castarray": "^4.4.0", 1532 + "lodash.isplainobject": "^4.0.6", 1533 + "lodash.merge": "^4.6.2", 1534 + "postcss-selector-parser": "6.0.10" 1535 + }, 1536 + "peerDependencies": { 1537 + "tailwindcss": ">=3.0.0 || insiders" 1538 + } 1539 + }, 1540 + "node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": { 1541 + "version": "6.0.10", 1542 + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", 1543 + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", 1544 + "dependencies": { 1545 + "cssesc": "^3.0.0", 1546 + "util-deprecate": "^1.0.2" 1547 + }, 1548 + "engines": { 1549 + "node": ">=4" 1550 + } 1551 + }, 1522 1552 "node_modules/@theatre/core": { 1523 1553 "version": "0.7.2", 1524 1554 "resolved": "https://registry.npmjs.org/@theatre/core/-/core-0.7.2.tgz", ··· 2209 2239 }, 2210 2240 "engines": { 2211 2241 "node": ">= 6" 2242 + } 2243 + }, 2244 + "node_modules/clsx": { 2245 + "version": "2.1.1", 2246 + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", 2247 + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", 2248 + "engines": { 2249 + "node": ">=6" 2212 2250 } 2213 2251 }, 2214 2252 "node_modules/code-red": { ··· 3441 3479 "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", 3442 3480 "dev": true 3443 3481 }, 3482 + "node_modules/lodash.castarray": { 3483 + "version": "4.4.0", 3484 + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", 3485 + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==" 3486 + }, 3487 + "node_modules/lodash.isplainobject": { 3488 + "version": "4.0.6", 3489 + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 3490 + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" 3491 + }, 3444 3492 "node_modules/lodash.merge": { 3445 3493 "version": "4.6.2", 3446 3494 "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 3447 - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", 3448 - "dev": true 3495 + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" 3449 3496 }, 3450 3497 "node_modules/lru-cache": { 3451 3498 "version": "10.2.2", ··· 4770 4817 "version": "6.2.0", 4771 4818 "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", 4772 4819 "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==" 4820 + }, 4821 + "node_modules/tailwind-merge": { 4822 + "version": "2.5.2", 4823 + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.2.tgz", 4824 + "integrity": "sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==", 4825 + "funding": { 4826 + "type": "github", 4827 + "url": "https://github.com/sponsors/dcastil" 4828 + } 4829 + }, 4830 + "node_modules/tailwind-variants": { 4831 + "version": "0.2.1", 4832 + "resolved": "https://registry.npmjs.org/tailwind-variants/-/tailwind-variants-0.2.1.tgz", 4833 + "integrity": "sha512-2xmhAf4UIc3PijOUcJPA1LP4AbxhpcHuHM2C26xM0k81r0maAO6uoUSHl3APmvHZcY5cZCY/bYuJdfFa4eGoaw==", 4834 + "dependencies": { 4835 + "tailwind-merge": "^2.2.0" 4836 + }, 4837 + "engines": { 4838 + "node": ">=16.x", 4839 + "pnpm": ">=7.x" 4840 + }, 4841 + "peerDependencies": { 4842 + "tailwindcss": "*" 4843 + } 4773 4844 }, 4774 4845 "node_modules/tailwindcss": { 4775 4846 "version": "3.4.4",
+4
package.json
··· 43 43 "@melt-ui/svelte": "^0.67.0", 44 44 "@sveltejs/adapter-static": "^3.0.1", 45 45 "@tailwindcss/aspect-ratio": "^0.4.2", 46 + "@tailwindcss/typography": "^0.5.14", 46 47 "@threlte/rapier": "^2.0.1", 47 48 "@threlte/xr": "^0.1.4", 48 49 "alea": "^1.0.1", 49 50 "autoprefixer": "^10.4.16", 51 + "clsx": "^2.1.1", 50 52 "most-visible": "^2.0.0", 51 53 "postcss": "^8.4.32", 52 54 "postprocessing": "^6.33.4", 53 55 "simplex-noise": "^4.0.1", 56 + "tailwind-merge": "^2.5.2", 57 + "tailwind-variants": "^0.2.1", 54 58 "tailwindcss": "^3.4.0", 55 59 "threlte-uikit": "^0.4.2", 56 60 "vite-imagetools": "^6.2.9"
+2 -2
src/app.css
··· 2 2 @tailwind components; 3 3 @tailwind utilities; 4 4 5 - @layer base { 5 + /* @layer base { 6 6 html { 7 7 scroll-behavior: smooth; 8 8 } 9 - } 9 + } */ 10 10 11 11 @layer utilities { 12 12 /* Hide scrollbar for Chrome, Safari and Opera */
+12 -42
src/lib/components/About.svelte
··· 13 13 <div class="mx-auto max-w-5xl px-6 lg:px-8"> 14 14 <div id="about" class="py-16 md:py-32 section"> 15 15 <div class="grid grid-cols-1 gap-y-16 lg:grid-cols-2 lg:grid-rows-[auto_1fr] lg:gap-y-12"> 16 - <div class="lg:pl-20"> 16 + <div class="lg:pl-20 w-full flex lg:justify-center"> 17 17 <div class="max-w-sm px-2.5 lg:max-w-none"> 18 18 <!-- <img 19 19 src={imageMe} ··· 44 44 <p> 45 45 I was one of the only kids in my class without a game console, but we had a computer. 46 46 At 12, I got a coding book for Christmas and started making my own games in C and 47 - OpenGL. Though I never finished those early projects, I got hooked on programming. 48 - </p> 49 - <p> 50 - After school, I started studying computer science and became a software developer. I'm 51 - really like the web because it's so accessible — anyone with a device and internet 52 - can access your work instantly. Publishing and sharing your work is also super simple, 53 - whether it's a website, a PWA, or a serverless function. 54 - </p> 55 - <p> 56 - Noawadays, I mostly build a variety of web-based projects and am fascinated by the intersection 57 - of design and development. I love 58 - learning new things and am always seeking new challenges. If you have questions or 59 - just want to connect, feel free to <a 60 - href="#contact" 61 - class="text-cyan-400 hover:text-cyan-300 font-semibold" 62 - > 63 - reach out. 64 - </a> 65 - </p> 66 - <!-- <p> 67 - i was one of the only kids in my class who didn't have some kind of game console at 68 - home. but we did have a computer and when I was 12, i got a coding book for christmas 69 - and decided to try my hand at making my own games (using c and opengl). 70 - </p> 71 - <p> 72 - i never finished any of those games i tried to make then, but I was hooked. i've been 73 - programming ever since and after finishing school, i started studying computer science 74 - and working as a software developer. 47 + OpenGL. Though I never finished any of those early projects, I got hooked on 48 + programming. 75 49 </p> 76 50 <p> 77 - i especially love the web, because it's so accessible. anyone with some kind of 78 - electronic device and an internet connection can access your work in seconds. it's 79 - also very easy to publish and share your work with the world, be it a static website, 80 - a containerized application or a serverless function. 51 + After school, I started studying computer science and became a software developer. I 52 + really like the web because it's so accessible — anyone with a device and internet can 53 + access your work instantly. Publishing and sharing your work is also pretty simple, 54 + whether it's as a website, a PWA, or a serverless function. 81 55 </p> 82 56 <p> 83 - nowadays, I built lots of things for the web, from websites to pwas and hybrid apps. 84 - i'm also interested in the intersection of design and development and how we can use 85 - technology to make the world a better place. 86 - </p> 87 - <p> 88 - i also love to learn new things and I'm always looking for new challenges. if you have 89 - any questions or just want to say hi, feel free to <a 57 + Noawadays, I mostly build a variety of web-based projects. I am fascinated by the 58 + intersection of design and development. I love learning new things and am always 59 + seeking new challenges. If you have questions or just want to connect, feel free to <a 90 60 href="#contact" 91 61 class="text-cyan-400 hover:text-cyan-300 font-semibold" 92 62 > 93 - get in touch 63 + reach out. 94 64 </a> 95 - </p> --> 65 + </p> 96 66 </div> 97 67 </div> 98 68
+5 -7
src/lib/components/Hero.svelte
··· 1 1 <div class="relative isolate overflow-hidden section h-screen pointer-events-none ml-52" id="home"> 2 2 <div class="mx-auto max-w-5xl px-6 py-40 lg:px-8"> 3 - <div class=""> 4 - <h1 5 - class="text-6xl mt-0 md:mt-36 font-bold tracking-tight text-right w-full text-zinc-900 dark:text-zinc-100 md:text-8xl" 6 - > 7 - hello world 8 - </h1> 9 - </div> 3 + <h1 4 + class="text-6xl mt-0 md:mt-36 font-bold tracking-tight text-right w-full text-zinc-900 dark:text-zinc-100 md:text-8xl" 5 + > 6 + hello world 7 + </h1> 10 8 </div> 11 9 </div>
+37
src/lib/components/ProjectBreadcrumb.svelte
··· 1 + <script lang="ts"> 2 + export let name: string; 3 + </script> 4 + 5 + <nav aria-label="Breadcrumb"> 6 + <ol 7 + role="list" 8 + class="mx-auto flex max-w-2xl items-center space-x-2 px-4 sm:px-6 lg:max-w-5xl lg:px-8" 9 + > 10 + <li> 11 + <div class="flex items-center"> 12 + <a 13 + href="/#projects" 14 + class="mr-2 text-sm font-medium text-neutral-900 hover:text-neutral-800 dark:text-neutral-100" 15 + >projects</a 16 + > 17 + <svg 18 + width="16" 19 + height="20" 20 + viewBox="0 0 16 20" 21 + fill="currentColor" 22 + aria-hidden="true" 23 + class="h-5 w-4 text-neutral-300" 24 + > 25 + <path d="M5.697 4.34L8.98 16.532h1.327L7.025 4.341H5.697z" /> 26 + </svg> 27 + </div> 28 + </li> 29 + 30 + <li class="text-sm"> 31 + <div 32 + class="font-medium text-neutral-500 dark:text-neutral-400 " 33 + >{name}</div 34 + > 35 + </li> 36 + </ol> 37 + </nav>
+22
src/lib/components/ProjectButtons.svelte
··· 1 + <script lang="ts"> 2 + export let codeUrl: string | undefined; 3 + export let projectUrl: string | undefined; 4 + </script> 5 + 6 + {#if codeUrl} 7 + <a 8 + href={codeUrl} 9 + target="_blank" 10 + class="flex w-full items-center justify-center rounded-xl bg-white/10 px-8 py-3 text-base font-medium text-white hover:bg-white/20" 11 + >check out the code</a 12 + > 13 + {/if} 14 + 15 + {#if projectUrl} 16 + <a 17 + href={projectUrl} 18 + target="_blank" 19 + class="flex w-full items-center justify-center rounded-xl dark:text-black bg-accent-400 px-8 py-3 text-base font-medium text-white hover:bg-accent-300" 20 + >launch project</a 21 + > 22 + {/if}
+132
src/lib/components/ProjectV1.svelte
··· 1 + <script lang="ts"> 2 + import type { Project } from '../../projects'; 3 + import Badge from './badge/badge.svelte'; 4 + import ProjectBreadcrumb from './ProjectBreadcrumb.svelte'; 5 + import ProjectButtons from './ProjectButtons.svelte'; 6 + 7 + export let project: Project; 8 + </script> 9 + 10 + <div class=""> 11 + <div class="pt-6 sm:pt-24"> 12 + <ProjectBreadcrumb name={project.name} /> 13 + 14 + <!-- Image gallery --> 15 + {#if project.images} 16 + <div 17 + class="mx-auto mt-6 max-w-2xl sm:px-6 lg:grid lg:max-w-5xl lg:grid-cols-3 lg:gap-x-8 lg:px-8" 18 + > 19 + <div class="aspect-h-4 aspect-w-3 hidden overflow-hidden rounded-xl lg:block"> 20 + <img 21 + src={project.images[0]} 22 + alt="Two each of neutral, white, and black shirts laying flat." 23 + class="h-full w-full object-cover object-center" 24 + /> 25 + </div> 26 + <div class="hidden lg:grid lg:grid-cols-1 lg:gap-y-8"> 27 + <div class="aspect-h-2 aspect-w-3 overflow-hidden rounded-xl"> 28 + <img 29 + src={project.images[1]} 30 + alt="Model wearing plain black basic tee." 31 + class="h-full w-full object-cover object-center" 32 + /> 33 + </div> 34 + <div class="aspect-h-2 aspect-w-3 overflow-hidden rounded-xl"> 35 + <img 36 + src={project.images[2]} 37 + alt="Model wearing plain neutral basic tee." 38 + class="h-full w-full object-cover object-center" 39 + /> 40 + </div> 41 + </div> 42 + <div 43 + class="aspect-h-5 aspect-w-4 lg:aspect-h-4 lg:aspect-w-3 sm:overflow-hidden sm:rounded-xl" 44 + > 45 + <img 46 + src={project.images[3]} 47 + alt="Model wearing plain white basic tee." 48 + class="h-full w-full object-cover object-center" 49 + /> 50 + </div> 51 + </div> 52 + {/if} 53 + 54 + <!-- Product info --> 55 + <div 56 + class="mx-auto max-w-2xl px-4 pb-16 pt-10 sm:px-6 lg:grid lg:max-w-5xl lg:grid-cols-3 lg:grid-rows-[auto,auto,1fr] lg:gap-x-8 lg:px-8 lg:pb-24 lg:pt-16" 57 + > 58 + <div class="lg:col-span-2 lg:border-r lg:border-neutral-200 dark:border-neutral-800 lg:pr-8"> 59 + <h1 class="text-2xl font-bold tracking-tight text-neutral-900 dark:text-white sm:text-3xl"> 60 + {project.name} 61 + </h1> 62 + </div> 63 + 64 + <!-- Options --> 65 + <div class="mt-4 lg:row-span-3 lg:mt-0"> 66 + <h2 class="sr-only">project information</h2> 67 + 68 + <div class="mt-10"> 69 + {#if project.tags} 70 + <!-- tags --> 71 + <div class="mt-10"> 72 + <div class="mt-4"> 73 + <div class="flex flex-wrap gap-4"> 74 + {#each project.tags as tag} 75 + <Badge size="lg">{tag}</Badge> 76 + {/each} 77 + </div> 78 + </div> 79 + </div> 80 + {/if} 81 + 82 + <div class="mt-8 flex flex-col gap-4"> 83 + <ProjectButtons codeUrl={project.codeUrl} projectUrl={project.projectUrl} /> 84 + </div> 85 + </div> 86 + </div> 87 + 88 + <div 89 + class="py-10 lg:col-span-2 lg:col-start-1 lg:border-r lg:border-neutral-200 dark:border-neutral-800 lg:pb-16 lg:pr-8 lg:pt-6" 90 + > 91 + <!-- Description and details --> 92 + <div> 93 + <h3 class="sr-only">Description</h3> 94 + 95 + <div class="space-y-6"> 96 + <p class="text-base text-neutral-900 dark:text-neutral-200"> 97 + {project.description} 98 + </p> 99 + </div> 100 + </div> 101 + 102 + {#if project.highlights} 103 + <div class="mt-10"> 104 + <h3 class="text-sm font-medium text-neutral-900 dark:text-neutral-50">highlights</h3> 105 + 106 + <div class="mt-4"> 107 + <ul role="list" class="list-disc space-y-2 pl-4 text-sm"> 108 + {#each project.highlights as highlight} 109 + <li class="text-neutral-400 dark:text-neutral-600"> 110 + <span class="text-neutral-600 dark:text-neutral-300">{highlight}</span> 111 + </li> 112 + {/each} 113 + </ul> 114 + </div> 115 + </div> 116 + {/if} 117 + 118 + {#if project.details} 119 + <div class="mt-10"> 120 + <h2 class="text-sm font-medium text-neutral-900 dark:text-neutral-50">details</h2> 121 + 122 + <div class="mt-4 space-y-6"> 123 + <p class="text-sm text-neutral-600 dark:text-neutral-300"> 124 + {project.details} 125 + </p> 126 + </div> 127 + </div> 128 + {/if} 129 + </div> 130 + </div> 131 + </div> 132 + </div>
+132
src/lib/components/ProjectV2.svelte
··· 1 + <script lang="ts"> 2 + import type { Project } from '../../projects'; 3 + import { Badge } from './badge'; 4 + import ProjectBreadcrumb from './ProjectBreadcrumb.svelte'; 5 + import ProjectButtons from './ProjectButtons.svelte'; 6 + 7 + export let project: Project; 8 + 9 + let selectedImage = 0; 10 + </script> 11 + 12 + <div class=""> 13 + <div class="mx-auto max-w-2xl px-4 py-8 sm:px-6 sm:py-24 lg:max-w-5xl lg:px-8"> 14 + <ProjectBreadcrumb name={project.name} /> 15 + 16 + <div class="mt-6 lg:grid lg:grid-cols-2 lg:items-start lg:gap-x-8"> 17 + <!-- Image gallery --> 18 + {#if project.images} 19 + <div class="flex flex-col-reverse"> 20 + <!-- Image selector --> 21 + 22 + {#if project.images.length > 0} 23 + <div class="mx-auto mt-6 hidden w-full max-w-2xl sm:block lg:max-w-none"> 24 + <div class="grid grid-cols-4 gap-6" aria-orientation="horizontal" role="tablist"> 25 + {#each project.images as image, index} 26 + <button 27 + class="relative flex h-24 cursor-pointer items-center justify-center rounded-md bg-white/10 text-sm font-medium text-neutral-900 hover:bg-neutral-400 border {index == 28 + selectedImage 29 + ? 'border-accent-400' 30 + : 'border-accent-100/20 hover:border-accent-400'}" 31 + type="button" 32 + on:click={() => (selectedImage = index)} 33 + > 34 + <span class="absolute inset-0 overflow-hidden rounded-md"> 35 + <img src={image} alt="" class="h-full w-full object-cover object-center" /> 36 + </span> 37 + <!-- Selected: "ring-indigo-500", Not Selected: "ring-transparent" --> 38 + <span class="pointer-events-none absolute inset-0 rounded-md" aria-hidden="true" 39 + ></span> 40 + </button> 41 + 42 + <!-- More images... --> 43 + {/each} 44 + 45 + <!-- More images... --> 46 + </div> 47 + </div> 48 + {/if} 49 + 50 + <div class="aspect-h-1 aspect-w-1 w-full"> 51 + <!-- Tab panel, show/hide based on tab state. --> 52 + <div id="tabs-1-panel-1" aria-labelledby="tabs-1-tab-1" role="tabpanel" tabindex="0"> 53 + <img 54 + src={project.images[selectedImage]} 55 + alt="Angled front view with bag zipped and handles upright." 56 + class="h-full w-full object-cover object-center sm:rounded-lg" 57 + /> 58 + </div> 59 + 60 + <!-- More images... --> 61 + </div> 62 + </div> 63 + {/if} 64 + 65 + <!-- Product info --> 66 + <div class="mt-10 px-4 sm:mt-16 sm:px-0 lg:mt-0"> 67 + <h1 class="text-3xl font-bold tracking-tight text-neutral-900 dark:text-white"> 68 + {project.name} 69 + </h1> 70 + 71 + {#if project.tags} 72 + <!-- tags --> 73 + <div class="mt-10"> 74 + <div class="mt-4 mb-8"> 75 + <div class="flex flex-wrap gap-4"> 76 + {#each project.tags as tag} 77 + <Badge size="lg">{tag}</Badge> 78 + {/each} 79 + </div> 80 + </div> 81 + 82 + <div class="grid sm:grid-cols-2 gap-4"> 83 + <ProjectButtons codeUrl={project.code} projectUrl={project.projectUrl} /> 84 + </div> 85 + </div> 86 + {/if} 87 + 88 + <div class="mt-6"> 89 + <h3 class="sr-only">Description</h3> 90 + 91 + <div class="space-y-6 text-base text-neutral-700 dark:text-neutral-300"> 92 + <p> 93 + {project.description} 94 + </p> 95 + </div> 96 + </div> 97 + 98 + <section aria-labelledby="details-heading" class="mt-12"> 99 + <h2 id="details-heading" class="sr-only">Additional details</h2> 100 + 101 + {#if project.highlights} 102 + <div 103 + class="divide-y divide-neutral-200 dark:divide-neutral-800 border-t dark:border-neutral-800" 104 + > 105 + <div> 106 + <h3> 107 + <!-- Expand/collapse question button --> 108 + <div class="group relative flex w-full items-center justify-between py-6 text-left"> 109 + <!-- Open: "text-indigo-600", Closed: "text-neutral-900" --> 110 + <span class="text-sm font-medium text-neutral-900 dark:text-neutral-100" 111 + >highlights</span 112 + > 113 + </div> 114 + </h3> 115 + <div class="prose prose-sm pb-6 dark:prose-invert prose-neutral" id="disclosure-1"> 116 + <ul role="list"> 117 + {#each project.highlights as highlight} 118 + <li>{highlight}</li> 119 + {/each} 120 + </ul> 121 + </div> 122 + </div> 123 + 124 + <!-- More sections... --> 125 + </div> 126 + {/if} 127 + 128 + </section> 129 + </div> 130 + </div> 131 + </div> 132 + </div>
+47
src/lib/components/ProjectV3.svelte
··· 1 + <script lang="ts"> 2 + import Project from '$lib/vr/components/Project.svelte'; 3 + import ProjectBreadcrumb from './ProjectBreadcrumb.svelte'; 4 + import ProjectButtons from './ProjectButtons.svelte'; 5 + 6 + export let project: Project; 7 + </script> 8 + 9 + <div class=""> 10 + <div 11 + class="mx-auto max-w-2xl px-4 py-16 sm:px-6 sm:py-24 lg:grid lg:max-w-5xl lg:grid-cols-2 lg:gap-x-8 lg:px-8" 12 + > 13 + <!-- Product details --> 14 + <div class="lg:max-w-lg lg:self-end"> 15 + <ProjectBreadcrumb name={project.name} /> 16 + 17 + <div class="mt-4"> 18 + <h1 class="text-3xl font-bold tracking-tight text-white sm:text-4xl">{project.name}</h1> 19 + </div> 20 + 21 + <section aria-labelledby="information-heading" class="mt-4"> 22 + <h2 id="information-heading" class="sr-only">project information</h2> 23 + 24 + <div class="mt-4 space-y-6"> 25 + <p class="text-base text-neutral-400">{project.description}</p> 26 + </div> 27 + 28 + <div class="mt-8 grid sm:grid-cols-2 gap-4"> 29 + <ProjectButtons codeUrl={project.codeUrl} projectUrl={project.projectUrl} /> 30 + </div> 31 + </section> 32 + </div> 33 + 34 + {#if project.images} 35 + <!-- Product image --> 36 + <div class="mt-10 lg:col-start-2 lg:row-span-2 lg:mt-0 lg:self-center"> 37 + <div class="aspect-h-1 aspect-w-1 overflow-hidden rounded-lg"> 38 + <img 39 + src={project.images[0]} 40 + alt="Model wearing light green backpack with black canvas straps and front zipper pouch." 41 + class="h-full w-full object-cover object-center" 42 + /> 43 + </div> 44 + </div> 45 + {/if} 46 + </div> 47 + </div>
+15 -140
src/lib/components/Projects.svelte
··· 1 1 <script lang="ts"> 2 - import svelteswipecards from '$lib/images/projects-new/svelte-swiper-cards-demo.mp4'; 3 - import fluidtexteffect from '$lib/images/projects-new/text-effect-fluid-demo.mp4'; 4 - import fake3d from '$lib/images/projects-new/fake3dimage-demo.mp4'; 5 - import hyperlumen from '$lib/images/projects-new/hyperlumen-demo.mp4'; 6 - import marblellous from '$lib/images/projects-new/marblellous-demo.mp4'; 7 - import oldcode from '$lib/images/projects-new/old-code-demo.mp4'; 8 - import autostereogramrenderer from '$lib/images/projects-new/autostereogram-renderer-demo.mp4'; 9 - import mandala from '$lib/images/projects-new/mandala-demo.mp4'; 10 - 11 - import threltevrcodeeditor from '$lib/images/projects-new/threlte-vr-code-editor-demo.mp4'; 12 - 13 - let projects: { 14 - src: string; 15 - href?: string; 16 - alt: string; 17 - aspect?: string; 18 - name?: string; 19 - description?: string; 20 - code?: string; 21 - }[] = [ 22 - { 23 - src: svelteswipecards, 24 - alt: 'svelte-swiper-cards', 25 - href: 'https://flo-bit.github.io/svelte-swiper-cards/', 26 - aspect: 'aspect-[9/18]', 27 - name: 'svelte swipable card component', 28 - description: 'a swipeable tinder like card component for svelte.', 29 - code: 'https://github.com/flo-bit/svelte-swiper-cards/' 30 - }, 31 - { 32 - src: fluidtexteffect, 33 - alt: 'Text Fluid Effect', 34 - href: 'https://flo-bit.github.io/text_effect_fluid/', 35 - aspect: 'aspect-[23/9]', 36 - name: 'fluid text effect', 37 - code: 'https://github.com/flo-bit/text_effect_fluid' 38 - }, 39 - { 40 - src: hyperlumen, 41 - alt: 'Hyperlumen', 42 - href: 'https://hyperlumen.de', 43 - aspect: 'aspect-[9/14]', 44 - name: 'hyperlumen', 45 - description: 46 - "light-up clothes that make you feel like you're in a sci-fi movie. perfect for raves." 47 - }, 48 - 49 - { 50 - src: mandala, 51 - alt: 'svg mandala drawer', 52 - href: 'https://flo-bit.github.io/mandala/', 53 - aspect: 'aspect-square', 54 - name: 'svg mandala drawer', 55 - description: 'draw svg mandalas in the browser.' 56 - }, 57 - { 58 - src: fake3d, 59 - alt: 'Image2Fake3D', 60 - href: 'https://flo-bit.github.io/image2fake3d/', 61 - aspect: 'aspect-[9/16]', 62 - name: 'image2fake3d', 63 - description: 64 - 'turns an image into a fake 3d image that you can rotate with your mouse or gyro sensor.', 65 - code: 'https://github.com/flo-bit/image2fake3d' 66 - }, 67 - { 68 - src: marblellous, 69 - alt: 'marblellous', 70 - href: 'https://flo-bit.github.io/ball-game/', 71 - aspect: 'aspect-[9/10]', 72 - name: 'marblellous', 73 - description: 74 - 'simple 3d browser game made with threlte. inspired by the game "marble blast gold".', 75 - code: 'https://github.com/flo-bit/ball-game' 76 - }, 77 - { 78 - src: oldcode, 79 - alt: 'old projects', 80 - href: 'https://flo-bit.github.io/old-code/', 81 - aspect: 'aspect-[16/11]', 82 - name: 'old coding projects', 83 - code: 'https://github.com/flo-bit/old-code' 84 - }, 85 - { 86 - src: threltevrcodeeditor, 87 - alt: 'threlte vr code editor', 88 - href: 'https://github.com/flo-bit/threlte-vr-code-editor', 89 - aspect: 'aspect-[16/11]', 90 - name: 'threlte vr code editor', 91 - description: 'a virtual reality code editor made with threlte.', 92 - code: 'https://github.com/flo-bit/threlte-vr-code-editor' 93 - }, 94 - { 95 - src: autostereogramrenderer, 96 - alt: 'autostereogram renderer', 97 - href: 'https://flo-bit.github.io/autostereogram-renderer/', 98 - aspect: 'aspect-square', 99 - name: 'autostereogram renderer', 100 - description: 'rendering a 3d scene as an autostereogram.' 101 - } 102 - ]; 2 + import { projects } from '../../projects'; 103 3 </script> 104 4 105 5 <div id="projects" class="z-20 py-16 md:py-32 section bg-black relative isolate"> ··· 116 16 </div> 117 17 118 18 <div class="columns-2 md:columns-4 gap-4"> 119 - {#each projects as project, index} 19 + {#each projects as project} 120 20 <div 121 21 class="group relative break-inside-avoid-column {project.aspect ?? 122 22 'aspect-square'} mb-4 w-full flex-none overflow-hidden rounded-xl ring-1 ring-white/10 bg-zinc-100 dark:bg-zinc-800 sm:rounded-2xl" ··· 140 40 loading="lazy" 141 41 /> 142 42 {/if} 143 - {#if project.href} 144 - <div 145 - class="overflow-hidden absolute z-10 pointer-events-none inset-0 w-full h-full flex items-end p-2 md:p-4 tracking-tight leading-6 text-white text-xl font-semibold opacity-80 md:opacity-0 group-hover:opacity-100 transition-opacity duration-200" 146 - > 147 - <div> 148 - {#if project.code && false} 149 - <a 150 - href={project.code} 151 - target="_blank" 152 - class="pointer-events-auto hover:opacity-60 transition-opacity duration-200" 153 - > 154 - <svg fill="currentColor" viewBox="0 0 24 24" aria-hidden="true" class="size-6"> 155 - <path 156 - fill-rule="evenodd" 157 - d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" 158 - clip-rule="evenodd" 159 - /> 160 - </svg> 161 - </a> 162 - {/if} 163 - <div class="mt-1 text-base"> 164 - {project.name} 165 - </div> 166 - 167 - <!-- {#if project.description} 168 - <div class="text-sm font-normal mt-2"> 169 - {project.description} 170 - </div> 171 - {/if} --> 172 - </div> 43 + <div 44 + class="overflow-hidden absolute z-10 pointer-events-none inset-0 w-full h-full flex items-end p-2 md:p-4 tracking-tight leading-6 text-white text-xl font-semibold opacity-80 md:opacity-0 group-hover:opacity-100 transition-opacity duration-200" 45 + > 46 + <div class="mt-1 text-base"> 47 + {project.name} 173 48 </div> 49 + </div> 174 50 175 - <a href={project.href} target="_blank"> 176 - <div class="sr-only">{project.alt}</div> 177 - <div class="absolute inset-0 rounded-xl"></div> 178 - <div 179 - class="absolute inset-0 w-full h-full opacity-60 md:opacity-0 group-hover:opacity-80 transition-opacity duration-200 bg-gradient-to-t from-black to-transparent" 180 - ></div> 181 - </a> 182 - {/if} 51 + <a href={'/projects/' + project.key}> 52 + <div class="sr-only">{project.alt}</div> 53 + <div class="absolute inset-0 rounded-xl"></div> 54 + <div 55 + class="absolute inset-0 w-full h-full opacity-60 md:opacity-0 group-hover:opacity-80 transition-opacity duration-200 bg-gradient-to-t from-black to-transparent" 56 + ></div> 57 + </a> 183 58 </div> 184 59 {/each} 185 60 </div>
+24
src/lib/components/badge/badge.svelte
··· 1 + <script lang="ts"> 2 + import { cn } from '$lib/utils'; 3 + import { badgeVariants, type Size, type Variant } from '.'; 4 + 5 + let className: string | undefined | null = undefined; 6 + export let href: string | undefined = undefined; 7 + export let variant: Variant = 'default'; 8 + export let size: Size = 'default'; 9 + export { className as class }; 10 + </script> 11 + 12 + <svelte:element 13 + this={href ? 'a' : 'span'} 14 + {href} 15 + class={cn(badgeVariants({ size, variant, className }))} 16 + {...$$restProps} 17 + > 18 + {#if variant?.includes('dot')} 19 + <svg class="h-1.5 w-1.5" viewBox="0 0 6 6" aria-hidden="true"> 20 + <circle cx="3" cy="3" r="3" /> 21 + </svg> 22 + {/if} 23 + <slot /> 24 + </svelte:element>
+168
src/lib/components/badge/index.ts
··· 1 + import { tv, type VariantProps } from 'tailwind-variants'; 2 + export { default as Badge } from './badge.svelte'; 3 + 4 + export const badgeVariants = tv({ 5 + base: 'inline-flex items-center gap-x-1.5 px-2 py-1 text-xs font-medium transition-colors select-none ring-inset ring-accent-600/20 dark:ring-accent-500/20', 6 + variants: { 7 + variant: { 8 + default: 9 + 'rounded-md bg-accent-50 dark:bg-accent-500/10 text-accent-700 dark:text-accent-400 ring-1 fill-accent-500 dark:fill-accent-400', 10 + pill: 'bg-accent-50 dark:bg-accent-500/10 text-accent-700 dark:text-accent-400 ring-1 fill-accent-500 dark:fill-accent-400 rounded-full', 11 + dot: 'rounded-md bg-accent-50 dark:bg-accent-500/10 text-accent-700 dark:text-accent-400 ring-1 fill-accent-500 dark:fill-accent-400', 12 + pill_dot: 13 + 'bg-accent-50 dark:bg-accent-500/10 text-accent-700 dark:text-accent-400 ring-1 fill-accent-500 dark:fill-accent-400 rounded-full', 14 + 15 + flat: 'rounded-md bg-accent-100 dark:bg-accent-500/20 text-accent-700 dark:text-accent-400 ring-0 fill-accent-500 dark:fill-accent-400', 16 + flat_dot: 17 + 'rounded-md bg-accent-100 dark:bg-accent-500/20 text-accent-700 dark:text-accent-400 ring-0 fill-accent-500 dark:fill-accent-400', 18 + flat_pill: 19 + 'rounded-full bg-accent-100 dark:bg-accent-500/20 text-accent-700 dark:text-accent-400 ring-0 fill-accent-500 dark:fill-accent-400', 20 + flat_pill_dot: 21 + 'rounded-full bg-accent-100 dark:bg-accent-500/20 text-accent-700 dark:text-accent-400 ring-0 fill-accent-500 dark:fill-accent-400', 22 + 23 + green: 24 + 'rounded-md bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 ring-1 ring-green-600/20 dark:ring-green-500/20', 25 + red: 'rounded-md bg-red-50 dark:bg-red-500/10 text-red-700 dark:text-red-400 ring-1 ring-red-600/20 dark:ring-red-500/20', 26 + blue: 'rounded-md bg-blue-50 dark:bg-blue-500/10 text-blue-700 dark:text-blue-400 ring-1 ring-blue-600/20 dark:ring-blue-500/20', 27 + yellow: 28 + 'rounded-md bg-yellow-50 dark:bg-yellow-500/10 text-yellow-700 dark:text-yellow-400 ring-1 ring-yellow-600/20 dark:ring-yellow-500/20', 29 + orange: 30 + 'rounded-md bg-orange-50 dark:bg-orange-500/10 text-orange-700 dark:text-orange-400 ring-1 ring-orange-600/20 dark:ring-orange-500/20', 31 + purple: 32 + 'rounded-md bg-purple-50 dark:bg-purple-500/10 text-purple-700 dark:text-purple-400 ring-1 ring-purple-600/20 dark:ring-purple-500/20', 33 + pink: 'rounded-md bg-pink-50 dark:bg-pink-500/10 text-pink-700 dark:text-pink-400 ring-1 ring-pink-600/20 dark:ring-pink-500/20', 34 + neutral: 35 + 'rounded-md bg-neutral-50 dark:bg-neutral-500/10 text-neutral-700 dark:text-neutral-400 ring-1 ring-neutral-600/20 dark:ring-neutral-500/20', 36 + 37 + green_pill: 38 + 'rounded-full bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 ring-1 ring-green-600/20 dark:ring-green-500/20', 39 + red_pill: 40 + 'rounded-full bg-red-50 dark:bg-red-500/10 text-red-700 dark:text-red-400 ring-1 ring-red-600/20 dark:ring-red-500/20', 41 + blue_pill: 42 + 'rounded-full bg-blue-50 dark:bg-blue-500/10 text-blue-700 dark:text-blue-400 ring-1 ring-blue-600/20 dark:ring-blue-500/20', 43 + yellow_pill: 44 + 'rounded-full bg-yellow-50 dark:bg-yellow-500/10 text-yellow-700 dark:text-yellow-400 ring-1 ring-yellow-600/20 dark:ring-yellow-500/20', 45 + orange_pill: 46 + 'rounded-full bg-orange-50 dark:bg-orange-500/10 text-orange-700 dark:text-orange-400 ring-1 ring-orange-600/20 dark:ring-orange-500/20', 47 + purple_pill: 48 + 'rounded-full bg-purple-50 dark:bg-purple-500/10 text-purple-700 dark:text-purple-400 ring-1 ring-purple-600/20 dark:ring-purple-500/20', 49 + pink_pill: 50 + 'rounded-full bg-pink-50 dark:bg-pink-500/10 text-pink-700 dark:text-pink-400 ring-1 ring-pink-600/20 dark:ring-pink-500/20', 51 + neutral_pill: 52 + 'rounded-full bg-neutral-50 dark:bg-neutral-500/10 text-neutral-700 dark:text-neutral-400 ring-1 ring-neutral-600/20 dark:ring-neutral-500/20', 53 + 54 + green_pill_dot: 55 + 'rounded-full bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 ring-1 ring-green-600/20 dark:ring-green-500/20 fill-green-500 dark:fill-green-400', 56 + red_pill_dot: 57 + 'rounded-full bg-red-50 dark:bg-red-500/10 text-red-700 dark:text-red-400 ring-1 ring-red-600/20 dark:ring-red-500/20 fill-red-500 dark:fill-red-400', 58 + blue_pill_dot: 59 + 'rounded-full bg-blue-50 dark:bg-blue-500/10 text-blue-700 dark:text-blue-400 ring-1 ring-blue-600/20 dark:ring-blue-500/20 fill-blue-500 dark:fill-blue-400', 60 + yellow_pill_dot: 61 + 'rounded-full bg-yellow-50 dark:bg-yellow-500/10 text-yellow-700 dark:text-yellow-400 ring-1 ring-yellow-600/20 dark:ring-yellow-500/20 fill-yellow-500 dark:fill-yellow-400', 62 + orange_pill_dot: 63 + 'rounded-full bg-orange-50 dark:bg-orange-500/10 text-orange-700 dark:text-orange-400 ring-1 ring-orange-600/20 dark:ring-orange-500/20 fill-orange-500 dark:fill-orange-400', 64 + purple_pill_dot: 65 + 'rounded-full bg-purple-50 dark:bg-purple-500/10 text-purple-700 dark:text-purple-400 ring-1 ring-purple-600/20 dark:ring-purple-500/20 fill-purple-500 dark:fill-purple-400', 66 + pink_pill_dot: 67 + 'rounded-full bg-pink-50 dark:bg-pink-500/10 text-pink-700 dark:text-pink-400 ring-1 ring-pink-600/20 dark:ring-pink-500/20 fill-pink-500 dark:fill-pink-400', 68 + neutral_pill_dot: 69 + 'rounded-full bg-neutral-50 dark:bg-neutral-500/10 text-neutral-700 dark:text-neutral-400 ring-1 ring-neutral-600/20 dark:ring-neutral-500/20 fill-neutral-500 dark:fill-neutral-400', 70 + 71 + green_dot: 72 + 'rounded-md bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 ring-1 ring-green-600/20 dark:ring-green-500/20 fill-green-500 dark:fill-green-400', 73 + red_dot: 74 + 'rounded-md bg-red-50 dark:bg-red-500/10 text-red-700 dark:text-red-400 ring-1 ring-red-600/20 dark:ring-red-500/20 fill-red-500 dark:fill-red-400', 75 + blue_dot: 76 + 'rounded-md bg-blue-50 dark:bg-blue-500/10 text-blue-700 dark:text-blue-400 ring-1 ring-blue-600/20 dark:ring-blue-500/20 fill-blue-500 dark:fill-blue-400', 77 + yellow_dot: 78 + 'rounded-md bg-yellow-50 dark:bg-yellow-500/10 text-yellow-700 dark:text-yellow-400 ring-1 ring-yellow-600/20 dark:ring-yellow-500/20 fill-yellow-500 dark:fill-yellow-400', 79 + orange_dot: 80 + 'rounded-md bg-orange-50 dark:bg-orange-500/10 text-orange-700 dark:text-orange-400 ring-1 ring-orange-600/20 dark:ring-orange-500/20 fill-orange-500 dark:fill-orange-400', 81 + purple_dot: 82 + 'rounded-md bg-purple-50 dark:bg-purple-500/10 text-purple-700 dark:text-purple-400 ring-1 ring-purple-600/20 dark:ring-purple-500/20 fill-purple-500 dark:fill-purple-400', 83 + pink_dot: 84 + 'rounded-md bg-pink-50 dark:bg-pink-500/10 text-pink-700 dark:text-pink-400 ring-1 ring-pink-600/20 dark:ring-pink-500/20 fill-pink-500 dark:fill-pink-400', 85 + neutral_dot: 86 + 'rounded-md bg-neutral-50 dark:bg-neutral-500/10 text-neutral-700 dark:text-neutral-400 ring-1 ring-neutral-600/20 dark:ring-neutral-500/20 fill-neutral-500 dark:fill-neutral-400', 87 + 88 + green_flat: 89 + 'rounded-md bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400 ring-0 ring-green-600/20 dark:ring-green-500/20', 90 + red_flat: 91 + 'rounded-md bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 ring-0 ring-red-600/20 dark:ring-red-500/20', 92 + blue_flat: 93 + 'rounded-md bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 ring-0 ring-blue-600/20 dark:ring-blue-500/20', 94 + yellow_flat: 95 + 'rounded-md bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 ring-0 ring-yellow-600/20 dark:ring-yellow-500/20', 96 + orange_flat: 97 + 'rounded-md bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 ring-0 ring-orange-600/20 dark:ring-orange-500/20', 98 + purple_flat: 99 + 'rounded-md bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400 ring-0 ring-purple-600/20 dark:ring-purple-500/20', 100 + pink_flat: 101 + 'rounded-md bg-pink-100 dark:bg-pink-500/20 text-pink-700 dark:text-pink-400 ring-0 ring-pink-600/20 dark:ring-pink-500/20', 102 + neutral_flat: 103 + 'rounded-md bg-neutral-100 dark:bg-neutral-500/20 text-neutral-700 dark:text-neutral-400 ring-0 ring-neutral-600/20 dark:ring-neutral-500/20', 104 + 105 + green_flat_pill: 106 + 'rounded-full bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400 ring-0 ring-green-600/20 dark:ring-green-500/20', 107 + red_flat_pill: 108 + 'rounded-full bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 ring-0 ring-red-600/20 dark:ring-red-500/20', 109 + blue_flat_pill: 110 + 'rounded-full bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 ring-0 ring-blue-600/20 dark:ring-blue-500/20', 111 + yellow_flat_pill: 112 + 'rounded-full bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 ring-0 ring-yellow-600/20 dark:ring-yellow-500/20', 113 + orange_flat_pill: 114 + 'rounded-full bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 ring-0 ring-orange-600/20 dark:ring-orange-500/20', 115 + purple_flat_pill: 116 + 'rounded-full bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400 ring-0 ring-purple-600/20 dark:ring-purple-500/20', 117 + pink_flat_pill: 118 + 'rounded-full bg-pink-100 dark:bg-pink-500/20 text-pink-700 dark:text-pink-400 ring-0 ring-pink-600/20 dark:ring-pink-500/20', 119 + neutral_flat_pill: 120 + 'rounded-full bg-neutral-100 dark:bg-neutral-500/20 text-neutral-700 dark:text-neutral-400 ring-0 ring-neutral-600/20 dark:ring-neutral-500/20', 121 + 122 + green_flat_dot: 123 + 'rounded-md bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400 ring-0 ring-green-600/20 dark:ring-green-500/20 fill-green-500 dark:fill-green-400', 124 + red_flat_dot: 125 + 'rounded-md bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 ring-0 ring-red-600/20 dark:ring-red-500/20 fill-red-500 dark:fill-red-400', 126 + blue_flat_dot: 127 + 'rounded-md bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 ring-0 ring-blue-600/20 dark:ring-blue-500/20 fill-blue-500 dark:fill-blue-400', 128 + yellow_flat_dot: 129 + 'rounded-md bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 ring-0 ring-yellow-600/20 dark:ring-yellow-500/20 fill-yellow-500 dark:fill-yellow-400', 130 + orange_flat_dot: 131 + 'rounded-md bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 ring-0 ring-orange-600/20 dark:ring-orange-500/20 fill-orange-500 dark:fill-orange-400', 132 + purple_flat_dot: 133 + 'rounded-md bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400 ring-0 ring-purple-600/20 dark:ring-purple-500/20 fill-purple-500 dark:fill-purple-400', 134 + pink_flat_dot: 135 + 'rounded-md bg-pink-100 dark:bg-pink-500/20 text-pink-700 dark:text-pink-400 ring-0 ring-pink-600/20 dark:ring-pink-500/20 fill-pink-500 dark:fill-pink-400', 136 + neutral_flat_dot: 137 + 'rounded-md bg-neutral-100 dark:bg-neutral-500/20 text-neutral-700 dark:text-neutral-400 ring-0 ring-neutral-600/20 dark:ring-neutral-500/20 fill-neutral-500 dark:fill-neutral-400', 138 + 139 + green_flat_pill_dot: 140 + 'rounded-full bg-green-100 dark:bg-green-500/20 text-green-700 dark:text-green-400 ring-0 ring-green-600/20 dark:ring-green-500/20 fill-green-500 dark:fill-green-400', 141 + red_flat_pill_dot: 142 + 'rounded-full bg-red-100 dark:bg-red-500/20 text-red-700 dark:text-red-400 ring-0 ring-red-600/20 dark:ring-red-500/20 fill-red-500 dark:fill-red-400', 143 + blue_flat_pill_dot: 144 + 'rounded-full bg-blue-100 dark:bg-blue-500/20 text-blue-700 dark:text-blue-400 ring-0 ring-blue-600/20 dark:ring-blue-500/20 fill-blue-500 dark:fill-blue-400', 145 + yellow_flat_pill_dot: 146 + 'rounded-full bg-yellow-100 dark:bg-yellow-500/20 text-yellow-700 dark:text-yellow-400 ring-0 ring-yellow-600/20 dark:ring-yellow-500/20 fill-yellow-500 dark:fill-yellow-400', 147 + orange_flat_pill_dot: 148 + 'rounded-full bg-orange-100 dark:bg-orange-500/20 text-orange-700 dark:text-orange-400 ring-0 ring-orange-600/20 dark:ring-orange-500/20 fill-orange-500 dark:fill-orange-400', 149 + purple_flat_pill_dot: 150 + 'rounded-full bg-purple-100 dark:bg-purple-500/20 text-purple-700 dark:text-purple-400 ring-0 ring-purple-600/20 dark:ring-purple-500/20 fill-purple-500 dark:fill-purple-400', 151 + pink_flat_pill_dot: 152 + 'rounded-full bg-pink-100 dark:bg-pink-500/20 text-pink-700 dark:text-pink-400 ring-0 ring-pink-600/20 dark:ring-pink-500/20 fill-pink-500 dark:fill-pink-400', 153 + neutral_flat_pill_dot: 154 + 'rounded-full bg-neutral-100 dark:bg-neutral-500/20 text-neutral-700 dark:text-neutral-400 ring-0 ring-neutral-600/20 dark:ring-neutral-500/20 fill-neutral-500 dark:fill-neutral-400' 155 + }, 156 + size: { 157 + default: 'text-xs px-2 py-1 font-medium', 158 + lg: 'text-base px-4 py-1.5' 159 + } 160 + }, 161 + defaultVariants: { 162 + variant: 'default', 163 + size: 'default' 164 + } 165 + }); 166 + 167 + export type Variant = VariantProps<typeof badgeVariants>['variant']; 168 + export type Size = VariantProps<typeof badgeVariants>['size'];
+5 -5
src/lib/components/nav/DektopNavigation.svelte
··· 13 13 class="flex rounded-full bg-white/90 px-3 text-sm font-medium text-zinc-800 shadow-lg shadow-zinc-800/5 ring-1 ring-zinc-900/5 backdrop-blur dark:bg-white/5 dark:text-zinc-200 dark:ring-white/10" 14 14 > 15 15 <!-- <NavigationItem href="#home" isActive={active == 'home'}>Home</NavigationItem> --> 16 - <NavigationItem href="#about" isActive={active == 'about'}>about</NavigationItem> 17 - <NavigationItem href="#projects" isActive={active == 'projects'}>projects</NavigationItem> 18 - <NavigationItem href="#articles" isActive={active == 'articles'}>articles</NavigationItem> 19 - <NavigationItem href="#learning" isActive={active == 'learning'}>learning</NavigationItem> 20 - <NavigationItem href="#contact" isActive={active == 'contact'}>contact</NavigationItem> 16 + <NavigationItem href="/#about" isActive={active == 'about'}>about</NavigationItem> 17 + <NavigationItem href="/#projects" isActive={active == 'projects'}>projects</NavigationItem> 18 + <NavigationItem href="/#articles" isActive={active == 'articles'}>articles</NavigationItem> 19 + <NavigationItem href="/#learning" isActive={active == 'learning'}>learning</NavigationItem> 20 + <NavigationItem href="/#contact" isActive={active == 'contact'}>contact</NavigationItem> 21 21 </ul> 22 22 </nav>
+1 -1
src/lib/components/nav/MobileNavigationItem.svelte
··· 8 8 9 9 <li> 10 10 <a 11 - href="#{current}" 11 + href="/#{current}" 12 12 class="block py-2 {active == current ? 'dark:text-cyan-400' : ''}" 13 13 on:click={hide} 14 14 >
src/lib/images/projects-new/hyperlumen/1.jpg

This is a binary file and will not be displayed.

src/lib/images/projects-new/hyperlumen/2.jpg

This is a binary file and will not be displayed.

src/lib/images/projects-new/hyperlumen/3.jpg

This is a binary file and will not be displayed.

src/lib/images/projects-new/hyperlumen/4.jpg

This is a binary file and will not be displayed.

src/lib/images/projects-new/shmup/shadow-shmup-demo.mp4

This is a binary file and will not be displayed.

+32
src/lib/utils.ts
··· 1 + /** 2 + * 3 + * Add this to tailwind.config.js 4 + * 5 + import colors from 'tailwindcss/colors'; 6 + 7 + theme: { 8 + extend: { 9 + colors: { 10 + accent: colors.sky 11 + } 12 + } 13 + }, 14 + darkMode: 'class', 15 + plugins: [ 16 + require('@tailwindcss/forms'), 17 + require('@tailwindcss/aspect-ratio'), 18 + require('@tailwindcss/typography') 19 + ] 20 + 21 + * 22 + * install npm packages 23 + * 24 + npm i clsx bits-ui tailwind-variants tailwind-merge @tailwindcss/forms @tailwindcss/aspect-ratio @tailwindcss/typography 25 + */ 26 + 27 + import { type ClassValue, clsx } from 'clsx'; 28 + import { twMerge } from 'tailwind-merge'; 29 + 30 + export function cn(...inputs: ClassValue[]) { 31 + return twMerge(clsx(inputs)); 32 + }
+159
src/projects.ts
··· 1 + import svelteswipecards from '$lib/images/projects-new/svelte-swiper-cards-demo.mp4'; 2 + import fluidtexteffect from '$lib/images/projects-new/text-effect-fluid-demo.mp4'; 3 + import fake3d from '$lib/images/projects-new/fake3dimage-demo.mp4'; 4 + import hyperlumen from '$lib/images/projects-new/hyperlumen-demo.mp4'; 5 + import marblellous from '$lib/images/projects-new/marblellous-demo.mp4'; 6 + import oldcode from '$lib/images/projects-new/old-code-demo.mp4'; 7 + import autostereogramrenderer from '$lib/images/projects-new/autostereogram-renderer-demo.mp4'; 8 + import mandala from '$lib/images/projects-new/mandala-demo.mp4'; 9 + import threltevrcodeeditor from '$lib/images/projects-new/threlte-vr-code-editor-demo.mp4'; 10 + 11 + import svelteswipecards1 from '$lib/images/projects-new/svelte-swiper-cards-image.png'; 12 + 13 + import hyperlumen1 from '$lib/images/projects-new/hyperlumen/1.jpg'; 14 + import hyperlumen2 from '$lib/images/projects-new/hyperlumen/2.jpg'; 15 + import hyperlumen3 from '$lib/images/projects-new/hyperlumen/3.jpg'; 16 + import hyperlumen4 from '$lib/images/projects-new/hyperlumen/4.jpg'; 17 + 18 + import shadowshmup from '$lib/images/projects-new/shmup/shadow-shmup-demo.mp4'; 19 + 20 + export type Project = { 21 + src: string; 22 + key: string; 23 + name: string; 24 + alt: string; 25 + 26 + href?: string; 27 + aspect?: string; 28 + description?: string; 29 + code?: string; 30 + images?: string[]; 31 + highlights?: string[]; 32 + details?: string; 33 + projectPageVersion?: 'v1' | 'v2' | 'v3'; 34 + tags?: string[]; 35 + 36 + projectUrl?: string; 37 + codeUrl?: string; 38 + }; 39 + 40 + export const projects: Project[] = [ 41 + { 42 + src: svelteswipecards, 43 + key: 'svelte-swiper-cards', 44 + alt: 'svelte-swiper-cards', 45 + href: 'https://flo-bit.github.io/svelte-swiper-cards/', 46 + 47 + projectUrl: 'https://flo-bit.github.io/svelte-swiper-cards/', 48 + 49 + aspect: 'aspect-[9/18]', 50 + name: 'swipable card component', 51 + description: 'a swipeable tinder like card component for svelte.', 52 + code: 'https://github.com/flo-bit/svelte-swiper-cards/', 53 + 54 + codeUrl: 'https://github.com/flo-bit/svelte-swiper-cards/', 55 + 56 + projectPageVersion: 'v2', 57 + tags: ['svelte', 'typescript', 'component'], 58 + images: [svelteswipecards1, svelteswipecards1] 59 + }, 60 + { 61 + src: fluidtexteffect, 62 + key: 'text-effect-fluid', 63 + alt: 'Text Fluid Effect', 64 + projectUrl: 'https://flo-bit.github.io/text_effect_fluid/', 65 + aspect: 'aspect-[23/9]', 66 + name: 'fluid text effect', 67 + codeUrl: 'https://github.com/flo-bit/text_effect_fluid' 68 + }, 69 + { 70 + src: shadowshmup, 71 + key: 'shadow-shmup', 72 + codeUrl: 'https://flo-bit.github.io/shadow-shmup/', 73 + alt: 'shadow shmup', 74 + aspect: 'aspect-[13/9]', 75 + name: 'shadow shmup', 76 + description: 'a 2d shoot em up game with cool visuals. made for piratejam 2024', 77 + tags: ['game', '2d', 'pixijs'] 78 + }, 79 + { 80 + src: hyperlumen, 81 + key: 'hyperlumen', 82 + alt: 'Hyperlumen', 83 + 84 + projectUrl: 'https://hyperlumen.de', 85 + 86 + aspect: 'aspect-[9/14]', 87 + name: 'hyperlumen', 88 + description: 89 + "light-up clothes that make you feel like you're in a sci-fi movie. perfect for raves.", 90 + images: [hyperlumen1, hyperlumen2, hyperlumen3, hyperlumen4], 91 + highlights: [ 92 + 'controlled via wifi with your smartphone', 93 + 'all the colors, all the animations', 94 + 'powered by a powerbank', 95 + 'handmade in germany' 96 + ], 97 + projectPageVersion: 'v1', 98 + tags: ['wled', 'wearable', 'leds', 'hardware'] 99 + }, 100 + { 101 + src: mandala, 102 + key: 'svg-mandala', 103 + alt: 'svg mandala drawer', 104 + projectUrl: 'https://flo-bit.github.io/mandala/', 105 + aspect: 'aspect-1', 106 + name: 'svg mandala drawer', 107 + description: 'draw svg mandalas in the browser.' 108 + }, 109 + { 110 + src: fake3d, 111 + key: 'image2fake3d', 112 + alt: 'Image2Fake3D', 113 + projectUrl: 'https://flo-bit.github.io/image2fake3d/', 114 + aspect: 'aspect-[9/16]', 115 + name: 'image2fake3d', 116 + description: 117 + 'turns an image into a fake 3d image that you can rotate with your mouse or gyro sensor.', 118 + codeUrl: 'https://github.com/flo-bit/image2fake3d' 119 + }, 120 + { 121 + src: marblellous, 122 + key: 'marblellous', 123 + alt: 'marblellous', 124 + projectUrl: 'https://flo-bit.github.io/ball-game/', 125 + aspect: 'aspect-[9/10]', 126 + name: 'marblellous', 127 + description: 128 + 'simple 3d browser game made with threlte. inspired by the game "marble blast gold".', 129 + codeUrl: 'https://github.com/flo-bit/ball-game' 130 + }, 131 + { 132 + src: oldcode, 133 + key: 'old-code', 134 + alt: 'old projects', 135 + projectUrl: 'https://flo-bit.github.io/old-code/', 136 + aspect: 'aspect-[16/11]', 137 + name: 'old coding projects', 138 + code: 'https://github.com/flo-bit/old-code' 139 + }, 140 + { 141 + src: threltevrcodeeditor, 142 + key: 'threlte-vr-code-editor', 143 + alt: 'threlte vr code editor', 144 + projectUrl: 'https://github.com/flo-bit/threlte-vr-code-editor', 145 + aspect: 'aspect-[16/11]', 146 + name: 'threlte vr code editor', 147 + description: 'a virtual reality code editor made with threlte.', 148 + code: 'https://github.com/flo-bit/threlte-vr-code-editor' 149 + }, 150 + { 151 + src: autostereogramrenderer, 152 + key: 'autostereogram-renderer', 153 + alt: 'autostereogram renderer', 154 + projectUrl: 'https://flo-bit.github.io/autostereogram-renderer/', 155 + aspect: 'aspect-1', 156 + name: 'autostereogram renderer', 157 + description: 'rendering a 3d scene as an autostereogram.' 158 + } 159 + ];
+21
src/routes/projects/[key]/+page.svelte
··· 1 + <script lang="ts"> 2 + import Navbar from '$lib/components/nav/Navbar.svelte'; 3 + import ProjectV1 from '$lib/components/ProjectV1.svelte'; 4 + import ProjectV2 from '$lib/components/ProjectV2.svelte'; 5 + import ProjectV3 from '$lib/components/ProjectV3.svelte'; 6 + import type { PageData } from './$types'; 7 + 8 + export let data: PageData; 9 + </script> 10 + 11 + <Navbar active="projects" /> 12 + 13 + {#if data.project} 14 + {#if data.project.projectPageVersion === 'v2'} 15 + <ProjectV2 project={data.project} /> 16 + {:else if data.project.projectPageVersion === 'v3'} 17 + <ProjectV3 project={data.project} /> 18 + {:else} 19 + <ProjectV1 project={data.project} /> 20 + {/if} 21 + {/if}
+9
src/routes/projects/[key]/+page.ts
··· 1 + import { projects } from '../../../projects.js'; 2 + 3 + export const load = ({ params }) => { 4 + const project = projects.find((project) => project.key === params.key); 5 + 6 + return { 7 + project 8 + }; 9 + };
+11 -2
tailwind.config.js
··· 1 + import colors from 'tailwindcss/colors'; 2 + 1 3 /** @type {import('tailwindcss').Config} */ 2 4 export default { 3 5 content: ['./src/**/*.{html,js,svelte,ts}'], 4 6 theme: { 5 - extend: {} 7 + extend: { 8 + colors: { 9 + accent: colors.cyan 10 + }, 11 + gridTemplateRows: { 12 + '[auto,auto,1fr]': 'auto auto 1fr' 13 + } 14 + } 6 15 }, 7 - plugins: [require('@tailwindcss/aspect-ratio')], 16 + plugins: [require('@tailwindcss/aspect-ratio'), require('@tailwindcss/typography')], 8 17 darkMode: 'class' 9 18 };