From b68d3fca75c68165c8e6e682127aa7b295f9ef63 Mon Sep 17 00:00:00 2001
From: ivarlovlie <git@ivarlovlie.no>
Date: Sat, 24 Sep 2022 15:36:27 +0800
Subject: feat: Migrate alert to tailwind markup

---
 apps/kit/src/lib/components/alert.svelte | 188 +++++++++++++++++++++----------
 1 file changed, 131 insertions(+), 57 deletions(-)

(limited to 'apps/kit/src/lib/components/alert.svelte')

diff --git a/apps/kit/src/lib/components/alert.svelte b/apps/kit/src/lib/components/alert.svelte
index 4a5c7ea..87962cf 100644
--- a/apps/kit/src/lib/components/alert.svelte
+++ b/apps/kit/src/lib/components/alert.svelte
@@ -1,7 +1,15 @@
 <script lang="ts">
-    import { random_string } from "$shared/lib/helpers";
-    import { afterUpdate, onMount } from "svelte";
+    import { random_string } from "$lib/helpers";
+    import { createEventDispatcher } from "svelte";
+    import { onMount } from "svelte";
     import { Temporal } from "temporal-polyfill";
+    import {
+        ExclamationTriangle,
+        CheckCircle,
+        InformationCircle,
+        XCircle,
+        XMark,
+    } from "./icons";
 
     const noCooldownSetting = "no-cooldown";
     // if no unique id is supplied, cooldown will not work between page loads.
@@ -9,12 +17,48 @@
     export let id = "alert--" + noCooldownSetting + "--" + random_string(4);
     export let title = "";
     export let message = "";
-    export let type = "info";
+    export let type: "info" | "success" | "warning" | "error" = "info";
     export let closeable = false;
     export let closeableCooldown = "-1";
+    export let rightLinkText = "";
+    export let listItems: Array<string> = [];
+    export let actions: Array<{ id: string; text: string; color?: string }> =
+        [];
+    // This value is set on a plain anchor tag without any svelte routing,
+    // listen to the right-link-click if you want to intercept the click without navigating
+    export let rightLinkHref = "javascript:void(0)";
     export let visible = true;
 
+    const dispatch = createEventDispatcher();
+
     const cooldownStorageKey = "lastseen--" + id;
+
+    let iconComponent: any;
+    let colorClassPart = "";
+
+    $: switch (type) {
+        case "info": {
+            colorClassPart = "blue";
+            iconComponent = InformationCircle;
+            break;
+        }
+        case "warning": {
+            colorClassPart = "yellow";
+            iconComponent = ExclamationTriangle;
+            break;
+        }
+        case "error": {
+            colorClassPart = "red";
+            iconComponent = XCircle;
+            break;
+        }
+        case "success": {
+            colorClassPart = "green";
+            iconComponent = CheckCircle;
+            break;
+        }
+    }
+
     $: cooldownEnabled =
         id.indexOf(noCooldownSetting) === -1 &&
         closeable &&
@@ -59,7 +103,7 @@
         }
 
         const lastSeen = Temporal.Instant.fromEpochSeconds(
-            localStorage.getItem(cooldownStorageKey) as number
+            parseInt(localStorage.getItem(cooldownStorageKey) ?? "-1")
         );
         if (
             Temporal.Instant.compare(
@@ -87,63 +131,93 @@
             run_cooldown();
         }
     });
-
-    afterUpdate(() => {
-        if (type === "default") {
-            type = "primary";
-        }
-    });
 </script>
 
