Attention Seeker Button button
A button that really knows how to get your attention! ◝( ゚ ∀。)◟
Usage Examples
Basic Usage
When the mouse approaches the button, it rushes over. If it's not in the viewport, it squeezes to the edge to join the fun.
CodfishLong-term Freezer Resident
Welcome to the world's (self-proclaimed) most professional codfish introduction website. No influencer unboxings here — just codfish contemplating their life plan: 'Should I be pan-fried, deep-fried, or steamed?'
Codfish, the saltwater prodigy of the ocean world, transforms into the dream leading role in fish and chips once ashore. Its dream is simple — to one day become a crispy-on-the-outside, tender-on-the-inside cod fillet, rather than forever lying in the freezer as the background prop you ignore while shopping.
ID Card
Scientific name: Gadus morhua
Nickname: Cod, Fish & Chips Star
Habitat: Cold waters & Freezers
Personality Traits
- Gentle flavor, never steals the show
- Delicate texture, no bones — easy to get along with
- Pairs with any sauce — a social butterfly
Life Goals
- Become a photo-worthy main course
- Make it onto a nutritionist's recommended list
- Stop being mistaken for dory fish
View example source code
vue
<template>
<div class="w-full flex flex-col gap-4 border border-gray-200 rounded-xl p-6 shadow-sm">
<div class="flex flex-col gap-4">
<div class="flex items-center gap-2 text-xl font-bold">
<span>{{ t('name') }}</span>
<span class="border border-sky-100 rounded-full px-2 py-0.5 text-sm text-sky-600 font-normal">
{{ t('badge') }}
</span>
</div>
<div class="opacity-80">
{{ t('intro') }}
</div>
<div class="py-6 leading-relaxed opacity-80">
{{ t('description') }}
</div>
<div class="grid grid-cols-1 gap-4 text-sm md:grid-cols-3">
<div class="border border-slate-100 rounded-lg p-4">
<div class="text-xs font-semibold opacity-80">
{{ t('idCardTitle') }}
</div>
<div class="mt-1">
<div>{{ t('scientificName') }}<span class="text-xs font-mono">Gadus morhua</span></div>
<div>{{ t('nickname') }}</div>
<div>{{ t('habitat') }}</div>
</div>
</div>
<div class="border border-slate-100 rounded-lg p-4">
<div class="text-xs font-semibold opacity-80">
{{ t('personalityTitle') }}
</div>
<ul class="mt-1 list-disc list-inside space-y-1">
<li>{{ t('personality1') }}</li>
<li>{{ t('personality2') }}</li>
<li>{{ t('personality3') }}</li>
</ul>
</div>
<div class="border border-slate-100 rounded-lg p-4">
<div class="text-xs font-semibold opacity-80">
{{ t('goalsTitle') }}
</div>
<ul class="mt-1 list-disc list-inside space-y-1">
<li>{{ t('goal1') }}</li>
<li>{{ t('goal2') }}</li>
<li>{{ t('goal3') }}</li>
</ul>
</div>
</div>
</div>
<div class="mt-4 flex justify-center">
<btn-attention-seeker
:label="t('buyButton')"
:top-offset="topOffset"
z-index="19"
@click="handleClick"
/>
</div>
</div>
</template>
<script setup lang="ts">
import { useElementSize, useWindowSize } from '@vueuse/core'
import { computed, onMounted, reactive, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import BtnAttentionSeeker from '../btn-attention-seeker.vue'
const { t } = useI18n()
const windowSize = reactive(useWindowSize())
const navRef = ref<HTMLHeadElement>()
const localNavRef = ref<HTMLDivElement>()
onMounted(() => {
navRef.value = document.querySelector<HTMLHeadElement>('.VPNav') ?? undefined
localNavRef.value = document.querySelector<HTMLDivElement>('.VPLocalNav') ?? undefined
})
const navEl = reactive(useElementSize(navRef))
const localNavEl = reactive(useElementSize(localNavRef))
const topOffset = computed(() => {
if (windowSize.width < 960) {
return localNavEl.height ?? 0
}
return (navEl.height ?? 0) + (localNavEl.height ?? 0)
})
function handleClick() {
window.open('https://codlin.me', '_blank')
}
</script>How It Works
The button's carrier container (carrierRef) follows the mouse position, and when near the viewport boundaries, it squeezes to the edge to join the fun.
Source Code
API
Props
interface Info {
width: number;
height: number;
x: number;
y: number;
}
interface Props {
/** 按鈕內文字 */
label?: string;
/** 是否停用 */
disabled?: boolean;
/** 同 CSS z-index */
zIndex?: number | string;
/** 跟隨距離,當距離小於此值時開始跟隨 */
followDistance?: number | ((info: Info) => number);
/** 上方偏移量,避免被 header 遮擋 */
topOffset?: number;
/** 下方偏移量,避免被 footer 遮擋 */
bottomOffset?: number;
}Slots
defineSlots<{
/** 按鈕 */
default?: () => unknown;
}>()