📦 Add boxes, heart, house & send moving icons

This commit is contained in:
pheralb
2025-08-25 19:03:20 +01:00
parent 502fab1352
commit 5a41f792c3
4 changed files with 366 additions and 0 deletions
@@ -0,0 +1,96 @@
<script>
/**
* @typedef {Object} Props
* @property {string} [color]
* @property {number} [size]
* @property {number} [strokeWidth]
* @property {boolean} [isHovered]
* @property {string} [class]
*/
/** @type {Props} */
let {
color = "currentColor",
size = 24,
strokeWidth = 2,
isHovered = false,
class: className = "",
} = $props();
function handleMouseEnter() {
isHovered = true;
}
function handleMouseLeave() {
isHovered = false;
}
</script>
<div
class={className}
aria-label="boxes"
role="img"
onmouseenter={handleMouseEnter}
onmouseleave={handleMouseLeave}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
style="overflow: visible"
viewBox="0 0 24 24"
fill="none"
stroke={color}
stroke-width={strokeWidth}
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z m4.03 3.58 -4.74 -2.85 m4.74 2.85 5-3 m-5 3v5.17"
class="box-path"
class:animate={isHovered}
data-transform="translate(-1.5px, 1.5px)"
/>
<path
d="M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z m5 3-5-3 m5 3 4.74-2.85 M17 16.5v5.17"
class="box-path"
class:animate={isHovered}
data-transform="translate(1.5px, 1.5px)"
/>
<path
d="M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z M12 8 7.26 5.15 m4.74 2.85 4.74-2.85 M12 13.5V8"
class="box-path"
class:animate={isHovered}
data-transform="translate(0px, -1.5px)"
/>
</svg>
</div>
<style>
div {
display: inline-block;
}
.box-path {
transition: transform 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
transform: translate(0px, 0px);
}
.box-path.animate {
transform: translate(var(--transform-x, 0px), var(--transform-y, 0px));
}
.box-path[data-transform="translate(-1.5px, 1.5px)"].animate {
--transform-x: -1.5px;
--transform-y: 1.5px;
}
.box-path[data-transform="translate(1.5px, 1.5px)"].animate {
--transform-x: 1.5px;
--transform-y: 1.5px;
}
.box-path[data-transform="translate(0px, -1.5px)"].animate {
--transform-x: 0px;
--transform-y: -1.5px;
}
</style>
@@ -0,0 +1,94 @@
<script>
/**
* @typedef {Object} Props
* @property {string} [color]
* @property {number} [size]
* @property {number} [strokeWidth]
* @property {boolean} [isHovered]
* @property {string} [class]
*/
/** @type {Props} */
let {
color = "currentColor",
size = 24,
strokeWidth = 2,
isHovered = false,
class: className = "",
} = $props();
function handleMouseEnter() {
isHovered = true;
setTimeout(() => {
isHovered = false;
}, 1200);
}
</script>
<div
class={className}
aria-label="heart"
role="img"
onmouseenter={handleMouseEnter}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke={color}
stroke-width={strokeWidth}
stroke-linecap="round"
stroke-linejoin="round"
class="heart-icon"
class:animate={isHovered}
>
<path
d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"
class="heart-path"
/>
</svg>
</div>
<style>
div {
display: inline-block;
}
.heart-icon {
overflow: visible;
}
.heart-path {
transform-origin: center;
transition: transform 0.3s ease;
}
.heart-icon.animate .heart-path {
animation: heartBeat 1.2s ease-in-out;
}
@keyframes heartBeat {
0% {
transform: scale(1);
}
16.67% {
transform: scale(1.1);
}
33.33% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
66.67% {
transform: scale(1);
}
83.33% {
transform: scale(1.1);
}
100% {
transform: scale(1);
}
}
</style>
@@ -0,0 +1,88 @@
<script>
/**
* @typedef {Object} Props
* @property {string} [color]
* @property {number} [size]
* @property {number} [strokeWidth]
* @property {boolean} [isHovered]
* @property {string} [class]
*/
/** @type {Props} */
let {
color = "currentColor",
size = 24,
strokeWidth = 2,
isHovered = false,
class: className = "",
} = $props();
function handleMouseEnter() {
isHovered = true;
setTimeout(() => {
isHovered = false;
}, 800);
}
</script>
<div
class={className}
aria-label="house"
role="img"
onmouseenter={handleMouseEnter}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke={color}
stroke-width={strokeWidth}
stroke-linecap="round"
stroke-linejoin="round"
class="house-icon"
class:animate={isHovered}
>
<path
d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"
/>
<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8" class="door" />
</svg>
</div>
<style>
div {
display: inline-block;
}
.house-icon {
overflow: visible;
}
.door {
stroke-dasharray: 22;
stroke-dashoffset: 0;
transition:
stroke-dashoffset 0.3s ease,
opacity 0.3s ease;
}
.house-icon.animate .door {
animation: doorAnimation 0.6s ease-out forwards;
}
@keyframes doorAnimation {
0% {
stroke-dashoffset: 22;
opacity: 0;
}
15% {
stroke-dashoffset: 22;
opacity: 0;
}
100% {
stroke-dashoffset: 0;
opacity: 1;
}
}
</style>
@@ -0,0 +1,88 @@
<script>
/**
* @typedef {Object} Props
* @property {string} [color]
* @property {number} [size]
* @property {number} [strokeWidth]
* @property {boolean} [isHovered]
* @property {string} [class]
*/
/** @type {Props} */
let {
color = "currentColor",
size = 24,
strokeWidth = 2,
isHovered = false,
class: className = "",
} = $props();
function handleMouseEnter() {
if (isHovered) return;
isHovered = true;
setTimeout(() => {
isHovered = false;
}, 1200);
}
</script>
<div
class={className}
aria-label="send"
role="img"
onmouseenter={handleMouseEnter}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width={size}
height={size}
viewBox="0 0 24 24"
fill="none"
stroke={color}
stroke-width={strokeWidth}
stroke-linecap="round"
stroke-linejoin="round"
class="send-icon"
>
<g class:animate-group={isHovered}>
<path
d="M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z"
class="path1"
/>
<path d="m21.854 2.147-10.94 10.939" class="path2" />
</g>
</svg>
</div>
<style>
div {
display: inline-block;
}
.send-icon {
overflow: hidden;
}
.animate-group {
transform-origin: center;
animation: sendAnimation 1.2s ease-in-out;
}
@keyframes sendAnimation {
0% {
transform: scale(1) translateX(0) translateY(0);
}
25% {
transform: scale(0.8) translateX(-10%) translateY(10%);
}
50% {
transform: scale(1) translateX(100%) translateY(-100%);
}
50.1% {
transform: scale(1) translateX(-125%) translateY(125%);
}
100% {
transform: scale(1) translateX(0) translateY(0);
}
}
</style>