221 lines
8.6 KiB
Vue
221 lines
8.6 KiB
Vue
<template>
|
|
<footer id="footer" ref="footerRef" class="bg-black">
|
|
<div
|
|
class="inner relative max-w-7xl mx-auto px-5 md:px-10 py-4 text-[12px] text-gray-400 md:px-4 md:py-9 md:text-[12px]"
|
|
>
|
|
<div class="menu-area py-4 pb-4">
|
|
<ul class="flex items-center flex-wrap gap-x-6 gap-y-2">
|
|
<li
|
|
v-for="(footerMenuItem, index) in footerLinks"
|
|
:key="index"
|
|
class="text-[15px] text-white/50 md:tracking-[-0.5px] relative flex items-center"
|
|
>
|
|
<NuxtLink
|
|
:to="footerMenuItem.url"
|
|
:target="footerMenuItem.target"
|
|
:class="[
|
|
footerMenuItem.active === 'y' && 'text-white/50',
|
|
index === 2 && 'text-[#fff]',
|
|
'hover:text-gray-600 transition-colors',
|
|
]"
|
|
>
|
|
{{ footerMenuItem.title }}
|
|
</NuxtLink>
|
|
</li>
|
|
<li class="relative">
|
|
<button class="text-[15px] text-white/50 hover:text-gray-600 transition-colors" @click="toggleAgeRating">
|
|
{{ tm('Footer_AgeRating') }}
|
|
</button>
|
|
<div v-if="showAgeRating" class="game-rating-card absolute bottom-6 left-1 md:left-1/2 md:-translate-x-1/2 bg-[#383838] rounded-lg border border-white/30 w-[340px] mx-auto z-10">
|
|
<!-- 헤더 -->
|
|
<div class="px-6 py-4 rounded-t-lg flex justify-between items-center">
|
|
<h3 class="text-white text-base">{{ tm('Footer_AgeRating') }}</h3>
|
|
<button class="text-white hover:text-gray-300 transition-colors" @click="toggleAgeRating">
|
|
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 등급 아이콘 그리드 -->
|
|
<div class="px-6 pt-2 pb-6">
|
|
<!-- 아이콘은 52x60 사이즈 갭은 4px 4개씩 그리드 레이아웃 -->
|
|
<div class="grid grid-cols-4 gap-[4px] mb-4 max-w-[220px] justify-start items-start">
|
|
<!-- 19세 등급 -->
|
|
<div v-for="image in getGameRatingImage" :key="image" class="text-center">
|
|
<img :src="image" alt="게임이용등급안내" class="w-full h-full object-contain" />
|
|
</div>
|
|
<div v-for="image in getContentInfoImage" :key="image" class="text-center">
|
|
<img :src="image" alt="게임이용등급안내" class="w-full h-full object-contain" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 정보 테이블 -->
|
|
<div class="px-6 py-6 rounded-b-lg bg-[#A31639]">
|
|
<div class="space-y-2">
|
|
<div class="flex flex-start border-b border-white/10 pb-2">
|
|
<span class="text-white text-sm flex-1">{{ footerAgeRatingInfo[0] }}</span>
|
|
<span class="text-white text-sm flex-1">{{ footerData.game_rating_info.title }}</span>
|
|
</div>
|
|
<div class="flex flex-start border-b border-white/10 pb-2">
|
|
<span class="text-white text-sm flex-1">{{ footerAgeRatingInfo[1] }}</span>
|
|
<span class="text-white text-sm flex-1">{{ footerData.game_rating_info.rating_grade }}</span>
|
|
</div>
|
|
<div class="flex flex-start border-b border-white/10 pb-2">
|
|
<span class="text-white text-sm flex-1">{{ footerAgeRatingInfo[2] }}</span>
|
|
<span class="text-white text-sm flex-1">{{ footerData.game_rating_info.reg_no }}</span>
|
|
</div>
|
|
<div class="flex flex-start border-b border-white/10 pb-2">
|
|
<span class="text-white text-sm flex-1">{{ footerAgeRatingInfo[3] }}</span>
|
|
<span class="text-white text-sm flex-1">{{ footerData.game_rating_info.prod_date }}</span>
|
|
</div>
|
|
<div class="flex flex-start">
|
|
<span class="text-white text-sm flex-1">{{ footerAgeRatingInfo[4] }}</span>
|
|
<span class="text-white text-sm flex-1">{{ footerData.game_rating_info.rating_class_no }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="address-area mt-4 hidden sm:block">
|
|
<address class="not-italic text-white/50">
|
|
<div class="row my-1.5 leading-5">
|
|
<span
|
|
v-dompurify-html="tm('Footer_Address')"
|
|
class="text-[13px] [&_a]:cursor-pointer [&_a]:text-white/50 [&_a]:underline"
|
|
></span>
|
|
</div>
|
|
</address>
|
|
</div>
|
|
|
|
<div class="language-area static md:absolute bottom-7 right-10 text-white mt-5 md:mt-0 md:bottom-5.5 md:right-4">
|
|
<BlocksLanguageSwitcher />
|
|
</div>
|
|
|
|
<div class="mt-6 md:mt-6 hidden sm:block">
|
|
<div v-dompurify-html="tm('Footer_caution')" class="text-xs text-white/30"></div>
|
|
</div>
|
|
|
|
<div class="copyright-area mt-6 text-[13px] text-white/50 md:mt-4">
|
|
<span>{{ tm('Footer_Copyright') }}</span>
|
|
</div>
|
|
|
|
<div class="logo-area flex mt-6 md:mt-6">
|
|
<a
|
|
href="https://www.smilegate.com"
|
|
target="_blank"
|
|
class="smilegate"
|
|
>
|
|
<img
|
|
:src="getImageHost(`/local/template/l9/common/logo_smilegate.png`, { imageType: 'game' })"
|
|
alt="스마일게이트 로고"
|
|
class="w-auto h-auto"
|
|
/>
|
|
</a>
|
|
<a
|
|
v-if="setDevCi.dev_ci_yn"
|
|
:href="footerData.use_dev_ci_url ? setDevCi.dev_ci_img_path : '#'"
|
|
target="_blank"
|
|
class="nx3 ml-2.5 md:ml-4"
|
|
>
|
|
<img
|
|
:src="getImageHost(`${setDevCi.dev_ci_img_path}`, { imageType: 'game' })"
|
|
alt="CI"
|
|
class="block w-auto h-[22px]"
|
|
/>
|
|
</a>
|
|
</div>
|
|
|
|
|
|
</div>
|
|
</footer>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import type { FooterMenuItem, FooterData, DevCiConfig } from '#layers/types/Common'
|
|
|
|
// Configuration
|
|
const runtimeConfig = useRuntimeConfig()
|
|
const dataResourcesUrl = runtimeConfig.public.dataResourcesUrl as string
|
|
const multilingualFileName = 'test_common_template.json'
|
|
|
|
// Multilingual
|
|
const resultGetMultilingual = await useGetMultilingual({
|
|
baseApiUrl: dataResourcesUrl,
|
|
fileName: multilingualFileName,
|
|
})
|
|
const { tm }: any = useI18n({
|
|
useScope: 'local',
|
|
messages: Object(resultGetMultilingual?.value?.multilingual),
|
|
})
|
|
|
|
const gameDataStore = useGameDataStore()
|
|
const { gameData } = storeToRefs(gameDataStore)
|
|
// const path = ref<string>(`${staticUrl}/local/template/${gameData.value.s3_folder_name}`)
|
|
|
|
// 공통다국어 data
|
|
const footerLinks = computed((): FooterMenuItem[] => {
|
|
const menu = (tm as any)('Footer_Menu')
|
|
return Array.isArray(menu) ? menu as FooterMenuItem[] : []
|
|
})
|
|
const footerData = ref(gameData.value?.footer_json as unknown as FooterData)
|
|
const setDevCi = ref<DevCiConfig>({
|
|
dev_ci_yn: gameData.value?.footer_dev_ci_img_yn as boolean,
|
|
dev_ci_img_path: gameData.value?.footer_dev_ci_img_path as string,
|
|
})
|
|
|
|
///local/template/common/grades_age
|
|
const getGameRatingImage = computed((): string[] => {
|
|
const contentInfo = footerData.value.game_rating_info.rating_type.split(',')
|
|
const ageTypeMap: Record<string, string> = {
|
|
'12': 'Type12',
|
|
'15': 'Type15',
|
|
'19': 'Type19',
|
|
'all': 'TypeAll',
|
|
'e': 'TypeExempt'
|
|
}
|
|
return contentInfo.map(item => {
|
|
const type = ageTypeMap[item] || 'TypeTest'
|
|
return getImageHost(`/images/common/grades_age/${type}.svg`, { imageType: 'common' })
|
|
})
|
|
})
|
|
|
|
const getContentInfoImage = computed((): string[] => {
|
|
const contentInfo = footerData.value.game_rating_info.content_info.split(',')
|
|
contentInfo.pop()
|
|
|
|
const contentTypeMap: Record<string, string> = {
|
|
'1': 'Type-sexual',
|
|
'2': 'Type-fear',
|
|
'3': 'Type-inapposite',
|
|
'4': 'Type-drug',
|
|
'5': 'Type-crime',
|
|
'6': 'Type-speculation',
|
|
'7': 'Type-violence'
|
|
}
|
|
|
|
return contentInfo.map(item => {
|
|
const type = contentTypeMap[item]
|
|
return type ? getImageHost(`/images/common/grades_use/${type}.svg`, { imageType: 'common' }) : ''
|
|
}).filter(Boolean)
|
|
})
|
|
|
|
const showAgeRating = ref<boolean>(false)
|
|
const toggleAgeRating = (): void => {
|
|
showAgeRating.value = !showAgeRating.value
|
|
}
|
|
|
|
const footerAgeRatingInfo = computed((): string[] => {
|
|
const info = (tm as any)('Footer_AgeRating_Info')
|
|
return Array.isArray(info) ? info : []
|
|
})
|
|
|
|
</script>
|
|
|
|
<style scoped>
|
|
</style>
|