Small fixes

This commit is contained in:
David Haz
2025-07-19 19:55:19 +03:00
parent a6df503535
commit 340985ce52
8 changed files with 350 additions and 452 deletions

View File

@@ -1,5 +1,5 @@
import code from '@content/Components/AnimatedList/AnimatedList.vue?raw'
import type { CodeObject } from '../../../types/code'
import code from '@content/Components/AnimatedList/AnimatedList.vue?raw';
import type { CodeObject } from '../../../types/code';
export const animatedList: CodeObject = {
cli: `npx jsrepo add https://vue-bits.dev/ui/Components/AnimatedList`,
@@ -24,4 +24,4 @@ const items = [
]
</script>`,
code
}
};

View File

@@ -13,4 +13,4 @@ export const folder: CodeObject = {
const items = ['Doc 1', 'Doc 2', 'Doc 3'];
</script>`,
code
};
};

View File

@@ -1,87 +1,94 @@
<template>
<component :is="as" :class="[
'relative inline-block overflow-hidden !bg-transparent !border-none !rounded-[20px]',
customClass
]" v-bind="restAttrs" :style="componentStyle">
<div class="absolute w-[300%] h-[50%] opacity-70 bottom-[-11px] right-[-250%] rounded-full animate-star-movement-bottom z-0"
:style="{
background: `radial-gradient(circle, ${color}, transparent 10%)`,
animationDuration: speed
}"></div>
<component
:is="as"
:class="['relative inline-block overflow-hidden !bg-transparent !border-none !rounded-[20px]', customClass]"
v-bind="restAttrs"
:style="componentStyle"
>
<div
class="absolute w-[300%] h-[50%] opacity-70 bottom-[-11px] right-[-250%] rounded-full animate-star-movement-bottom z-0"
:style="{
background: `radial-gradient(circle, ${color}, transparent 10%)`,
animationDuration: speed
}"
></div>
<div class="absolute w-[300%] h-[50%] opacity-70 top-[-10px] left-[-250%] rounded-full animate-star-movement-top z-0"
:style="{
background: `radial-gradient(circle, ${color}, transparent 10%)`,
animationDuration: speed
}"></div>
<div
class="absolute w-[300%] h-[50%] opacity-70 top-[-10px] left-[-250%] rounded-full animate-star-movement-top z-0"
:style="{
background: `radial-gradient(circle, ${color}, transparent 10%)`,
animationDuration: speed
}"
></div>
<div
class="relative z-10 border border-[#222] bg-black text-white text-[16px] text-center px-[26px] py-[16px] rounded-[20px]">
<slot />
</div>
</component>
<div
class="relative z-10 border border-[#333] bg-[#0b0b0b] text-white text-[16px] text-center px-[64px] py-[24px] rounded-[20px]"
>
<slot />
</div>
</component>
</template>
<script setup lang="ts">
import { computed, defineProps, useAttrs } from 'vue';
interface StarBorderProps {
as?: string;
customClass?: string;
color?: string;
speed?: string;
thickness?: number;
as?: string;
customClass?: string;
color?: string;
speed?: string;
thickness?: number;
}
const props = withDefaults(defineProps<StarBorderProps>(), {
as: 'button',
customClass: '',
color: 'white',
speed: '6s',
thickness: 1
as: 'button',
customClass: '',
color: 'white',
speed: '6s',
thickness: 1
});
const restAttrs = useAttrs();
const componentStyle = computed(() => {
const base = {
padding: `${props.thickness}px 0`
};
const userStyle = (restAttrs.style as Record<string, string>) || {};
return { ...base, ...userStyle };
const base = {
padding: `${props.thickness}px 0`
};
const userStyle = (restAttrs.style as Record<string, string>) || {};
return { ...base, ...userStyle };
});
</script>
<style scoped>
@keyframes star-movement-bottom {
0% {
transform: translate(0%, 0%);
opacity: 1;
}
0% {
transform: translate(0%, 0%);
opacity: 1;
}
100% {
transform: translate(-100%, 0%);
opacity: 0;
}
100% {
transform: translate(-100%, 0%);
opacity: 0;
}
}
@keyframes star-movement-top {
0% {
transform: translate(0%, 0%);
opacity: 1;
}
0% {
transform: translate(0%, 0%);
opacity: 1;
}
100% {
transform: translate(100%, 0%);
opacity: 0;
}
100% {
transform: translate(100%, 0%);
opacity: 0;
}
}
.animate-star-movement-bottom {
animation: star-movement-bottom linear infinite alternate;
animation: star-movement-bottom linear infinite alternate;
}
.animate-star-movement-top {
animation: star-movement-top linear infinite alternate;
animation: star-movement-top linear infinite alternate;
}
</style>

