From f8ae7740f4a79d1374e136aba58b4c75f09b1396 Mon Sep 17 00:00:00 2001
From: ivarlovlie <git@ivarlovlie.no>
Date: Sun, 25 Sep 2022 19:25:17 +0800
Subject: feat: More complete alert

---
 apps/kit/src/lib/components/alert.svelte | 220 +++++++++++++++++++++----------
 1 file changed, 153 insertions(+), 67 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 53aa783..6cc0e63 100644
--- a/apps/kit/src/lib/components/alert.svelte
+++ b/apps/kit/src/lib/components/alert.svelte
@@ -11,30 +11,74 @@
         XMark,
     } from "./icons";
 
+    const dispatch = createEventDispatcher();
     const noCooldownSetting = "no-cooldown";
+
+    let iconComponent: any;
+    let colorClassPart = "";
+
     // if no unique id is supplied, cooldown will not work between page loads.
     // Therefore we are disabling it with noCooldownSetting in the fallback id.
+    /**
+     * An optional id for this alert, a default is set if not specified.
+     * This value is necessary for closeable cooldown to work.
+     */
     export let id = "alert--" + noCooldownSetting + "--" + random_string(4);
+    /**
+     * The title to communicate, value is optional
+     */
     export let title = "";
+    /**
+     * The message to communicate, value is optional
+     */
     export let message = "";
+    /**
+     * Changes the alerts color and icon.
+     */
     export let type: "info" | "success" | "warning" | "error" = "info";
+    /**
+     * If true the alert can be removed from the DOM by clicking on a X icon on the upper right hand courner
+     */
     export let closeable = false;
+    /**
+     * The amount of seconds that should go by before this alert is shown again, only works when a unique id is set.
+     * Set to ~ if it should be only shown once per client (State stored in localestorage).
+     **/
     export let closeableCooldown = "-1";
+    /**
+     * The text that is displayed on the right link
+     */
     export let rightLinkText = "";
+    /**
+     * An array of list items displayed under the message or title
+     */
     export let listItems: Array<string> = [];
+    /**
+     * An array of {id:string;text:string;color?:string}, where id is dispatched back as an svelte event with this syntax act$id (ex: on:actcancel).
+     * Text is the button text
+     * Color is the optional tailwind color to used, the value is used in classes like bg-$color-50.
+     */
     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 rightLinkClick if you want to intercept the click without navigating
+    /**
+     * This value is set on a plain anchor tag without any svelte routing,
+     * listen to the on:rightLinkClick if you want to intercept the click without navigating
+     */
     export let rightLinkHref = "javascript:void(0)";
-    export let visible = true;
+    $: cooldownEnabled =
+        id.indexOf(noCooldownSetting) === -1 &&
+        closeable &&
+        (closeableCooldown === "~" || parseInt(closeableCooldown) > 0);
+    /**
+     * Sets this alerts visibility state, when this is false it is removed from the dom using svelte a {#if} block.
+     */
+    export let visible =
+        closeableCooldown === "~" || parseInt(closeableCooldown) > 0
+            ? false
+            : true;
 
-    const dispatch = createEventDispatcher();
     const cooldownStorageKey = "lastseen--" + id;
 
-    let iconComponent: any;
-    let colorClassPart = "";
-
     $: switch (type) {
         case "info": {
             colorClassPart = "blue";
@@ -58,11 +102,6 @@
         }
     }
 
-    $: cooldownEnabled =
-        id.indexOf(noCooldownSetting) === -1 &&
-        closeable &&
-        (closeableCooldown === "~" || parseInt(closeableCooldown) > 0);
-
     function close() {
         visible = false;
         if (cooldownEnabled) {
@@ -83,7 +122,7 @@
     }
 
     function actionClicked(name: string) {
-        dispatch("act-" + name);
+        dispatch("act" + name);
     }
 
     // Manages the state of the alert if cooldown is enabled
@@ -97,12 +136,12 @@
             visible = true;
             return;
         }
