Back
Dynamic Island Effect
DynamicIslandEffect.svelte
<script lang="ts">
import { blur } from "svelte/transition";
import { draw } from "svelte/transition";
import Button from "$lib/components/ui/button/button.svelte";
import { spring, tweened } from "svelte/motion";
// Play with Damping and Stiffness
let x = spring(100, {
stiffness: 0.05,
damping: 0.25,
});
let y = spring(28);
let rounded = tweened(20);
let isHovered = false;
let isTimeHovered = false;
let text = "Ring";
// Svg path
let paths = [
"M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9",
"M10.3 21a1.94 1.94 0 0 0 3.4 0",
"M4 2C2.8 3.7 2 5.7 2 8",
"M22 8c0-2.3-.8-4.3-2-6",
];
let run: NodeJS.Timeout;
let timeoutId: NodeJS.Timeout;
// Effects run on Click
let isSvgRing = true;
let clickEffect = () => {
if (run) clearInterval(run);
if (timeoutId) clearTimeout(timeoutId);
originalSize();
text = "Ring";
isSvgRing = true;
isHovered = true;
isTimeHovered = false;
x.set(140);
y.set(35);
rounded.set(50);
run = setInterval(() => {
isSvgRing = !isSvgRing;
text = isSvgRing ? "Ring" : "Silent";
isSvgRing ? x.set(140) : x.set(155);
}, 1500);
timeoutId = setTimeout(() => {
clearInterval(run);
originalSize();
}, 10000);
};
let originalSize = () => {
clearInterval(run);
isTimeHovered = false;
isHovered = false;
x.set(100);
y.set(28);
rounded.set(20);
};
let timerSize = () => {
clearInterval(run);
isHovered = false;
isTimeHovered = true;
x.set(200);
y.set(55);
rounded.set(50);
};
</script>
<div
class="flex justify-center items-center min-h-[300px] flex-col bg-gray-100 w-full"
>
<div class="min-h-60 flex justify-center items-center">
<div
class="bg-black"
style="width: {$x}px; height:{$y}px; border-radius: {$rounded}px;"
>
{#if isHovered}
<div
class="px-4 flex justify-between text-white items-center h-full"
in:blur={{ amount: 15 }}
>
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
><path in:draw d={paths[0]} /><path in:draw d={paths[1]} /><path
in:draw={{ delay: 300 }}
d={paths[2]}
/><path in:draw={{ delay: 300 }} d={paths[3]} /></svg
>
</div>
{#key text}
<div
class="text-xs font-medium {isSvgRing
? 'text-white'
: 'text-red-500'}"
in:blur
>
{text}
</div>
{/key}
</div>
{:else if isTimeHovered}
<div
class="px-4 flex justify-between text-white items-center h-full"
in:blur={{ amount: 2 }}
>
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="22"
height="22"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.4"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-monitor-dot"
><circle cx="19" cy="6" r="3" /><path
d="M22 12v3a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h9"
/><path d="M12 17v4" /><path d="M8 21h8" /></svg
>
</div>
{#key text}
<div class="text-sm font-medium" in:blur>Desktop</div>
{/key}
</div>
{:else}
<div
class="px-2 flex justify-between text-white items-center h-full"
in:blur={{ amount: 2 }}
>
<div></div>
{#key text}
<div in:blur>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="#1F1F1F"
stroke="currentColor"
stroke-width="1.4"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-circle"
><circle cx="12" cy="12" r="10" /></svg
>
</div>
{/key}
</div>
{/if}
</div>
</div>
<div class="flex justify-center items-center gap-4">
<Button
class="rounded-full outline-none border border-black"
on:click={originalSize}>Idle</Button
>
<Button
class="rounded-full outline-none border border-black"
on:click={clickEffect}>Ring</Button
>
<Button
on:click={timerSize}
class="rounded-full outline-none border border-black">Timer</Button
>
</div>
</div>