View File

@@ -23,10 +23,12 @@
:animate="getItemInView(index) ? { scale: 1, opacity: 1 } : { scale: 0.7, opacity: 0 }"
:transition="{ duration: 0.2, delay: 0.1 }"
@mouseenter="() => setSelectedIndex(index)"
@click="() => {
setSelectedIndex(index)
emit('itemSelected', item, index)
}"
@click="
() => {
setSelectedIndex(index);
emit('itemSelected', item, index);
}
"
>
<div :class="`p-4 bg-[#111] rounded-lg ${selectedIndex === index ? 'bg-[#222]' : ''} ${itemClassName}`">
<p class="text-white m-0">{{ item }}</p>
@@ -47,24 +49,36 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue'
import { Motion } from 'motion-v'
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Motion } from 'motion-v';
interface AnimatedListProps {
items?: string[]
showGradients?: boolean
enableArrowNavigation?: boolean
className?: string
itemClassName?: string
displayScrollbar?: boolean
initialSelectedIndex?: number
items?: string[];
showGradients?: boolean;
enableArrowNavigation?: boolean;
className?: string;
itemClassName?: string;
displayScrollbar?: boolean;
initialSelectedIndex?: number;
}
const props = withDefaults(defineProps<AnimatedListProps>(), {
items: () => [
'Item 1', 'Item 2', 'Item 3', 'Item 4', 'Item 5',
'Item 6', 'Item 7', 'Item 8', 'Item 9', 'Item 10',
'Item 11', 'Item 12', 'Item 13', 'Item 14', 'Item 15'
'Item 1',
'Item 2',
'Item 3',
'Item 4',
'Item 5',
'Item 6',
'Item 7',
'Item 8',
'Item 9',
'Item 10',
'Item 11',
'Item 12',
'Item 13',
'Item 14',
'Item 15'
],
showGradients: true,
enableArrowNavigation: true,
@@ -72,114 +86,108 @@ const props = withDefaults(defineProps<AnimatedListProps>(), {
itemClassName: '',
displayScrollbar: true,
initialSelectedIndex: -1
})
});
const emit = defineEmits<{
itemSelected: [item: string, index: number]
}>()
itemSelected: [item: string, index: number];
}>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef')
const listRef = useTemplateRef<HTMLDivElement>('listRef')
const selectedIndex = ref(props.initialSelectedIndex)
const keyboardNav = ref(false)
const topGradientOpacity = ref(0)
const bottomGradientOpacity = ref(1)
const itemsInView = ref<boolean[]>([])
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const listRef = useTemplateRef<HTMLDivElement>('listRef');
const selectedIndex = ref(props.initialSelectedIndex);
const keyboardNav = ref(false);
const topGradientOpacity = ref(0);
const bottomGradientOpacity = ref(1);
const itemsInView = ref<boolean[]>([]);
const setSelectedIndex = (index: number) => {
selectedIndex.value = index
}
selectedIndex.value = index;
};
const getItemInView = (index: number) => {
return itemsInView.value[index] ?? false
}
return itemsInView.value[index] ?? false;
};
const handleScroll = (e: Event) => {
const target = e.target as HTMLDivElement
const { scrollTop, scrollHeight, clientHeight } = target
topGradientOpacity.value = Math.min(scrollTop / 50, 1)
const bottomDistance = scrollHeight - (scrollTop + clientHeight)
bottomGradientOpacity.value =
scrollHeight <= clientHeight ? 0 : Math.min(bottomDistance / 50, 1)
updateItemsInView()
}
const target = e.target as HTMLDivElement;
const { scrollTop, scrollHeight, clientHeight } = target;
topGradientOpacity.value = Math.min(scrollTop / 50, 1);
const bottomDistance = scrollHeight - (scrollTop + clientHeight);
bottomGradientOpacity.value = scrollHeight <= clientHeight ? 0 : Math.min(bottomDistance / 50, 1);
updateItemsInView();
};
const updateItemsInView = () => {
if (!listRef.value) return
const container = listRef.value
const containerRect = container.getBoundingClientRect()
if (!listRef.value) return;
const container = listRef.value;
const containerRect = container.getBoundingClientRect();
itemsInView.value = props.items.map((_, index) => {
const item = container.querySelector(`[data-index="${index}"]`) as HTMLElement
if (!item) return false
const itemRect = item.getBoundingClientRect()
const viewHeight = containerRect.height
const itemTop = itemRect.top - containerRect.top
const itemBottom = itemTop + itemRect.height
return itemTop < viewHeight && itemBottom > 0
})
}
const item = container.querySelector(`[data-index="${index}"]`) as HTMLElement;
if (!item) return false;
const itemRect = item.getBoundingClientRect();
const viewHeight = containerRect.height;
const itemTop = itemRect.top - containerRect.top;
const itemBottom = itemTop + itemRect.height;
return itemTop < viewHeight && itemBottom > 0;
});
};
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) {
e.preventDefault()
keyboardNav.value = true
setSelectedIndex(Math.min(selectedIndex.value + 1, props.items.length - 1))
e.preventDefault();
keyboardNav.value = true;
setSelectedIndex(Math.min(selectedIndex.value + 1, props.items.length - 1));
} else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) {
e.preventDefault()
keyboardNav.value = true
setSelectedIndex(Math.max(selectedIndex.value - 1, 0))
e.preventDefault();
keyboardNav.value = true;
setSelectedIndex(Math.max(selectedIndex.value - 1, 0));
} else if (e.key === 'Enter') {
if (selectedIndex.value >= 0 && selectedIndex.value < props.items.length) {
e.preventDefault()
emit('itemSelected', props.items[selectedIndex.value], selectedIndex.value)
e.preventDefault();
emit('itemSelected', props.items[selectedIndex.value], selectedIndex.value);
}
}
}
};
watch([selectedIndex, keyboardNav], () => {
if (!keyboardNav.value || selectedIndex.value < 0 || !listRef.value) return
const container = listRef.value
const selectedItem = container.querySelector(
`[data-index="${selectedIndex.value}"]`
) as HTMLElement | null
if (!keyboardNav.value || selectedIndex.value < 0 || !listRef.value) return;
const container = listRef.value;
const selectedItem = container.querySelector(`[data-index="${selectedIndex.value}"]`) as HTMLElement | null;
if (selectedItem) {
const extraMargin = 50
const containerScrollTop = container.scrollTop
const containerHeight = container.clientHeight
const itemTop = selectedItem.offsetTop
const itemBottom = itemTop + selectedItem.offsetHeight
const extraMargin = 50;
const containerScrollTop = container.scrollTop;
const containerHeight = container.clientHeight;
const itemTop = selectedItem.offsetTop;
const itemBottom = itemTop + selectedItem.offsetHeight;
if (itemTop < containerScrollTop + extraMargin) {
container.scrollTo({ top: itemTop - extraMargin, behavior: 'smooth' })
} else if (
itemBottom >
containerScrollTop + containerHeight - extraMargin
) {
container.scrollTo({ top: itemTop - extraMargin, behavior: 'smooth' });
} else if (itemBottom > containerScrollTop + containerHeight - extraMargin) {
container.scrollTo({
top: itemBottom - containerHeight + extraMargin,
behavior: 'smooth'
})
});
}
}
keyboardNav.value = false
})
keyboardNav.value = false;
});
onMounted(() => {
if (props.enableArrowNavigation) {
window.addEventListener('keydown', handleKeyDown)
window.addEventListener('keydown', handleKeyDown);
}
itemsInView.value = new Array(props.items.length).fill(true)
setTimeout(updateItemsInView, 100)
})
itemsInView.value = new Array(props.items.length).fill(true);
setTimeout(updateItemsInView, 100);
});
onUnmounted(() => {
if (props.enableArrowNavigation) {
window.removeEventListener('keydown', handleKeyDown)
window.removeEventListener('keydown', handleKeyDown);
}
})
</script>
});
</script>

