feat: Created base set of components
This commit is contained in:
		
							
								
								
									
										23
									
								
								src/components/Cards/Card.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/components/Cards/Card.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
    // Allows additional styling to be applied to the Card component's outer wrapping
 | 
			
		||||
    export let containerStyle: string = "";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class={containerStyle}>
 | 
			
		||||
    <div class="bg-slate-100/10 dark:bg-slate-100/10 rounded-2xl shadow-2xl p-6 flex flex-col h-full w-full">
 | 
			
		||||
        <div class="text-red-400 font-bold flex flex-row justify-between items-center mb-4">
 | 
			
		||||
            <slot name="headerLeft" class="text-2xl md:text-3xl truncate"></slot>
 | 
			
		||||
            <slot name="headerRight" class="max-md:hidden text-xl md:text-2xl truncate"></slot>
 | 
			
		||||
        </div>
 | 
			
		||||
        <hr class="border-1" />
 | 
			
		||||
        <div class="flex-1 flex flex-col justify-center mt-4 mb-8">
 | 
			
		||||
            <slot name="content"/>
 | 
			
		||||
        </div>
 | 
			
		||||
        
 | 
			
		||||
        <hr class="border-1" />
 | 
			
		||||
        <div class="flex flex-row justify-between items-center mt-4 text-base opacity-90">
 | 
			
		||||
            <slot name="footerLeft"/>
 | 
			
		||||
            <slot name="footerRight"/>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										33
									
								
								src/components/Collapsible.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/components/Collapsible.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
    export let open = false;
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="w-full">
 | 
			
		||||
    <button
 | 
			
		||||
        type="button"
 | 
			
		||||
        class="flex items-center justify-between w-full px-2 py-2 text-left rounded hover:font-bold transition group"
 | 
			
		||||
        on:click={() => open = !open}
 | 
			
		||||
        aria-expanded={open}
 | 
			
		||||
    >
 | 
			
		||||
        <span><slot name="label"/></span>
 | 
			
		||||
        <svg
 | 
			
		||||
            class="w-5 h-5 ml-2 transition-transform duration-200"
 | 
			
		||||
            style="transform: rotate({open ? 90 : 0}deg)"
 | 
			
		||||
            fill="none"
 | 
			
		||||
            stroke="currentColor"
 | 
			
		||||
            stroke-width="2"
 | 
			
		||||
            viewBox="0 0 24 24"
 | 
			
		||||
        >
 | 
			
		||||
            <path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7" />
 | 
			
		||||
        </svg>
 | 
			
		||||
    </button>
 | 
			
		||||
    <div
 | 
			
		||||
        class="overflow-hidden transition-all duration-300"
 | 
			
		||||
        style="max-height: {open ? '1000px' : '0'}"
 | 
			
		||||
        aria-hidden={!open}
 | 
			
		||||
    >
 | 
			
		||||
        <div class="pt-2">
 | 
			
		||||
            <slot name="content"/>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										91
									
								
								src/components/Gallery.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								src/components/Gallery.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
    import { spring } from 'svelte/motion';
 | 
			
		||||
    import { onMount } from 'svelte';
 | 
			
		||||
 | 
			
		||||
    export let items: any[] = []; // Array of components/items to display
 | 
			
		||||
    
 | 
			
		||||
    let container: HTMLElement;
 | 
			
		||||
    let isDragging = false;
 | 
			
		||||
    let startX: number;
 | 
			
		||||
    let scrollLeft: number;
 | 
			
		||||
    
 | 
			
		||||
    const centerOffset = spring(0);
 | 
			
		||||
    
 | 
			
		||||
    function handleMouseDown(e: MouseEvent) {
 | 
			
		||||
        isDragging = true;
 | 
			
		||||
        startX = e.pageX - container.offsetLeft;
 | 
			
		||||
        scrollLeft = container.scrollLeft;
 | 
			
		||||
        container.style.cursor = 'grabbing';
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    function handleMouseMove(e: MouseEvent) {
 | 
			
		||||
        if (!isDragging) return;
 | 
			
		||||
        e.preventDefault();
 | 
			
		||||
        const x = e.pageX - container.offsetLeft;
 | 
			
		||||
        const walk = (x - startX) * 2;
 | 
			
		||||
        container.scrollLeft = scrollLeft - walk;
 | 
			
		||||
        updateItemScales();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    function handleMouseUp() {
 | 
			
		||||
        isDragging = false;
 | 
			
		||||
        container.style.cursor = 'grab';
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    function updateItemScales() {
 | 
			
		||||
        const containerCenter = container.offsetWidth / 2;
 | 
			
		||||
        $centerOffset = container.scrollLeft + containerCenter;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    onMount(() => {
 | 
			
		||||
        container.addEventListener('scroll', updateItemScales);
 | 
			
		||||
        return () => container.removeEventListener('scroll', updateItemScales);
 | 
			
		||||
    });
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="gallery-container"
 | 
			
		||||
    bind:this={container}
 | 
			
		||||
    on:mousedown={handleMouseDown}
 | 
			
		||||
    on:mousemove={handleMouseMove}
 | 
			
		||||
    on:mouseup={handleMouseUp}
 | 
			
		||||
    on:mouseleave={handleMouseUp}>
 | 
			
		||||
    
 | 
			
		||||
    {#each items as item, i}
 | 
			
		||||
        <div class="gallery-item"
 | 
			
		||||
            style="
 | 
			
		||||
                --scale: {Math.max(0.6, 1 - Math.abs($centerOffset - (i * 300 + 150)) / 1000)};
 | 
			
		||||
                --opacity: {Math.max(0.3, 1 - Math.abs($centerOffset - (i * 300 + 150)) / 1000)};
 | 
			
		||||
            ">
 | 
			
		||||
            <svelte:component this={item} />
 | 
			
		||||
        </div>
 | 
			
		||||
    {/each}
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
    .gallery-container {
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        overflow-x: scroll;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        gap: 1rem;
 | 
			
		||||
        padding: 2rem;
 | 
			
		||||
        cursor: grab;
 | 
			
		||||
        scrollbar-width: none;
 | 
			
		||||
        -ms-overflow-style: none;
 | 
			
		||||
        scroll-behavior: smooth;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .gallery-container::-webkit-scrollbar {
 | 
			
		||||
        display: none;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .gallery-item {
 | 
			
		||||
        min-width: 300px;
 | 
			
		||||
        height: 400px;
 | 
			
		||||
        transform: scale(var(--scale, 1));
 | 
			
		||||
        opacity: var(--opacity, 1);
 | 
			
		||||
        transition: transform 0.3s ease, opacity 0.3s ease;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        align-items: center;
 | 
			
		||||
        justify-content: center;
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										7
									
								
								src/components/GridGallery.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/components/GridGallery.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<!-- GridGallery.svelte -->
 | 
			
		||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 w-full">
 | 
			
		||||
    <slot />
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										73
									
								
								src/components/Loading.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/components/Loading.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,73 @@
 | 
			
		||||
<style>
 | 
			
		||||
    .loader {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        top: calc(50% - 32px);
 | 
			
		||||
        left: calc(50% - 32px);
 | 
			
		||||
        width: 64px;
 | 
			
		||||
        height: 64px;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
        perspective: 800px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .inner {
 | 
			
		||||
        position: absolute;
 | 
			
		||||
        box-sizing: border-box;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        height: 100%;
 | 
			
		||||
        border-radius: 50%;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .inner.one {
 | 
			
		||||
        left: 0%;
 | 
			
		||||
        top: 0%;
 | 
			
		||||
        animation: rotate-one 1s linear infinite;
 | 
			
		||||
        border-bottom: 3px solid gray;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .inner.two {
 | 
			
		||||
        right: 0%;
 | 
			
		||||
        top: 0%;
 | 
			
		||||
        animation: rotate-two 1s linear infinite;
 | 
			
		||||
        border-right: 3px solid gray;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .inner.three {
 | 
			
		||||
        right: 0%;
 | 
			
		||||
        bottom: 0%;
 | 
			
		||||
        animation: rotate-three 1s linear infinite;
 | 
			
		||||
        border-top: 3px solid gray;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @keyframes rotate-one {
 | 
			
		||||
        0% {
 | 
			
		||||
            transform: rotateX(35deg) rotateY(-45deg) rotateZ(0deg);
 | 
			
		||||
        }
 | 
			
		||||
        100% {
 | 
			
		||||
            transform: rotateX(35deg) rotateY(-45deg) rotateZ(360deg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @keyframes rotate-two {
 | 
			
		||||
        0% {
 | 
			
		||||
            transform: rotateX(50deg) rotateY(10deg) rotateZ(0deg);
 | 
			
		||||
        }
 | 
			
		||||
        100% {
 | 
			
		||||
            transform: rotateX(50deg) rotateY(10deg) rotateZ(360deg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @keyframes rotate-three {
 | 
			
		||||
        0% {
 | 
			
		||||
            transform: rotateX(35deg) rotateY(55deg) rotateZ(0deg);
 | 
			
		||||
        }
 | 
			
		||||
        100% {
 | 
			
		||||
            transform: rotateX(35deg) rotateY(55deg) rotateZ(360deg);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<div class="loader">
 | 
			
		||||
    <div class="inner one"></div>
 | 
			
		||||
    <div class="inner two"></div>
 | 
			
		||||
    <div class="inner three"></div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										9
									
								
								src/components/PageIcon.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/components/PageIcon.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
<script>
 | 
			
		||||
  export let iconClass = 'devicon-htmx-plain';
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<span
 | 
			
		||||
  class="fixed lg:top-4 bottom-4 left-4 text-5xl z-[1000] text-grey"
 | 
			
		||||
>
 | 
			
		||||
  <i class={iconClass}></i>
 | 
			
		||||
</span>
 | 
			
		||||
							
								
								
									
										26
									
								
								src/components/Section.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/components/Section.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
    export let label: string = "";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div id={label} class="relative flex flex-row w-full min-h-[300px] mt-5 mb-25">
 | 
			
		||||
    <!-- Sticky/Sliding Label -->
 | 
			
		||||
    <div class="hidden md:flex flex-col items-center mr-6">
 | 
			
		||||
        <div class="sticky top-24 left-0 z-10">
 | 
			
		||||
            <span class="text-2xl font-bold text-blue-400 tracking-widest"
 | 
			
		||||
                  style="writing-mode: vertical-rl; text-orientation: mixed;">
 | 
			
		||||
                {label}
 | 
			
		||||
            </span>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
    <!-- Main Content -->
 | 
			
		||||
    <div class="flex-1 flex flex-col">
 | 
			
		||||
        <!-- Label for mobile -->
 | 
			
		||||
        <div class="md:hidden mb-2">
 | 
			
		||||
            <span class="text-2xl font-bold text-blue-400">{label}</span>
 | 
			
		||||
        </div>
 | 
			
		||||
        <hr class="border-blue-400 mb-6" />
 | 
			
		||||
        <div>
 | 
			
		||||
            <slot />
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										17
									
								
								src/components/SkillProgress.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/components/SkillProgress.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
    export let value: number = 0; // 0 to 100
 | 
			
		||||
    export let skillColour: string = 'bg-orange-400'; // Default color
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="w-full mt-3">
 | 
			
		||||
    <div class="flex justify-between mb-1">
 | 
			
		||||
        <span class="text-sm font-medium">Competency Level</span>
 | 
			
		||||
        <span class="text-sm font-medium">{value}%</span>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="w-full bg-gray-800 rounded-full h-5">
 | 
			
		||||
        <div
 | 
			
		||||
            class="{skillColour} h-5 rounded-full transition-all duration-500"
 | 
			
		||||
            style="width: {value}%"
 | 
			
		||||
        ></div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										29
									
								
								src/components/Timeline.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/components/Timeline.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
    import Collapsible from "./Collapsible.svelte";
 | 
			
		||||
 | 
			
		||||
    export let timelineData: Array<{
 | 
			
		||||
        title: string;
 | 
			
		||||
        description: string;
 | 
			
		||||
        duration: string;
 | 
			
		||||
    }>;
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="flex flex-col items-center justify-center">
 | 
			
		||||
  <div class="max-w-4xl w-full">
 | 
			
		||||
    {#each timelineData as entry, i}
 | 
			
		||||
      <div class="relative border-l border-gray-700 pl-8 pb-12">
 | 
			
		||||
        {#if i == 0}
 | 
			
		||||
          <div class="absolute top-0 left-[8px] text-green-400 w-4 h-4">♦</div>
 | 
			
		||||
        {:else}
 | 
			
		||||
          <div class="absolute top-0 left-[8px] text-green-400 w-4 h-4">⋄</div>
 | 
			
		||||
        {/if}
 | 
			
		||||
        <p class="text-sm opacity-70">{entry.duration}</p>
 | 
			
		||||
 | 
			
		||||
        <Collapsible open={i==0}>
 | 
			
		||||
          <span slot="label" class="text-2lg font-semibold text-red-400 mt-1 focus:outline-none hover:underline transition">{entry.title}</span>
 | 
			
		||||
          <span slot="content">{@html entry.description}</span>
 | 
			
		||||
        </Collapsible>
 | 
			
		||||
      </div>
 | 
			
		||||
    {/each}
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										9
									
								
								src/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/index.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
			
		||||
export { default as Timeline } from './components/Timeline.svelte';
 | 
			
		||||
export { default as SkillProgress } from './components/SkillProgress.svelte';
 | 
			
		||||
export { default as Section } from './components/Section.svelte';
 | 
			
		||||
export { default as PageIcon } from './components/PageIcon.svelte';
 | 
			
		||||
export { default as Loading } from './components/Loading.svelte';
 | 
			
		||||
export { default as GridGallery } from './components/GridGallery.svelte';
 | 
			
		||||
export { default as Gallery } from './components/Gallery.svelte';
 | 
			
		||||
export { default as Collapsible } from './components/Collapsible.svelte';
 | 
			
		||||
export { default as Card } from './components/Cards/Card.svelte';
 | 
			
		||||
		Reference in New Issue
	
	Block a user