-        if (!visible) {
-            console.log(
-                "Alert " + id + " is not visible, stopping cooldown change"
-            );
-            return;
-        }
+        // if (!visible) {
+        //     console.log(
+        //         "Alert " + id + " is not visible, stopping cooldown change"
+        //     );
+        //     return;
+        // }
         if (closeableCooldown === "~") {
             console.log("Alert " + id + " has an infinite cooldown, hiding");
             visible = false;
@@ -137,6 +176,19 @@
         if (cooldownEnabled) {
             run_cooldown();
         }
+
+        if (
+            closeable &&
+            closeableCooldown &&
+            id.indexOf(noCooldownSetting) !== -1
+        ) {
+            // TODO: This prints twice before shutting up as it should, in this example look at the only alert with closeableCooldown in alertsbook.
+            // Looks like svelte mounts three times and that my id is only set on the third. Not sure it does at all after logging the id onMount.
+            console.error(
+                "Alert cooldown does not work without specifying a unique id, related id: " +
+                    id
+            );
+        }
     });
 </script>
 
@@ -149,52 +201,85 @@
                     class="text-{colorClassPart}-400"
                 />
             </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={() => rightLinkClicked()}
-                                        class="whitespace-nowrap font-medium text-{colorClassPart}-700 hover:text-{colorClassPart}-600"
-                                    >
-                                        {rightLinkText}
-                                        <span aria-hidden="true"> &rarr;</span>
-                                    </a>
-                                </p>
+            <div class="ml-3 text-sm w-full">
+                {#if !rightLinkText}
+                    {#if title}
+                        <h3 class="font-medium text-{colorClassPart}-800">
+                            {title}
+                        </h3>
+                    {/if}
+                    {#if message}
+                        <div
+                            class="{title
+                                ? 'mt-2'
+                                : ''} text-{colorClassPart}-700 justify-start"
+                        >
+                            <p>
+                                {@html message}
+                            </p>
+                        </div>
+                    {/if}
+                    {#if listItems?.length ?? 0}
+                        <ul
+                            class="list-disc space-y-1 pl-5 text-{colorClassPart}-700"
+                        >
+                            {#each listItems as listItem}
+                                <li>{listItem}</li>
+                            {/each}
+                        </ul>
+                    {/if}
+                {:else}
+                    <div class="flex-1 md:flex md:justify-between">
+                        <div>
+                            {#if title}
+                                <h3
+                                    class="font-medium text-{colorClassPart}-800"
+                                >
+                                    {title}
+                                </h3>
                             {/if}
+                            {#if message}
+                                <div
+                                    class="{title
+                                        ? 'mt-2'
+                                        : ''} text-{colorClassPart}-700 justify-start"
+                                >
+                                    <p>
+                                        {@html message}
+                                    </p>
+                                </div>
+                            {/if}
+                            {#if listItems?.length ?? 0}
+                                <ul
+                                    class="list-disc space-y-1 pl-5 text-{colorClassPart}-700"
+                                >
+                                    {#each listItems as listItem}
+                                        <li>{listItem}</li>
+                                    {/each}
+                                </ul>
+                            {/if}
+                        </div>
+                        <p class="mt-3 text-sm md:mt-0 md:ml-6 flex items-end">
+                            <a
+                                href={rightLinkHref}
+                                on:click={() => rightLinkClicked()}
+                                class="whitespace-nowrap font-medium text-{colorClassPart}-700 hover:text-{colorClassPart}-600"
+                            >
+                                {rightLinkText}
+                                <span aria-hidden="true"> &rarr;</span>
+                            </a>
                         </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={() => actionClicked(action.id)}
-                                class="rounded-md
+                {#if actions?.length ?? 0}
+                    <div class="ml-2 mt-4">
+                        <div class="-mx-2 -my-1.5 flex gap-1">
+                            {#each actions as action}
+                                {@const color = action?.color ?? colorClassPart}
+                                <button
+                                    type="button"
+                                    on:click={() => actionClicked(action.id)}
+                                    class="rounded-md
                             bg-{color}-50
                             px-2 py-1.5 text-sm font-medium
                             text-{color}-800
@@ -203,13 +288,14 @@
                             focus:ring-{color}-600
                             focus:ring-offset-2
                             focus:ring-offset-{color}-50"
-                            >
-                                {action.text}
-                            </button>
-                        {/each}
+                                >
+                                    {action.text}
+                                </button>
+                            {/each}
+                        </div>
                     </div>
-                </div>
-            {/if}
+                {/if}
+            </div>
             {#if closeable}
                 <div class="ml-auto pl-3">
                     <div class="-mx-1.5 -my-1.5">
-- 
cgit v1.3