View File

@@ -1,51 +1,34 @@
<template>
<div :style="{transform: `scale(${props.size})`}" :class="class">
<div
:class="folderClass"
:style="folderStyle"
@click="handleClick"
>
<div class="folder_back">
<div
v-for="(item, i) in papers"
:key="i"
:class="`paper paper-${i + 1}`"
@mousemove="(e) => handlePaperMouseMove(e, i)"
@mouseleave="(e) => handlePaperMouseLeave(e, i)"
:style="open ? {
'--magnet-x': `${paperOffsets[i]?.x || 0}px`,
'--magnet-y': `${paperOffsets[i]?.y || 0}px`,
} : {}"
>
<slot
:name="`item-${i + 1}`"
:item="item"
:index="i"
:isOpen="open"
>
<div :style="{ transform: `scale(${props.size})` }" :class="props.class">
<div :class="folderClass" :style="folderStyle" @click="handleClick">
<div
class="relative w-[100px] h-[80px] rounded-tl-0 rounded-tr-[10px] rounded-br-[10px] rounded-bl-[10px]"
:style="{ backgroundColor: folderBackColor }"
>
<span
class="absolute z-0 bottom-[98%] left-0 w-[30px] h-[10px] rounded-tl-[5px] rounded-tr-[5px] rounded-bl-0 rounded-br-0"
:style="{ backgroundColor: folderBackColor }"
></span>
<div v-for="(item, i) in papers" :key="i" :class="getPaperClasses(i)" :style="getPaperStyle(i)">
<slot :name="`item-${i + 1}`" :item="item" :index="i" :isOpen="open">
{{ item }}
</slot>
</div>
<div class="folder_front"></div>
<div class="folder_front right"></div>
<div :class="frontClass" :style="{ backgroundColor: props.color }"></div>
<div :class="rightClass" :style="{ backgroundColor: props.color }"></div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
interface PaperOffset {
x: number
y: number
}
import { ref, computed } from 'vue';
interface Props {
color?: string
size?: number
items?: (string | null)[]
class?: string
color?: string;
size?: number;
items?: (string | null)[];
class?: string;
}
const props = withDefaults(defineProps<Props>(), {
@@ -53,212 +36,112 @@ const props = withDefaults(defineProps<Props>(), {
size: 1,
items: () => [],
class: ''
})
});
const darkenColor = (hex: string, percent: number): string => {
let color = hex.startsWith('#') ? hex.slice(1) : hex
let color = hex.startsWith('#') ? hex.slice(1) : hex;
if (color.length === 3) {
color = color
.split('')
.map((c) => c + c)
.join('')
.map(c => c + c)
.join('');
}
const num = parseInt(color, 16)
let r = (num >> 16) & 0xff
let g = (num >> 8) & 0xff
let b = num & 0xff
r = Math.max(0, Math.min(255, Math.floor(r * (1 - percent))))
g = Math.max(0, Math.min(255, Math.floor(g * (1 - percent))))
b = Math.max(0, Math.min(255, Math.floor(b * (1 - percent))))
return (
'#' +
((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()
)
}
const num = parseInt(color, 16);
let r = (num >> 16) & 0xff;
let g = (num >> 8) & 0xff;
let b = num & 0xff;
r = Math.max(0, Math.min(255, Math.floor(r * (1 - percent))));
g = Math.max(0, Math.min(255, Math.floor(g * (1 - percent))));
b = Math.max(0, Math.min(255, Math.floor(b * (1 - percent))));
return '#' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase();
};
const open = ref(false)
const maxItems = 3
const paperOffsets = ref<PaperOffset[]>(
Array.from({ length: maxItems }, () => ({ x: 0, y: 0 }))
)
const open = ref(false);
const maxItems = 3;
const papers = computed(() => {
const result = props.items.slice(0, maxItems)
const result = props.items.slice(0, maxItems);
while (result.length < maxItems) {
result.push(null)
result.push(null);
}
return result
})
return result;
});
const folderBackColor = computed(() => darkenColor(props.color, 0.08))
const paper1 = computed(() => darkenColor('#ffffff', 0.1))
const paper2 = computed(() => darkenColor('#ffffff', 0.05))
const paper3 = computed(() => '#ffffff')
const folderBackColor = computed(() => darkenColor(props.color, 0.08));
const paper1 = computed(() => darkenColor('#ffffff', 0.1));
const paper2 = computed(() => darkenColor('#ffffff', 0.05));
const paper3 = computed(() => '#ffffff');
const folderStyle = computed(() => ({
'--folder-color': props.color,
'--folder-back-color': folderBackColor.value,
'--paper-1': paper1.value,
'--paper-2': paper2.value,
'--paper-3': paper3.value,
}))
transform: open.value ? 'translateY(-8px)' : undefined
}));
const folderClass = computed(() => `folder ${open.value ? 'open' : ''}`.trim())
const folderClass = computed(() =>
`group relative transition-all duration-200 ease-in cursor-pointer ${
!open.value ? 'hover:-translate-y-2' : ''
}`.trim()
);
const getPaperClasses = (index: number) => {
let sizeClasses = '';
if (index === 0) sizeClasses = 'w-[70%] h-[80%]';
if (index === 1) sizeClasses = open.value ? 'w-[80%] h-[80%]' : 'w-[80%] h-[70%]';
if (index === 2) sizeClasses = open.value ? 'w-[90%] h-[80%]' : 'w-[90%] h-[60%]';
return `absolute z-20 bottom-[10%] left-1/2 transition-all duration-300 ease-in-out overflow-hidden ${
!open.value ? 'transform -translate-x-1/2 translate-y-[10%] group-hover:translate-y-0' : 'hover:scale-110'
} ${sizeClasses}`.trim();
};
const getOpenTransform = (index: number) => {
if (index === 0) return 'translate(-120%, -70%) rotate(-15deg)';
if (index === 1) return 'translate(10%, -70%) rotate(15deg)';
if (index === 2) return 'translate(-50%, -100%) rotate(5deg)';
return '';
};
const getPaperStyle = (index: number) => {
const backgroundColor = index === 0 ? paper1.value : index === 1 ? paper2.value : paper3.value;
const baseStyle = {
backgroundColor,
borderRadius: '10px',
transition: 'all 0.3s ease-in-out'
};
if (open.value) {
const transformStyle = getOpenTransform(index);
return {
...baseStyle,
transform: transformStyle
};
}
return baseStyle;
};
const frontClass = computed(() => {
const baseClasses = 'absolute z-30 w-full h-full origin-bottom transition-all duration-300 ease-in-out';
const borderRadius = 'rounded-tl-[5px] rounded-tr-[10px] rounded-br-[10px] rounded-bl-[10px]';
if (open.value) {
return `${baseClasses} ${borderRadius} [transform:skew(15deg)_scaleY(0.6)]`;
} else {
return `${baseClasses} ${borderRadius} group-hover:[transform:skew(15deg)_scaleY(0.6)]`;
}
});
const rightClass = computed(() => {
const baseClasses = 'absolute z-30 w-full h-full origin-bottom transition-all duration-300 ease-in-out';
const borderRadius = 'rounded-tl-[5px] rounded-tr-[10px] rounded-br-[10px] rounded-bl-[10px]';
if (open.value) {
return `${baseClasses} ${borderRadius} [transform:skew(-15deg)_scaleY(0.6)]`;
} else {
return `${baseClasses} ${borderRadius} group-hover:[transform:skew(-15deg)_scaleY(0.6)]`;
}
});
const handleClick = () => {
open.value = !open.value
if (!open.value) {
paperOffsets.value = Array.from({ length: maxItems }, () => ({ x: 0, y: 0 }))
}
}
const handlePaperMouseMove = (e: MouseEvent, index: number) => {
if (!open.value) return
const target = e.currentTarget as HTMLElement
const rect = target.getBoundingClientRect()
const centerX = rect.left + rect.width / 2
const centerY = rect.top + rect.height / 2
const offsetX = (e.clientX - centerX) * 0.15
const offsetY = (e.clientY - centerY) * 0.15
paperOffsets.value = paperOffsets.value.map((offset, i) =>
i === index ? { x: offsetX, y: offsetY } : offset
)
}
const handlePaperMouseLeave = (e: MouseEvent, index: number) => {
paperOffsets.value = paperOffsets.value.map((offset, i) =>
i === index ? { x: 0, y: 0 } : offset
)
}
open.value = !open.value;
};
</script>
<style scoped>
:root {
--folder-color: #70a1ff;
--folder-back-color: #4785ff;
--paper-1: #e6e6e6;
--paper-2: #f2f2f2;
--paper-3: #ffffff;
}
.folder {
transition: all 0.2s ease-in;
cursor: pointer;
}
.folder:not(.folder--click):hover {
transform: translateY(-8px);
}
.folder:not(.folder--click):hover .paper {
transform: translate(-50%, 0%);
}
.folder:not(.folder--click):hover .folder_front {
transform: skew(15deg) scaleY(0.6);
}
.folder:not(.folder--click):hover .right {
transform: skew(-15deg) scaleY(0.6);
}
.folder.open {
transform: translateY(-8px);
}
.folder.open .paper:nth-child(1) {
transform: translate(-120%, -70%) rotateZ(-15deg);
}
.folder.open .paper:nth-child(1):hover {
transform: translate(-120%, -70%) rotateZ(-15deg) scale(1.1);
z-index: 3;
}
.folder.open .paper:nth-child(2) {
transform: translate(10%, -70%) rotateZ(15deg);
height: 80%;
}
.folder.open .paper:nth-child(2):hover {
transform: translate(10%, -70%) rotateZ(15deg) scale(1.1);
z-index: 3;
}
.folder.open .paper:nth-child(3) {
transform: translate(-50%, -100%) rotateZ(5deg);
height: 80%;
}
.folder.open .paper:nth-child(3):hover {
transform: translate(-50%, -100%) rotateZ(5deg) scale(1.1);
z-index: 3;
}
.folder.open .folder_front {
transform: skew(15deg) scaleY(0.6);
}
.folder.open .right {
transform: skew(-15deg) scaleY(0.6);
}
.folder_back {
position: relative;
width: 100px;
height: 80px;
background: var(--folder-back-color);
border-radius: 0px 10px 10px 10px;
}
.folder_back::after {
position: absolute;
z-index: 0;
bottom: 98%;
left: 0;
content: "";
width: 30px;
height: 10px;
background: var(--folder-back-color);
border-radius: 5px 5px 0 0;
}
.paper {
position: absolute;
z-index: 2;
bottom: 10%;
left: 50%;
transform: translate(-50%, 10%);
width: 70%;
height: 80%;
background: var(--paper-1);
border-radius: 10px;
transition: all 0.3s ease-in-out;
overflow: hidden;
}
.paper:nth-child(2) {
background: var(--paper-2);
width: 80%;
height: 70%;
}
.paper:nth-child(3) {
background: var(--paper-3);
width: 90%;
height: 60%;
}
.folder_front {
position: absolute;
z-index: 3;
width: 100%;
height: 100%;
background: var(--folder-color);
border-radius: 5px 10px 10px 10px;
transform-origin: bottom;
transition: all 0.3s ease-in-out;
}
</style>

