Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/sparkles text #62

Merged
merged 5 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div class="flex h-80 items-center justify-center">
<SparklesText text="Inspira UI" />
</div>
</template>
49 changes: 49 additions & 0 deletions components/content/inspira/ui/sparkles-text/Sparkle.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script setup lang="ts">
import { defineProps } from "vue";
interface SparkleProps {
id: string;
x: string;
y: string;
color: string;
delay: number;
scale: number;
duration?: number;
}
const props = withDefaults(defineProps<SparkleProps>(), {
duration: 800,
});
const motionVariants = {
initial: { opacity: 0, left: props.x, top: props.y },
enter: {
opacity: [0, 1, 0],
scale: [0, props.scale, 0],
rotate: [75, 120, 150],
transition: {
duration: props.duration,
repeat: Infinity,
delay: props.delay,
},
},
};
</script>

<template>
<svg
:key="props.id"
v-motion
:initial="motionVariants.initial"
:enter="motionVariants.enter"
class="pointer-events-none absolute z-20"
:width="21"
:height="21"
viewBox="0 0 21 21"
>
<path
d="M9.82531 0.843845C10.0553 0.215178 10.9446 0.215178 11.1746 0.843845L11.8618 2.72026C12.4006 4.19229 12.3916 6.39157 13.5 7.5C14.6084 8.60843 16.8077 8.59935 18.2797 9.13822L20.1561 9.82534C20.7858 10.0553 20.7858 10.9447 20.1561 11.1747L18.2797 11.8618C16.8077 12.4007 14.6084 12.3916 13.5 13.5C12.3916 14.6084 12.4006 16.8077 11.8618 18.2798L11.1746 20.1562C10.9446 20.7858 10.0553 20.7858 9.82531 20.1562L9.13819 18.2798C8.59932 16.8077 8.60843 14.6084 7.5 13.5C6.39157 12.3916 4.19225 12.4007 2.72023 11.8618L0.843814 11.1747C0.215148 10.9447 0.215148 10.0553 0.843814 9.82534L2.72023 9.13822C4.19225 8.59935 6.39157 8.60843 7.5 7.5C8.60843 6.39157 8.59932 4.19229 9.13819 2.72026L9.82531 0.843845Z"
:fill="props.color"
/>
</svg>
</template>
89 changes: 89 additions & 0 deletions components/content/inspira/ui/sparkles-text/SparklesText.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
<script setup lang="ts">
import { ref, onMounted, watch, computed } from "vue";
import { useIntervalFn } from "@vueuse/core";
import { cn } from "~/lib/utils";
interface Sparkle {
id: string;
x: string;
y: string;
color: string;
delay: number;
scale: number;
lifespan: number;
}
interface Colors {
first: string;
second: string;
}
interface SparklesTextProps {
as?: string;
class?: string;
text: string;
sparklesCount?: number;
colors?: Colors;
}
const props = withDefaults(defineProps<SparklesTextProps>(), {
sparklesCount: 10,
colors: () => ({ first: "#9E7AFF", second: "#FE8BBB" }),
});
const sparkles = ref<Sparkle[]>([]);
function generateSparkle(): Sparkle {
const starX = `${Math.random() * 100}%`;
const starY = `${Math.random() * 100}%`;
const color = Math.random() > 0.5 ? props.colors.first : props.colors.second;
const delay = Math.random() * 2;
const scale = Math.random() * 1 + 0.3;
const lifespan = Math.random() * 10 + 5;
const id = `${starX}-${starY}-${Date.now()}`;
return { id, x: starX, y: starY, color, delay, scale, lifespan };
};
function initializeSparkles() {
sparkles.value = Array.from({ length: props.sparklesCount }, generateSparkle);
};
function updateSparkles() {
sparkles.value = sparkles.value.map((sparkle) => {
if (sparkle.lifespan <= 0) {
return generateSparkle();
} else {
return { ...sparkle, lifespan: sparkle.lifespan - 0.1 };
}
});
};
useIntervalFn(updateSparkles, 100);
onMounted(() => {
initializeSparkles();
});
</script>

<template>
<div
:class="cn('text-6xl font-bold', props.class)"
class="sparkle-colors"
>
<span class="relative inline-block">
<Sparkle
v-for="sparkle in sparkles"
:key="sparkle.id"
v-bind="sparkle"
/>
<strong>{{ props.text }}</strong>
</span>
</div>
</template>

<style scoped>
.sparkle-colors {
--sparkles-first-color: v-bind(props.colors.first);
--sparkles-second-color: v-bind(props.colors.second);
}
</style>
35 changes: 35 additions & 0 deletions content/2.components/sparkles-text.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
title: Sparkles Text
description: A dynamic text that generates continuous sparkles with smooth transitions, perfect for highlighting text with animated stars.
navBadges:
- value: New
type: lime
---

::ComponentLoader{label="Preview" componentName="SparklesTextDemo" type="examples" id="sparkles-text"}
::

## API

| Prop Name | Type | Default | Description |
| --------------- | -------- | ---------------------------------------- | --------------------------------------------- |
| `class` | `string` | `-` | The class to be applied to the sparkles text. |
| `text` | `string` | `Inspira UI` | The text to display. |
| `sparklesCount` | `number` | `10` | sparkles count that appears on the text. |
| `colors` | `object` | `{first: '#A07CFE'; second: '#FE8FB5';}` | The sparkles colors. |

## Component Code

You can copy and paste the following code to create these components:

::code-group
::CodeViewerTab{label="SparklesText.vue" icon="vscode-icons:file-type-vue" componentName="SparklesText" type="ui" id="sparkles-text"}
::

::CodeViewerTab{label="Sparkle.vue" icon="vscode-icons:file-type-vue" componentName="Sparkle" type="ui" id="sparkles-text"}
::

## Credits

- Credits to [SivaReddy Uppathi](https://github.com/sivareddyuppathi) for this component.
- Inspired from [Magic UI](https://magicui.design/docs/components/sparkles-text).