-<div
-    class="alert alert--{type} padding-sm radius-md"
-    {id}
-    class:alert--is-visible={visible}
-    role="alert"
->
-    <div class="flex justify-between">
-        <div class="flex flex-row items-center">
-            <svg
-                class="icon icon--sm alert__icon margin-right-xxs"
-                viewBox="0 0 24 24"
-                aria-hidden="true"
-            >
-                <path
-                    d="M12,0C5.383,0,0,5.383,0,12s5.383,12,12,12s12-5.383,12-12S18.617,0,12,0z M14.658,18.284 c-0.661,0.26-2.952,1.354-4.272,0.191c-0.394-0.346-0.59-0.785-0.59-1.318c0-0.998,0.328-1.868,0.919-3.957 c0.104-0.395,0.231-0.907,0.231-1.313c0-0.701-0.266-0.887-0.987-0.887c-0.352,0-0.742,0.125-1.095,0.257l0.195-0.799 c0.787-0.32,1.775-0.71,2.621-0.71c1.269,0,2.203,0.633,2.203,1.837c0,0.347-0.06,0.955-0.186,1.375l-0.73,2.582 c-0.151,0.522-0.424,1.673-0.001,2.014c0.416,0.337,1.401,0.158,1.887-0.071L14.658,18.284z M13.452,8c-0.828,0-1.5-0.672-1.5-1.5 s0.672-1.5,1.5-1.5s1.5,0.672,1.5,1.5S14.28,8,13.452,8z"
+{#if visible}
+    <div class="rounded-md bg-{colorClassPart}-50 p-4 ">
+        <div class="flex">
+            <div class="flex-shrink-0">
+                <svelte:component
+                    this={iconComponent}
+                    class="text-{colorClassPart}-400"
                 />
-            </svg>
-            {#if title}
-                <p class="text-sm">
-                    <strong class="error-title">{title}</strong>
-                </p>
-            {:else if message}
-                <div class="text-component text-sm break-word">
-                    {@html message}
+            </div>
+            <div class="ml-3">
+                {#if title}
+                    <h3 class="text-sm font-medium text-{colorClassPart}-800">
+                        {title}
+                    </h3>
+                {/if}
+                {#if message}
+                    <div
+                        class="{title
+                            ? 'mt-2 text-sm'
+                            : ''} text-{colorClassPart}-700"
+                    >
+                        <p>
+                            {@html message}
+                            {#if rightLinkText}
+                                <p class="mt-3 text-sm md:mt-0 md:ml-6">
+                                    <a
+                                        href={rightLinkHref}
+                                        on:click={() =>
+                                            dispatch("right-link-click")}
+                                        class="whitespace-nowrap font-medium text-{colorClassPart}-700 hover:text-{colorClassPart}-600"
+                                    >
+                                        {rightLinkText}
+                                        <span aria-hidden="true"> &rarr;</span>
+                                    </a>
+                                </p>
+                            {/if}
+                        </p>
+                        {#if listItems?.length ?? 0}
+                            <ul class="list-disc space-y-1 pl-5">
+                                {#each listItems as listItem}
+                                    <li>{listItem}</li>
+                                {/each}
+                            </ul>
+                        {/if}
+                    </div>
+                {/if}
+            </div>
+            {#if actions?.length ?? 0}
+                <div class="mt-4">
+                    <div class="-mx-2 -my-1.5 flex">
+                        {#each actions as action}
+                            {@const color = action?.color ?? colorClassPart}
+                            <button
+                                type="button"
+                                on:click={() => dispatch("act-" + action.id)}
+                                class="rounded-md
+                            bg-{color}-50
+                            px-2 py-1.5 text-sm font-medium
+                            text-{color}-800
+                            hover:bg-{color}-100
+                            focus:outline-none focus:ring-2
+                            focus:ring-{color}-600
+                            focus:ring-offset-2
+                            focus:ring-offset-{color}-50"
+                            >
+                                {action.text}
+                            </button>
+                        {/each}
+                    </div>
+                </div>
+            {/if}
+            {#if closeable}
+                <div class="ml-auto pl-3">
+                    <div class="-mx-1.5 -my-1.5">
+                        <button
+                            type="button"
+                            on:click={() => close()}
+                            class="inline-flex rounded-md bg-{colorClassPart}-50 p-1.5 text-{colorClassPart}-500 hover:bg-{colorClassPart}-100 focus:outline-none focus:ring-2 focus:ring-{colorClassPart}-600 focus:ring-offset-2 focus:ring-offset-{colorClassPart}-50"
+                        >
+                            <span class="sr-only">Dismiss</span>
+                            <XMark />
+                        </button>
+                    </div>
                 </div>
             {/if}
         </div>
-        {#if closeable}
-            <button class="reset alert__close-btn" on:click={close}>
-                <svg
-                    class="icon"
-                    viewBox="0 0 20 20"
-                    fill="none"
-                    stroke="currentColor"
-                    stroke-linecap="round"
-                    stroke-linejoin="round"
-                    stroke-width="2"
-                >
-                    <title>Close alert</title>
-                    <line x1="3" y1="3" x2="17" y2="17" />
-                    <line x1="17" y1="3" x2="3" y2="17" />
-                </svg>
-            </button>
-        {/if}
     </div>
-
-    {#if message && title}
-        <div class="text-component text-sm break-word padding-top-xs">
-            {@html message}
-        </div>
-    {/if}
-</div>
+{/if}
-- 
cgit v1.3

