fix. [SWV-866] 액션버튼 기능 개선 (이미지 타입 추가)
Made-with: Cursor
This commit is contained in:
@@ -1,32 +1,45 @@
|
||||
<script setup lang="ts">
|
||||
interface props {
|
||||
<<<<<<< HEAD
|
||||
type?: 'button' | 'link'
|
||||
to?: string
|
||||
target?: '_self' | '_blank'
|
||||
=======
|
||||
type?: 'internal' | 'external' | 'action'
|
||||
href?: string
|
||||
>>>>>>> feature/20250228_SWV-866
|
||||
backgroundColor?: string
|
||||
srOnly?: string
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<props>(), {
|
||||
<<<<<<< HEAD
|
||||
type: 'button',
|
||||
to: '',
|
||||
target: '_self',
|
||||
=======
|
||||
type: 'action',
|
||||
>>>>>>> feature/20250228_SWV-866
|
||||
backgroundColor: '',
|
||||
srOnly: '',
|
||||
})
|
||||
|
||||
const componentTag = computed((): string => {
|
||||
switch (props.type) {
|
||||
case 'link':
|
||||
case 'internal':
|
||||
return 'AtomsLocaleLink'
|
||||
case 'external':
|
||||
return 'a'
|
||||
default:
|
||||
return 'button'
|
||||
}
|
||||
})
|
||||
const componentProps = computed(() => {
|
||||
switch (props.type) {
|
||||
case 'link':
|
||||
return { to: props.to, target: props.target }
|
||||
case 'internal':
|
||||
return { to: props.href, target: '_self' }
|
||||
case 'external':
|
||||
return { href: props.href, target: '_blank' }
|
||||
default:
|
||||
return {}
|
||||
}
|
||||
|
||||
87
layers/components/atoms/Button/Image.vue
Normal file
87
layers/components/atoms/Button/Image.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<script setup lang="ts">
|
||||
import type { ImageButtonType } from '#layers/types/components/button'
|
||||
|
||||
interface props {
|
||||
type?: ImageButtonType
|
||||
href?: string
|
||||
backgroundImage: string
|
||||
alt: string
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<props>(), {
|
||||
type: 'action',
|
||||
disabled: false,
|
||||
})
|
||||
|
||||
const componentTag = computed((): string => {
|
||||
switch (props.type) {
|
||||
case 'external':
|
||||
return 'a'
|
||||
case 'internal':
|
||||
return 'AtomsLocaleLink'
|
||||
default:
|
||||
return 'button'
|
||||
}
|
||||
})
|
||||
|
||||
const componentProps = computed(() => {
|
||||
if (props.type === 'external') {
|
||||
return {
|
||||
href: props.href,
|
||||
target: '_blank',
|
||||
}
|
||||
}
|
||||
|
||||
if (props.type === 'internal') {
|
||||
if (props.href) {
|
||||
return {
|
||||
to: props.href,
|
||||
target: '_self',
|
||||
}
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
return {}
|
||||
})
|
||||
const buttonStyle = computed(() => {
|
||||
return {
|
||||
backgroundImage: props.backgroundImage,
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<component
|
||||
:is="componentTag"
|
||||
v-bind="{ ...componentProps }"
|
||||
:class="['btn-base', { disabled: props.disabled }]"
|
||||
:style="buttonStyle"
|
||||
:disabled="props.disabled"
|
||||
>
|
||||
<img
|
||||
v-if="props.backgroundImage"
|
||||
:src="props.backgroundImage"
|
||||
:alt="props.alt"
|
||||
class="btn-bg"
|
||||
/>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.btn-base {
|
||||
@apply overflow-hidden relative h-[48px] md:h-[64px] rounded-[8px] md:rounded-[10px] cursor-pointer
|
||||
after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full after:bg-white after:transition-opacity after:duration-300 after:ease-in-out after:opacity-0
|
||||
hover:after:opacity-20;
|
||||
}
|
||||
|
||||
.btn-base.disabled {
|
||||
@apply cursor-default pointer-events-none
|
||||
after:opacity-20 after:z-[2];
|
||||
}
|
||||
|
||||
.btn-bg {
|
||||
@apply w-full h-full object-contain;
|
||||
}
|
||||
</style>
|
||||
@@ -2,23 +2,23 @@
|
||||
import type { TrackingObject } from '#layers/types/api/common'
|
||||
|
||||
interface Props {
|
||||
category?: 'system' | 'image'
|
||||
variant?: 'videoPlay' | 'videoPlayImg'
|
||||
backgroundColor?: string
|
||||
tracking: TrackingObject
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), { category: 'system' })
|
||||
const props = withDefaults(defineProps<Props>(), { variant: 'videoPlay' })
|
||||
|
||||
const { locale } = useI18n()
|
||||
const { sendLog } = useAnalytics()
|
||||
|
||||
const buttonClasses = computed(() => [
|
||||
'btn-play',
|
||||
props.category === 'system' ? 'play-icon' : 'play-image',
|
||||
props.variant === 'videoPlay' ? 'play-icon' : 'play-image',
|
||||
])
|
||||
|
||||
const buttonStyle = computed(() =>
|
||||
props.category === 'system' && props.backgroundColor
|
||||
props.variant === 'videoPlay' && props.backgroundColor
|
||||
? { backgroundColor: props.backgroundColor }
|
||||
: {}
|
||||
)
|
||||
@@ -28,7 +28,7 @@ const onClick = () => sendLog(locale.value, props.tracking)
|
||||
|
||||
<template>
|
||||
<button :class="buttonClasses" :style="buttonStyle" @click="onClick">
|
||||
<span v-if="props.category === 'system'" class="icon">
|
||||
<span v-if="props.variant === 'videoPlay'" class="icon">
|
||||
<AtomsIconsArrowRightFill />
|
||||
</span>
|
||||
<span class="sr-only">Play</span>
|
||||
@@ -37,12 +37,11 @@ const onClick = () => sendLog(locale.value, props.tracking)
|
||||
|
||||
<style scoped>
|
||||
.btn-play {
|
||||
@apply relative flex items-center justify-center;
|
||||
@apply relative flex items-center justify-center rounded-full w-[60px] h-[60px] md:w-[80px] md:h-[80px];
|
||||
}
|
||||
|
||||
.play-icon {
|
||||
@apply w-[60px] h-[60px] md:w-[80px] md:h-[80px] rounded-full
|
||||
before:content-[''] before:absolute before:top-0 before:left-0 before:w-full before:h-full before:border before:border-[rgba(255,255,255,0.5)] before:rounded-full
|
||||
@apply before:content-[''] before:absolute before:top-0 before:left-0 before:w-full before:h-full before:border before:border-[rgba(255,255,255,0.5)] before:rounded-full
|
||||
after:content-[''] after:absolute after:top-0 after:left-0 after:w-full after:h-full after:bg-white after:rounded-[50%] after:opacity-0 after:transition-opacity after:duration-300 after:ease-in-out
|
||||
hover:after:opacity-10;
|
||||
}
|
||||
@@ -54,16 +53,13 @@ const onClick = () => sendLog(locale.value, props.tracking)
|
||||
}
|
||||
|
||||
.play-image {
|
||||
@apply w-[69px] h-[69px] md:w-[110px] md:h-[110px];
|
||||
@apply overflow-hidden;
|
||||
}
|
||||
.play-image::before {
|
||||
@apply content-[''] absolute inset-0 z-0 bg-no-repeat bg-center bg-cover bg-[url(/images/common/btn_play/btn_default.png)] transition-opacity duration-300 ease-out;
|
||||
@apply content-[''] absolute inset-0 z-0 rounded-full bg-no-repeat bg-center bg-cover bg-[url(/images/common/btn_play/btn_default_m.png)] md:bg-[url(/images/common/btn_play/btn_default.png)];
|
||||
}
|
||||
.play-image::after {
|
||||
@apply content-[''] absolute inset-0 z-0 bg-no-repeat bg-center bg-cover bg-[url(/images/common/btn_play/btn_hover.png)] opacity-0 transition-opacity duration-300 ease-out;
|
||||
}
|
||||
.play-image:hover::before {
|
||||
@apply opacity-0;
|
||||
@apply content-[''] absolute inset-0 z-0 rounded-full bg-no-repeat bg-center bg-cover bg-[url(/images/common/btn_play/btn_hover_m.png)] md:bg-[url(/images/common/btn_play/btn_hover.png)] opacity-0 transition-opacity duration-300 ease-out;
|
||||
}
|
||||
.play-image:hover::after {
|
||||
@apply opacity-100;
|
||||
|
||||
@@ -5,12 +5,11 @@ interface props {
|
||||
type?: ButtonType
|
||||
size?: string
|
||||
variant?: ButtonVariant
|
||||
target?: '_self' | '_blank'
|
||||
href?: string
|
||||
backgroundColor?: string
|
||||
textColor?: string
|
||||
disabled?: boolean
|
||||
gradient?: boolean
|
||||
useGradient?: boolean
|
||||
useGameFont?: boolean
|
||||
}
|
||||
|
||||
@@ -21,7 +20,7 @@ const props = withDefaults(defineProps<props>(), {
|
||||
target: '_self',
|
||||
textColor: 'var(--alternative-02)',
|
||||
disabled: false,
|
||||
gradient: false,
|
||||
useGradient: false,
|
||||
useGameFont: false,
|
||||
})
|
||||
|
||||
@@ -31,21 +30,20 @@ const { fontFamily } = storeToRefs(gameDataStore)
|
||||
const componentTag = computed((): string => {
|
||||
switch (props.type) {
|
||||
case 'external':
|
||||
case 'link':
|
||||
return 'a'
|
||||
case 'download':
|
||||
return props.href ? 'a' : 'button'
|
||||
case 'internal':
|
||||
return props.href ? 'AtomsLocaleLink' : 'button'
|
||||
return 'AtomsLocaleLink'
|
||||
default:
|
||||
return 'button'
|
||||
}
|
||||
})
|
||||
const componentProps = computed(() => {
|
||||
if (props.type === 'external' || props.type === 'link') {
|
||||
if (props.type === 'external') {
|
||||
return {
|
||||
href: props.href,
|
||||
target: props.target,
|
||||
target: '_blank',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +51,7 @@ const componentProps = computed(() => {
|
||||
if (props.href) {
|
||||
return {
|
||||
to: props.href,
|
||||
target: '_self',
|
||||
}
|
||||
}
|
||||
return {}
|
||||
@@ -106,7 +105,8 @@ const textStyle = computed(() => {
|
||||
:style="buttonStyle"
|
||||
:disabled="props.disabled"
|
||||
>
|
||||
<i v-if="props.gradient" class="btn-gradient"></i>
|
||||
<!-- 그라데이션 -->
|
||||
<i v-if="props.useGradient" class="btn-gradient"></i>
|
||||
<span class="btn-content" :style="textStyle">
|
||||
<slot />
|
||||
<AtomsIconsLongArrowRightLine
|
||||
|
||||
Reference in New Issue
Block a user