chore/tailwind-conversion #32
@@ -1,28 +1,26 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
    import { createEventDispatcher } from 'svelte';
 | 
			
		||||
 | 
			
		||||
    const dispatch = createEventDispatcher();
 | 
			
		||||
 | 
			
		||||
    function onClick() {
 | 
			
		||||
        dispatch('click');
 | 
			
		||||
    }
 | 
			
		||||
    export let headerLeft: string = "";
 | 
			
		||||
    export let headerRight: string = "";
 | 
			
		||||
    export let headerColour: string = "text-red-500";
 | 
			
		||||
    export let footer: string = "";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
 | 
			
		||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
 | 
			
		||||
<div
 | 
			
		||||
    class="flex flex-col justify-between p-6 bg-secondary rounded-lg shadow-lg transition-all duration-200 hover:shadow-xl hover:scale-[1.02] snap-start"
 | 
			
		||||
    on:click={onClick}
 | 
			
		||||
>
 | 
			
		||||
    <div class="card-header flex items-center justify-between w-full mb-0">
 | 
			
		||||
        <slot name="header"></slot>
 | 
			
		||||
<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="{headerColour} flex flex-row justify-between items-center mb-4">
 | 
			
		||||
        <p class="text-2xl md:text-3xl font-bold truncate">{headerLeft}</p>
 | 
			
		||||
        
 | 
			
		||||
        {#if headerRight}
 | 
			
		||||
            <p class="max-md:hidden text-xl md:text-2xl truncate">{@html headerRight}</p>
 | 
			
		||||
        {/if}
 | 
			
		||||
    </div>
 | 
			
		||||
    <hr />
 | 
			
		||||
    <div class="card-content flex items-center justify-center w-full max-w-full">
 | 
			
		||||
        <slot name="content"></slot>
 | 
			
		||||
    <hr class="mb-4 border-1" />
 | 
			
		||||
    <div class="flex-1 flex flex-col justify-center p-5">
 | 
			
		||||
        <slot />
 | 
			
		||||
    </div>
 | 
			
		||||
    <hr class="not-required" />
 | 
			
		||||
    <div class="card-footer flex gap-4 w-full max-w-full justify-between mb-4">
 | 
			
		||||
        <slot name="footer"></slot>
 | 
			
		||||
    {#if footer}
 | 
			
		||||
        <hr class="my-4 border-1" />
 | 
			
		||||
        <div class="mt-2 text-base opacity-90">
 | 
			
		||||
            {@html footer}
 | 
			
		||||
        </div>
 | 
			
		||||
    {/if}
 | 
			
		||||
</div>
 | 
			
		||||
							
								
								
									
										26
									
								
								src/lib/components/Section.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								src/lib/components/Section.svelte
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
    export let label: string = "";
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<div class="relative flex flex-row w-full min-h-[300px] mt-5 mb-5">
 | 
			
		||||
    <!-- 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>
 | 
			
		||||
@@ -1,38 +1,7 @@
 | 
			
		||||
import { ToastType, type Toast } from "$lib/toast";
 | 
			
		||||
import { writable, type Writable } from "svelte/store";
 | 
			
		||||
import { writable } from "svelte/store";
 | 
			
		||||
import type { GitRepo } from "./types";
 | 
			
		||||
import { fetchRepos } from "./api/git";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Toast Stores
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
export const toasts: Writable<Toast[]> = writable([]);
 | 
			
		||||
 | 
			
		||||
export const addToast = (toast: Toast) => {
 | 
			
		||||
  // Create a unique ID so we can easily find/remove it
 | 
			
		||||
  // if it is dismissible/has a timeout.
 | 
			
		||||
  toast.id = Math.floor(Math.random() * 10000);
 | 
			
		||||
 | 
			
		||||
  // Setup some sensible defaults for a toast.
 | 
			
		||||
  const defaults = {
 | 
			
		||||
    id: toast.id,
 | 
			
		||||
    type: ToastType.Info,
 | 
			
		||||
    dismissible: true,
 | 
			
		||||
    timeout: 3000,
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  // Push the toast to the top of the list of toasts
 | 
			
		||||
  toasts.update((all) => [{ ...defaults, ...toast }, ...all]);
 | 
			
		||||
 | 
			
		||||
  // If toast is dismissible, dismiss it after "timeout" amount of time.
 | 
			
		||||
  if (toast.timeout) setTimeout(() => dismissToast(toast.id), toast.timeout);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const dismissToast = (id: number) => {
 | 
			
		||||
  toasts.update((all) => all.filter((t) => t.id !== id));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
// Git Repo Stores
 | 
			
		||||
////////////////////////////////////////
 | 
			
		||||
 
 | 
			
		||||
@@ -1,26 +0,0 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @enum Used to refer to the type of toast being displayed
 | 
			
		||||
 */
 | 
			
		||||
export enum ToastType {
 | 
			
		||||
    Info = "info",
 | 
			
		||||
    Success = "success",
 | 
			
		||||
    Error = "error"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @class Toast Notification
 | 
			
		||||
 */
 | 
			
		||||
export class Toast {
 | 
			
		||||
    constructor(text: String, type: ToastType, dismissable: boolean, timeout: number ) {
 | 
			
		||||
        this.text = text;
 | 
			
		||||
        this.type = type;
 | 
			
		||||
        this.dismissable = dismissable;
 | 
			
		||||
        this.timeout = timeout;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    id: number = 0;
 | 
			
		||||
    text: String;
 | 
			
		||||
    type: ToastType;
 | 
			
		||||
    dismissable: Boolean;
 | 
			
		||||
    timeout: number;
 | 
			
		||||
}
 | 
			
		||||
@@ -3,6 +3,8 @@
 | 
			
		||||
    import { toasts } from 'svelte-toasts';
 | 
			
		||||
 | 
			
		||||
    import Loading from '$lib/components/Loading.svelte';
 | 
			
		||||
    import Section from '$lib/components/Section.svelte';
 | 
			
		||||
    import Card from '$lib/components/Cards/Card.svelte';
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
{#await getJson('/json/me.json')}
 | 
			
		||||
@@ -18,23 +20,19 @@
 | 
			
		||||
        })}
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
    <div class="bg-slate-100/10 dark:bg-slate-100/10 p-10 m-5 rounded-2xl shadow-2xl">
 | 
			
		||||
        <div class="flex flex-row justify-between text-red-500 p-4">
 | 
			
		||||
            <p class="text-3xl md:text-4xl font-bold">
 | 
			
		||||
                {info.name}
 | 
			
		||||
            </p>
 | 
			
		||||
            <p class="max-md:hidden text-2xl md:text-3xl">{info.job_title}</p>
 | 
			
		||||
        </div>
 | 
			
		||||
        <hr class="max-md:hidden border-3 m-5" />
 | 
			
		||||
        <div class="flex flex-row items-center gap-5 m-2">
 | 
			
		||||
    <!-- Main Card -->
 | 
			
		||||
    <Section label="Experience">
 | 
			
		||||
        <Card headerLeft={info.name} headerRight={info.job_title} footer={info.location}>
 | 
			
		||||
            <div class="flex flex-row items-center gap-5">
 | 
			
		||||
                <img
 | 
			
		||||
                    src={info.profile_photo}
 | 
			
		||||
                    alt="Avatar"
 | 
			
		||||
                class="max-md:hidden rounded-full w-64 h-64 mt-5 mb-5 p-3 border-5"
 | 
			
		||||
                    class="max-md:hidden rounded-full w-32 h-32 md:w-48 md:h-48 mt-2 mb-2 p-2 border-3"
 | 
			
		||||
                />
 | 
			
		||||
                <p>{@html info.about}</p>
 | 
			
		||||
            </div>
 | 
			
		||||
    </div>
 | 
			
		||||
        </Card>
 | 
			
		||||
    </Section>
 | 
			
		||||
{:catch}
 | 
			
		||||
    <div style="display: none;">
 | 
			
		||||
        {toasts.add({
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "Luke Else",
 | 
			
		||||
  "job_title": "Software Engineer",
 | 
			
		||||
  "location": "Crawley, Sussex <br /> UK",
 | 
			
		||||
  "profile_photo": "/profile.jpg",
 | 
			
		||||
  "skills": [
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user