aboutsummaryrefslogtreecommitdiffstats
path: root/apps/kit/src/lib/components/alert.svelte
diff options
context:
space:
mode:
authorivarlovlie <git@ivarlovlie.no>2022-09-24 09:36:27 +0200
committerivarlovlie <git@ivarlovlie.no>2022-09-24 09:36:27 +0200
commitb68d3fca75c68165c8e6e682127aa7b295f9ef63 (patch)
tree79c11bbd72ac84b2845a466fc704e09a84da94ca /apps/kit/src/lib/components/alert.svelte
parent9a09b5d7448b32af7bc9f7972d1ef61c631ef436 (diff)
downloadgreatoffice-b68d3fca75c68165c8e6e682127aa7b295f9ef63.tar.xz
greatoffice-b68d3fca75c68165c8e6e682127aa7b295f9ef63.zip
feat: Migrate alert to tailwind markup
Diffstat (limited to 'apps/kit/src/lib/components/alert.svelte')
-rw-r--r--apps/kit/src/lib/components/alert.svelte188
1 files changed, 131 insertions, 57 deletions
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}