View File

@@ -1,29 +1,27 @@
<template>
<TabbedLayout>
<template #preview>
<div class="demo-container overflow-hidden h-[400px]">
<StarBorder as="button" :color="color" :speed="speedProp" :thickness="thickness">
Star Border
</StarBorder>
</div>
<TabbedLayout>
<template #preview>
<div class="demo-container overflow-hidden h-[400px]">
<StarBorder as="button" :color="color" :speed="speedProp" :thickness="thickness">Star Border</StarBorder>
</div>
<Customize>
<PreviewSelect title="Color" v-model="color" :options="colorOptions" />
<PreviewSlider title="Thickness" v-model="thickness" :min="0.5" :max="8" :step="0.5" value-unit="px" />
<PreviewSlider title="Speed" v-model="speed" :min="1" :max="10" :step="0.5" value-unit="s" />
</Customize>
<Customize>
<PreviewSelect title="Color" v-model="color" :options="colorOptions" />
<PreviewSlider title="Thickness" v-model="thickness" :min="0.5" :max="8" :step="0.5" value-unit="px" />
<PreviewSlider title="Speed" v-model="speed" :min="1" :max="10" :step="0.5" value-unit="s" />
</Customize>
<PropTable :data="propData" />
</template>
<PropTable :data="propData" />
</template>
<template #code>
<CodeExample :code-object="starBorder" />
</template>
<template #code>
<CodeExample :code-object="starBorder" />
</template>
<template #cli>
<CliInstallation :command="starBorder.cli" />
</template>
</TabbedLayout>
<template #cli>
<CliInstallation :command="starBorder.cli" />
</template>
</TabbedLayout>
</template>
<script setup lang="ts">
@@ -38,46 +36,50 @@ import PreviewSelect from '../../components/common/PreviewSelect.vue';
import StarBorder from '../../content/Animations/StarBorder/StarBorder.vue';
import { starBorder } from '@/constants/code/Animations/starBorderCode';
const thickness = ref<number>(3)
const speed = ref<number>(6)
const speedProp = ref<string>('6s')
const color = ref<string>('magenta')
const colorOptions = [{ label: 'Magenta', value: "magenta" }, { label: 'Cyan', value: "cyan" }, { label: 'white', value: "white" }]
const thickness = ref<number>(3);
const speed = ref<number>(6);
const speedProp = ref<string>('6s');
const color = ref<string>('magenta');
const colorOptions = [
{ label: 'Magenta', value: 'magenta' },
{ label: 'Cyan', value: 'cyan' },
{ label: 'white', value: 'white' }
];
watch(speed, () => {
speedProp.value = (speed.value).toString() + 's'
})
speedProp.value = speed.value.toString() + 's';
});
const propData = [
{
name: 'as',
type: 'string',
default: 'button',
description: 'Allows specifying the type of the parent component to be rendered.'
},
{
name: 'customClass',
type: 'string',
default: '',
description: 'Allows adding custom classes to the component.'
},
{
name: 'color',
type: 'string',
default: 'white',
description: 'Changes the main color of the border (fades to transparent)'
},
{
name: 'speed',
type: 'string',
default: '6s',
description: 'Changes the speed of the animation.'
},
{
name: 'thickness',
type: 'number',
default: '3',
description: 'Controls the thickness of the star border effect.'
}
{
name: 'as',
type: 'string',
default: 'button',
description: 'Allows specifying the type of the parent component to be rendered.'
},
{
name: 'customClass',
type: 'string',
default: '',
description: 'Allows adding custom classes to the component.'
},
{
name: 'color',
type: 'string',
default: 'white',
description: 'Changes the main color of the border (fades to transparent)'
},
{
name: 'speed',
type: 'string',
default: '6s',
description: 'Changes the speed of the animation.'
},
{
name: 'thickness',
type: 'number',
default: '3',
description: 'Controls the thickness of the star border effect.'
}
];
</script>

