feat: add cursor pointer style to buttons and toggle elements for better UX

This commit is contained in:
mahdiarghyani
2025-12-15 14:59:04 +03:30
parent d4cf695911
commit 010d8bd8ea
5 changed files with 26 additions and 18 deletions
+2 -2
View File
@@ -3,9 +3,9 @@
<!-- Nuxt UI Select-based language picker --> <!-- Nuxt UI Select-based language picker -->
<USelect v-model="model" :items="items" value-key="value" size="sm" color="primary" variant="soft" <USelect v-model="model" :items="items" value-key="value" size="sm" color="primary" variant="soft"
:highlight="false" arrow :trailing="true" placeholder="Language" :highlight="false" arrow :trailing="true" placeholder="Language"
class="px-1 w-[64px] sm:w-[78px] rounded-full ring-1 ring-gray-200/70 dark:ring-gray-700/60 backdrop-blur-md shadow-sm h-[25px] hover:ring-primary-500/50 hover:shadow-md transition-all duration-200" class="cursor-pointer px-1 w-[64px] sm:w-[78px] rounded-full ring-1 ring-gray-200/70 dark:ring-gray-700/60 backdrop-blur-md shadow-sm h-[25px] hover:ring-primary-500/50 hover:shadow-md transition-all duration-200"
:ui="{ :ui="{
base: 'rounded-full', base: 'rounded-full cursor-pointer',
trailingIcon: 'text-dimmed group-data-[state=open]:rotate-180 transition-transform duration-200', trailingIcon: 'text-dimmed group-data-[state=open]:rotate-180 transition-transform duration-200',
content: 'min-w-fit scale-fade-in' content: 'min-w-fit scale-fade-in'
}" :aria-label="t('nav.languageSelector')"> }" :aria-label="t('nav.languageSelector')">
+4 -1
View File
@@ -18,6 +18,7 @@
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<UTooltip :text="t('theme.mode.system')"> <UTooltip :text="t('theme.mode.system')">
<UButton :color="isModeActive('system') ? 'primary' : 'neutral'" variant="soft" size="sm" square <UButton :color="isModeActive('system') ? 'primary' : 'neutral'" variant="soft" size="sm" square
class="cursor-pointer"
:class="isModeActive('system') ? 'ring-1 ring-primary-400/40 bg-primary-500/10 dark:bg-primary-400/10' : ''" :class="isModeActive('system') ? 'ring-1 ring-primary-400/40 bg-primary-500/10 dark:bg-primary-400/10' : ''"
icon="i-twemoji-desktop-computer" :aria-label="t('theme.mode.system')" icon="i-twemoji-desktop-computer" :aria-label="t('theme.mode.system')"
@click="setMode($event, 'system')" /> @click="setMode($event, 'system')" />
@@ -25,12 +26,14 @@
<UTooltip :text="t('theme.mode.light')"> <UTooltip :text="t('theme.mode.light')">
<UButton :color="isModeActive('light') ? 'primary' : 'neutral'" variant="soft" size="sm" square <UButton :color="isModeActive('light') ? 'primary' : 'neutral'" variant="soft" size="sm" square
class="cursor-pointer"
:class="isModeActive('light') ? 'ring-1 ring-primary-400/40 bg-primary-500/10 dark:bg-primary-400/10' : ''" :class="isModeActive('light') ? 'ring-1 ring-primary-400/40 bg-primary-500/10 dark:bg-primary-400/10' : ''"
icon="i-twemoji-sun" :aria-label="t('theme.mode.light')" @click="setMode($event, 'light')" /> icon="i-twemoji-sun" :aria-label="t('theme.mode.light')" @click="setMode($event, 'light')" />
</UTooltip> </UTooltip>
<UTooltip :text="t('theme.mode.dark')"> <UTooltip :text="t('theme.mode.dark')">
<UButton :color="isModeActive('dark') ? 'primary' : 'neutral'" variant="soft" size="sm" square <UButton :color="isModeActive('dark') ? 'primary' : 'neutral'" variant="soft" size="sm" square
class="cursor-pointer"
:class="isModeActive('dark') ? 'ring-1 ring-primary-400/40 bg-primary-500/10 dark:bg-primary-400/10' : ''" :class="isModeActive('dark') ? 'ring-1 ring-primary-400/40 bg-primary-500/10 dark:bg-primary-400/10' : ''"
icon="i-twemoji-crescent-moon" :aria-label="t('theme.mode.dark')" @click="setMode($event, 'dark')" /> icon="i-twemoji-crescent-moon" :aria-label="t('theme.mode.dark')" @click="setMode($event, 'dark')" />
</UTooltip> </UTooltip>
@@ -44,7 +47,7 @@
<div class="grid grid-cols-3 gap-2"> <div class="grid grid-cols-3 gap-2">
<UButton v-for="p in primaryItems" :key="p.key" :color="isPrimaryActive(p.key) ? 'primary' : 'neutral'" <UButton v-for="p in primaryItems" :key="p.key" :color="isPrimaryActive(p.key) ? 'primary' : 'neutral'"
variant="soft" size="sm" variant="soft" size="sm"
:class="['justify-start', isPrimaryActive(p.key) ? 'ring-1 ring-primary-400/40 bg-primary-500/10 dark:bg-primary-400/10' : '']" :class="['cursor-pointer justify-start', isPrimaryActive(p.key) ? 'ring-1 ring-primary-400/40 bg-primary-500/10 dark:bg-primary-400/10' : '']"
:aria-label="`Primary: ${p.label}`" @click="setPrimary($event, p.key)"> :aria-label="`Primary: ${p.label}`" @click="setPrimary($event, p.key)">
<span class="inline-flex items-center gap-2"> <span class="inline-flex items-center gap-2">
<span class="size-3 rounded-full" :class="colorClassMap[p.key]" /> <span class="size-3 rounded-full" :class="colorClassMap[p.key]" />
+12 -7
View File
@@ -12,7 +12,8 @@
:class="[isActive('hero') ? activeClass : inactiveClass]" variant="soft" square icon="i-twemoji-house" :class="[isActive('hero') ? activeClass : inactiveClass]" variant="soft" square icon="i-twemoji-house"
:aria-label="t('nav.home')" @click="goTo('hero')" /> :aria-label="t('nav.home')" @click="goTo('hero')" />
</UTooltip> </UTooltip>
<button type="button" class="hidden lg:inline-flex text-sm font-medium transition-colors duration-200" <button type="button"
class="hidden lg:inline-flex cursor-pointer text-sm font-medium transition-colors duration-200"
:class="[isActive('hero') ? labelActiveClass : labelInactiveClass]" @click="goTo('hero')"> :class="[isActive('hero') ? labelActiveClass : labelInactiveClass]" @click="goTo('hero')">
{{ t('nav.home') }} {{ t('nav.home') }}
</button> </button>
@@ -25,7 +26,8 @@
:class="[isActive('skills') ? activeClass : inactiveClass]" variant="soft" square :class="[isActive('skills') ? activeClass : inactiveClass]" variant="soft" square
icon="i-twemoji-hammer-and-wrench" :aria-label="t('sections.skills')" @click="goTo('skills')" /> icon="i-twemoji-hammer-and-wrench" :aria-label="t('sections.skills')" @click="goTo('skills')" />
</UTooltip> </UTooltip>
<button type="button" class="hidden lg:inline-flex text-sm font-medium transition-colors duration-200" <button type="button"
class="hidden lg:inline-flex cursor-pointer text-sm font-medium transition-colors duration-200"
:class="[isActive('skills') ? labelActiveClass : labelInactiveClass]" @click="goTo('skills')"> :class="[isActive('skills') ? labelActiveClass : labelInactiveClass]" @click="goTo('skills')">
{{ t('sections.skills') }} {{ t('sections.skills') }}
</button> </button>
@@ -38,7 +40,8 @@
:class="[isActive('work') ? activeClass : inactiveClass]" variant="soft" square :class="[isActive('work') ? activeClass : inactiveClass]" variant="soft" square
icon="i-twemoji-briefcase" :aria-label="t('sections.work')" @click="goTo('work')" /> icon="i-twemoji-briefcase" :aria-label="t('sections.work')" @click="goTo('work')" />
</UTooltip> </UTooltip>
<button type="button" class="hidden lg:inline-flex text-sm font-medium transition-colors duration-200" <button type="button"
class="hidden lg:inline-flex cursor-pointer text-sm font-medium transition-colors duration-200"
:class="[isActive('work') ? labelActiveClass : labelInactiveClass]" @click="goTo('work')"> :class="[isActive('work') ? labelActiveClass : labelInactiveClass]" @click="goTo('work')">
{{ t('sections.work') }} {{ t('sections.work') }}
</button> </button>
@@ -51,7 +54,8 @@
:class="[isActive('projects') ? activeClass : inactiveClass]" variant="soft" square :class="[isActive('projects') ? activeClass : inactiveClass]" variant="soft" square
icon="i-twemoji-rocket" :aria-label="t('sections.projects')" @click="goTo('projects')" /> icon="i-twemoji-rocket" :aria-label="t('sections.projects')" @click="goTo('projects')" />
</UTooltip> </UTooltip>
<button type="button" class="hidden lg:inline-flex text-sm font-medium transition-colors duration-200" <button type="button"
class="hidden lg:inline-flex cursor-pointer text-sm font-medium transition-colors duration-200"
:class="[isActive('projects') ? labelActiveClass : labelInactiveClass]" @click="goTo('projects')"> :class="[isActive('projects') ? labelActiveClass : labelInactiveClass]" @click="goTo('projects')">
{{ t('sections.projects') }} {{ t('sections.projects') }}
</button> </button>
@@ -60,14 +64,15 @@
<!-- Blog --> <!-- Blog -->
<div class="flex items-center gap-1.5"> <div class="flex items-center gap-1.5">
<UTooltip :text="t('sections.blog')"> <UTooltip :text="t('sections.blog')">
<NuxtLink :to="localePath('/blog')"> <NuxtLink :to="localePath('/blog')" class="cursor-pointer">
<UButton class="cursor-pointer transition-all duration-200" <UButton class="cursor-pointer transition-all duration-200"
:class="[isBlogActive ? activeClass : inactiveClass]" variant="soft" square icon="i-twemoji-memo" :class="[isBlogActive ? activeClass : inactiveClass]" variant="soft" square icon="i-twemoji-memo"
:aria-label="t('sections.blog')" /> :aria-label="t('sections.blog')" />
</NuxtLink> </NuxtLink>
</UTooltip> </UTooltip>
<NuxtLink :to="localePath('/blog')"> <NuxtLink :to="localePath('/blog')" class="cursor-pointer">
<button type="button" class="hidden lg:inline-flex text-sm font-medium transition-colors duration-200" <button type="button"
class="hidden lg:inline-flex cursor-pointer text-sm font-medium transition-colors duration-200"
:class="[isBlogActive ? labelActiveClass : labelInactiveClass]"> :class="[isBlogActive ? labelActiveClass : labelInactiveClass]">
{{ t('sections.blog') }} {{ t('sections.blog') }}
</button> </button>
+2 -2
View File
@@ -11,7 +11,7 @@
class="ms-auto flex flex-row-reverse items-center gap-1 overflow-x-auto no-scrollbar whitespace-nowrap px-1 py-1 min-w-0" class="ms-auto flex flex-row-reverse items-center gap-1 overflow-x-auto no-scrollbar whitespace-nowrap px-1 py-1 min-w-0"
role="toolbar" aria-label="AI Stack group filters"> role="toolbar" aria-label="AI Stack group filters">
<UButton :icon="filterButtonIcon" size="xs" :variant="filterButtonVariant" :color="filterButtonColor" <UButton :icon="filterButtonIcon" size="xs" :variant="filterButtonVariant" :color="filterButtonColor"
class="filter-toggle rounded-full shrink-0 mx-1" class="filter-toggle cursor-pointer rounded-full shrink-0 mx-1"
:class="{ 'is-open': filtersOpen, 'has-selection': hasSelection }" :aria-label="filterButtonLabel" :class="{ 'is-open': filtersOpen, 'has-selection': hasSelection }" :aria-label="filterButtonLabel"
:aria-expanded="hasSelection ? undefined : filtersOpen" aria-controls="ai-group-filter-group" :aria-expanded="hasSelection ? undefined : filtersOpen" aria-controls="ai-group-filter-group"
@click="handlePrimaryAction" /> @click="handlePrimaryAction" />
@@ -23,7 +23,7 @@
<UTooltip :text="opt.label" :arrow="true" :delay-duration="0.5" <UTooltip :text="opt.label" :arrow="true" :delay-duration="0.5"
:content="{ side: 'bottom', sideOffset: 8, collisionPadding: 12 }"> :content="{ side: 'bottom', sideOffset: 8, collisionPadding: 12 }">
<UButton :icon="opt.icon" size="xs" :variant="isSelected(opt.value) ? 'solid' : 'soft'" <UButton :icon="opt.icon" size="xs" :variant="isSelected(opt.value) ? 'solid' : 'soft'"
color="primary" class="rounded-full shrink-0" :aria-pressed="isSelected(opt.value)" color="primary" class="cursor-pointer rounded-full shrink-0" :aria-pressed="isSelected(opt.value)"
:aria-label="`Filter by ${opt.label}`" :title="opt.label" @click="toggleGroup(opt.value)" /> :aria-label="`Filter by ${opt.label}`" :title="opt.label" @click="toggleGroup(opt.value)" />
</UTooltip> </UTooltip>
</div> </div>
+2 -2
View File
@@ -3,7 +3,7 @@
class="ms-auto flex flex-row-reverse items-center gap-1 overflow-x-auto no-scrollbar whitespace-nowrap px-1 py-1 min-w-0" class="ms-auto flex flex-row-reverse items-center gap-1 overflow-x-auto no-scrollbar whitespace-nowrap px-1 py-1 min-w-0"
role="toolbar" aria-label="Skill filters"> role="toolbar" aria-label="Skill filters">
<UButton :icon="filterButtonIcon" size="xs" :variant="filterButtonVariant" :color="filterButtonColor" <UButton :icon="filterButtonIcon" size="xs" :variant="filterButtonVariant" :color="filterButtonColor"
class="filter-toggle rounded-full shrink-0 mx-1" class="filter-toggle cursor-pointer rounded-full shrink-0 mx-1"
:class="{ 'is-open': filtersOpen, 'has-selection': hasSelection }" :aria-label="filterButtonLabel" :class="{ 'is-open': filtersOpen, 'has-selection': hasSelection }" :aria-label="filterButtonLabel"
:aria-expanded="hasSelection ? undefined : filtersOpen" aria-controls="skill-filter-group" :aria-expanded="hasSelection ? undefined : filtersOpen" aria-controls="skill-filter-group"
@click="handlePrimaryAction" /> @click="handlePrimaryAction" />
@@ -15,7 +15,7 @@
<UTooltip :text="meta(type).label" :arrow="true" :delay-duration="0.5" <UTooltip :text="meta(type).label" :arrow="true" :delay-duration="0.5"
:content="{ side: 'bottom', sideOffset: 8, collisionPadding: 12 }"> :content="{ side: 'bottom', sideOffset: 8, collisionPadding: 12 }">
<UButton :icon="meta(type).icon" size="xs" :variant="isSelected(type) ? 'solid' : 'soft'" color="primary" <UButton :icon="meta(type).icon" size="xs" :variant="isSelected(type) ? 'solid' : 'soft'" color="primary"
class="rounded-full shrink-0" :aria-pressed="isSelected(type)" class="cursor-pointer rounded-full shrink-0" :aria-pressed="isSelected(type)"
:aria-label="`Filter by ${meta(type).label}`" :title="meta(type).label" @click="toggle(type)" /> :aria-label="`Filter by ${meta(type).label}`" :title="meta(type).label" @click="toggle(type)" />
</UTooltip> </UTooltip>
</div> </div>