View File

@@ -31,21 +31,21 @@
</template>
<script setup lang="ts">
import { ref } from 'vue'
import TabbedLayout from '../../components/common/TabbedLayout.vue'
import PropTable from '../../components/common/PropTable.vue'
import CliInstallation from '../../components/code/CliInstallation.vue'
import CodeExample from '../../components/code/CodeExample.vue'
import Customize from '../../components/common/Customize.vue'
import PreviewSwitch from '@/components/common/PreviewSwitch.vue'
import AnimatedList from '../../content/Components/AnimatedList/AnimatedList.vue'
import { animatedList } from '../../constants/code/Components/animatedListCode'
import { useForceRerender } from '@/composables/useForceRerender'
import { ref } from 'vue';
import TabbedLayout from '../../components/common/TabbedLayout.vue';
import PropTable from '../../components/common/PropTable.vue';
import CliInstallation from '../../components/code/CliInstallation.vue';
import CodeExample from '../../components/code/CodeExample.vue';
import Customize from '../../components/common/Customize.vue';
import PreviewSwitch from '@/components/common/PreviewSwitch.vue';
import AnimatedList from '../../content/Components/AnimatedList/AnimatedList.vue';
import { animatedList } from '../../constants/code/Components/animatedListCode';
import { useForceRerender } from '@/composables/useForceRerender';
const { rerenderKey } = useForceRerender()
const showGradients = ref(true)
const enableArrowNavigation = ref(true)
const displayScrollbar = ref(true)
const { rerenderKey } = useForceRerender();
const showGradients = ref(true);
const enableArrowNavigation = ref(true);
const displayScrollbar = ref(true);
const propData = [
{
@@ -96,5 +96,5 @@ const propData = [
default: '-',
description: 'Emitted when an item is selected. Receives (item: string, index: number)'
}
]
</script>
];
</script>

View File

@@ -2,8 +2,7 @@
<TabbedLayout>
<template #preview>
<div class="demo-container">
<Folder :items="items" :size="size" :color="color">
</Folder>
<Folder :size="size" :color="color"></Folder>
</div>
<Customize>
@@ -37,7 +36,6 @@ import PreviewSlider from '@/components/common/PreviewSlider.vue';
import PropTable from '@/components/common/PropTable.vue';
import TabbedLayout from '@/components/common/TabbedLayout.vue';
const items = ['Doc 1', 'Doc 2', 'Doc 3'];
const color = ref('#5227FF');
const size = ref(2);
@@ -65,6 +63,6 @@ const propData = [
type: 'number',
default: '1',
description: 'Size multiplier for the folder.'
},
}
];
</script>
</script>