diff --git a/app/app.vue b/app/app.vue index 9fab093..3d3ba43 100644 --- a/app/app.vue +++ b/app/app.vue @@ -5,6 +5,14 @@ import LoadingLocal from '#layers/components/blocks/loading/Local.vue' import type { GameDataMetaTag, GameDataValue } from '#layers/types/api/gameData' const nuxtApp = useNuxtApp() +const { gtag, initialize } = useGtag() +const { gaId } = useGoogleAnalyticsId() +initialize(gaId.value) +gtag('event', 'screen_view', { + app_name: 'My App', + screen_name: 'Home' +}) + const gameDataStore = useGameDataStore() const { setGameData } = gameDataStore diff --git a/layers/composables/useAnalytics.ts b/layers/composables/useAnalytics.ts new file mode 100644 index 0000000..3156506 --- /dev/null +++ b/layers/composables/useAnalytics.ts @@ -0,0 +1,272 @@ +import * as amplitude from '@amplitude/analytics-browser' +import type { AnalyticsDetailType } from '../types/AnalyticsType' +import type { IdentityInfo, ActionInfo, MarketingInfo } from '../types/Stove81Plug' + +declare const svcLog: any +declare const twq: any +declare const ttq: any + +// target에 {XX1, XX2}와 같은 형태가 포함되어 있을 경우 options.clickItem으로부터 값 추출하여 세팅 +const findValueFromOption = (target: string, { options = {} }: any) => { + if (target.includes('{') && target.includes('}')) { + const strTargetClickItem = target.substring(target.indexOf('{') + 1, target.indexOf('}')) + + const arrTargetClickItem = strTargetClickItem.split(',') + const arrTargetClickItemValue = [] + + for (let targetClickItem of arrTargetClickItem) { + targetClickItem = targetClickItem.trim() + arrTargetClickItemValue.push(options.clickItem[targetClickItem]) + } + target = target.replaceAll(`{${strTargetClickItem}}`, arrTargetClickItemValue.join(',')) + } + return target +} + +/** + * Google Analytics 전송 + * + * @param {AnalyticsDetailType} analytics + * @param {object} options + */ +const sendGA = (analytics: AnalyticsDetailType, { options = {} }: any) => { + try { + const { gtag } = useGtag() + + const eventName = findValueFromOption(analytics.event || '', { options }) + const eventCategory = findValueFromOption(analytics.eventCategory || '', { options }) + const eventLocale = analytics.eventLocale || '' + + // GA 클릭 이벤트 명 뒤에 언어 값 추가 노출되도록 개발. ex) GNB_자유게시판_KO + const eventLabel = `${eventCategory}_${eventLocale}` + + gtag('set', 'cookie_domain', `${window?.location?.hostname || ''}`) // env 값으로 설정 시 쿠키 생성 안 돼서 window.location.hostname으로 설정 + gtag('set', 'cookie_expires', '0') // 0으로 설정 시 쿠키가 Session 기반 쿠키로 전환 + gtag('event', `${eventName}`, { + event_category: eventLabel + }) + } catch (e) { + console.error('[Exception] useAnalytics.sendGA: ', e) + } +} + +/** + * Stove Analytics(81 Plug) 전송 + * + * @param {AnalyticsDetailType} analytics + * @param {string} mcode + * @param {object} options + */ +const sendSA = (analytics: AnalyticsDetailType, { mcode = '', options = {} }: any) => { + try { + const runtimeConfig = useRuntimeConfig() + const gameNo = runtimeConfig.public.stoveGameNo + + const device = useDevice() + const deviceType = device.isDesktop ? 'pcweb' : 'mobileweb' + + const country = `${csrGetCountry()}` + const memberNo = `${csrGetStoveMemberNo()}` + + const actionType = analytics.actionType || '' + const logSourceType = analytics.logSourceType || '' + const viewArea = analytics.viewArea || '' + const viewType = analytics.viewType || '' + const clickArea = analytics.clickArea || '' + const clickSarea = findValueFromOption(analytics.clickSarea || '', { options }) + const eventLocale = analytics.eventLocale || '' + + const identityInfo: IdentityInfo = { + app_id: 'stove', + log_source_type: logSourceType, + country, + locale: eventLocale, + lang_cd: eventLocale, + member_no: memberNo, + channeling_cd: 'SO' + } + + const marketingInfo: MarketingInfo = { + marketing_code: mcode || '', + device_type: deviceType, + media_type: '', + media_page: '' + } + + let actionParam = {} + + if (actionType === 'view') { + actionParam = { + view_area: viewArea, + view_type: viewType, + view_info: { + game_no: gameNo, + lang_cd: eventLocale, + ...options?.viewInfo + } + } + } else if (actionType === 'click') { + actionParam = { + click_area: clickArea, + click_sarea: clickSarea, + click_item: { + game_no: gameNo, + lang_cd: eventLocale, + ...options?.clickItem + } + } + } + + const actionInfo: ActionInfo = { + action_type: actionType, + action_param: actionParam, + marketing_info: marketingInfo + } + + const amplitudeActionInfo = { + ...actionInfo, + url: `${location?.href || ''}`, + agent: `${navigator?.userAgent || ''}` + } + + const amplitudeActionParams: { + event_type: string + event_properties: ActionInfo & { url: string; agent: string } + } = { + event_type: actionType, + event_properties: amplitudeActionInfo + } + + svcLog.identity(identityInfo) + svcLog.action(actionInfo, {}, {}) // 81plug warning log 제거를 위해 2번째 인자부터 빈 객체 세팅 + amplitude.track(amplitudeActionParams) + } catch (e) { + console.error('[Exception] useAnalytics.sendSA: ', e) + } +} + +/** + * 기본 로그 일괄 전송 + * + * @param {string} locale + * @param {AnalyticsDetailType} analytics + */ +const sendLog = (locale: string, analytics: AnalyticsDetailType) => { + // 언어 코드 대문자 변환 + analytics.eventLocale = locale.toUpperCase() + + if (analytics) { + // GA 전송 : eventCategory 유무로 판별 + if (analytics.eventCategory && analytics.eventCategory !== '') { + sendGA(analytics, { options: analytics.options }) + } + // SA 전송 : actionType, logSourceType 유무로 판별 + if ( + analytics.actionType && + analytics.actionType !== '' && + analytics.logSourceType && + analytics.logSourceType !== '' + ) { + sendSA(analytics, { mcode: analytics.mcode, options: analytics.options }) + } + } +} + +/** + * Google Analytics 전송 (기본 이벤트만 전송) + * + * @param {string} gaEventName + */ +const sendGAEventOnly = (gaEventName: string) => { + try { + const { gtag } = useGtag() + + gtag('set', 'cookie_domain', `${window?.location?.hostname || ''}`) // env 값으로 설정 시 쿠키 생성 안 돼서 window.location.hostname으로 설정 + gtag('set', 'cookie_expires', '0') // 0으로 설정 시 쿠키가 Session 기반 쿠키로 전환 + gtag('event', `${gaEventName}`) + } catch (e) { + console.error('[Exception] useAnalytics.sendGAEventOnly: ', e) + } +} + +/** + * 메타 픽셀 전송 + * + * @param {string} fbEventName + * @description 수집 대상 페이지에 useHead({ meta: [loadMetaPixelMeta()] }) 선언 + */ +const sendMetaPixel = (fbEventName: string) => { + try { + const { $fbq } = useNuxtApp() + if (typeof $fbq === 'function') { + $fbq('trackCustom', fbEventName) + } + } catch (e) { + console.error('[Exception] useAnalytics.sendMetaPixel: ', e) + } +} + +/** + * X(트위터) 픽셀 전송 + * + * @param {string} twEventName + * @description 수집 대상 페이지에 useHead({ script: [loadTwitterPixelScript()] }) 선언 + */ +const sendTwitterPixel = (twEventName: string) => { + try { + twq('event', twEventName, {}) + } catch (e) { + console.error('[Exception] useAnalytics.sendTwitterPixel: ', e) + } +} + +/** + * 틱톡 픽셀 전송 + * + * @param {string} ttEventName + * @description 수집 대상 페이지에 onMounted(() => { loadTikTokPixelScript() }) 선언 + */ +const sendTiktokPixel = (ttEventName: string) => { + try { + ttq.track(ttEventName) + } catch (e) { + console.error('[Exception] useAnalytics.sendTiktokPixel: ', e) + } +} + +/** + * 마케팅 인텔리전스 팀 요청 마케팅 스크립트 일괄 전송 + * + * @param {string} gaEventName + * @param {string} fbEventName + * @param {string} twEventName + * @param {string} ttEventName + */ +const sendMarketingScript = ({ + gaEventName, + fbEventName, + twEventName, + ttEventName +}: { + gaEventName?: string + fbEventName?: string + twEventName?: string + ttEventName?: string +}) => { + if (gaEventName) { + sendGAEventOnly(gaEventName) + } + if (fbEventName) { + sendMetaPixel(fbEventName) + } + if (twEventName) { + sendTwitterPixel(twEventName) + } + if (ttEventName) { + sendTiktokPixel(ttEventName) + } +} + +export default () => { + return { sendGA, sendSA, sendLog, sendMarketingScript } +} diff --git a/layers/composables/useGoogleAnalyticsId.ts b/layers/composables/useGoogleAnalyticsId.ts new file mode 100644 index 0000000..a30652d --- /dev/null +++ b/layers/composables/useGoogleAnalyticsId.ts @@ -0,0 +1,19 @@ +export const useGoogleAnalyticsId = () => { + const nuxtApp = useNuxtApp() + + // SSR에서 context에서 가져오기 + const getGAIdFromServer = () => { + return import.meta.server + ? (nuxtApp.ssrContext?.event.context.googleAnalyticsId ?? null) + : null + } + + // useState로 SSR/CSR 상태 동기화 + const gaId = useState('googleAnalyticsId', () => { + return getGAIdFromServer() + }) + + return { + gaId + } +} diff --git a/layers/nuxt.config.ts b/layers/nuxt.config.ts index 5ba92bf..95adaae 100644 --- a/layers/nuxt.config.ts +++ b/layers/nuxt.config.ts @@ -9,5 +9,5 @@ export default defineNuxtConfig({ components: { dirs: ['components'], global: true, - }, + } }) diff --git a/layers/plugins/amplitude.client.ts b/layers/plugins/amplitude.client.ts new file mode 100644 index 0000000..d8377d3 --- /dev/null +++ b/layers/plugins/amplitude.client.ts @@ -0,0 +1,41 @@ +import * as amplitude from '@amplitude/analytics-browser' + +// Nuxt 플러그인 정의 +export default defineNuxtPlugin((nuxtApp) => { + // const { memberNo } = useAnalytics() as { memberNo: string } + const memberNo = csrGetStoveMemberNo() + + // Amplitude 초기화 + amplitude.init('6bfa2705264260f060e02493ecf882ad', { + // 원하는 설정을 여기에 추가하세요 + defaultTracking: { + attribution: false, // 기본 추적 설정: 속성 추적 비활성화 + pageViews: true, // 페이지 뷰 추적 활성화 + sessions: false, // 세션 추적 비활성화 + formInteractions: false, // 폼 상호작용 추적 비활성화 + fileDownloads: false // 파일 다운로드 추적 비활성화 + }, + autocapture: { + attribution: true + } + }) + + // Identify 이벤트 생성 및 설정 + const identifyEvent = new amplitude.Identify() + identifyEvent.set('member_no', memberNo) + + // Identify 이벤트 전송 및 사용자 ID 설정 + amplitude.identify(identifyEvent) + amplitude.setUserId(`${memberNo}`) + + ;(window as any).amplitude = amplitude // amplitude 객체 전역으로 설정(Stove GNB에서 사용) + + // 페이지가 숨겨질 때 이벤트 리스너 추가 + window.addEventListener('pagehide', () => { + amplitude.setTransport('beacon') // 전송 방식 설정 + amplitude.flush() // Amplitude 데이터 전송 + }) + + // Nuxt 앱에 amplitude 인스턴스 제공 + nuxtApp.provide('amplitude', amplitude) +}) diff --git a/layers/plugins/global-tracking.ts b/layers/plugins/global-tracking.ts new file mode 100644 index 0000000..b96f590 --- /dev/null +++ b/layers/plugins/global-tracking.ts @@ -0,0 +1,42 @@ +import type { AnalyticsDetailType } from '../types/AnalyticsType' + +export default defineNuxtPlugin((nuxtApp) => { + // 공통 함수 정의 + const createEventHandler = (eventName: string, sendFunction: Function) => { + return (el: any, binding: any) => { + const eventHandler = (event: Event) => { + const bindingValue = binding.value + if (bindingValue) { + sendFunction(bindingValue) + } + // 기존의 @click 핸들러 호출 + if (typeof binding.value === 'function') { + binding.value(event) + } + } + + el.addEventListener(eventName, eventHandler) + el[`__${eventName}EventHandler__`] = eventHandler + } + } + + const removeEventHandler = (eventName: string) => { + return (el: any) => { + if (el[`__${eventName}EventHandler__`]) { + el.removeEventListener(eventName, el[`__${eventName}EventHandler__`]) + delete el[`__${eventName}EventHandler__`] + } + } + } + + // analytics + nuxtApp.vueApp.directive('analytics', { + mounted: createEventHandler('click', (bindingValue: AnalyticsDetailType) => { + const { sendLog } = useAnalytics() + const i18n = nuxtApp.$i18n as { locale: { value: string } } + + sendLog(i18n.locale.value, bindingValue) + }), + beforeUnmount: removeEventHandler('click') + }) +}) diff --git a/layers/server/middleware/gameInfo.ts b/layers/server/middleware/gameInfo.ts index 013df7f..572f25a 100644 --- a/layers/server/middleware/gameInfo.ts +++ b/layers/server/middleware/gameInfo.ts @@ -60,6 +60,13 @@ export default defineEventHandler(async event => { query: queryParams, }) + const gaId = (response as any).value?.ga_code + + if (gaId) { + // 환경변수에 동적 설정 + event.context.googleAnalyticsId = gaId + } + // 타입 단언을 사용하여 response의 타입 오류를 해결 const res = response as { code?: number; value?: unknown } diff --git a/layers/types/AnalyticsType.ts b/layers/types/AnalyticsType.ts new file mode 100644 index 0000000..1a99b83 --- /dev/null +++ b/layers/types/AnalyticsType.ts @@ -0,0 +1,84 @@ +interface AnalyticsMetaType { + gameId: string + metaNo: number + metaType?: string + metaCode?: string + metaValue?: number + metaName?: string + metaOption?: string + metaDesc?: string + refMetaNo?: number + sort?: number + status?: boolean +} + +interface AnalyticsType { + analyticsNo: number + gameId: string + analyticsType?: AnalyticsMetaType + analyticsVersion?: AnalyticsMetaType + analyticsCode?: string + analyticsName?: string + analyticsDesc?: string + sort?: number + status?: boolean +} + +interface AnalyticsDetailType extends AnalyticsType { + detailNo: number + // analyticsNo in AnalyticsType + sbNo?: string + areaNo?: string + event?: string + eventCategory?: string + actionType?: string + areaNm?: string + clickAreaNm?: string + logSourceType?: string + // View ----- + viewArea?: string + viewType?: string + viewInfo?: string + // Click ----- + clickArea?: string + clickSarea?: string + gameNo?: string // Y/N + langCd?: string // Y/N + locale?: string // Y/N + memberNo?: string // Y/N + country?: string // Y/N + description?: string + clickItem?: string + opinion?: string + devOption?: string + // 가공 ----- + arrViewInfo?: String[] + mapClickItem?: Map + eventLocale?: string + // 옵션 ----- + mcode?: string + options?: object +} + +// [API] Req / Res ----- +interface ReqGetAnalytics { + baseApiUrl: string + fileName?: string +} + +interface ResGetAnalytics { + code: number + message: string + value?: { + analyticsDetail?: AnalyticsDetailType + } +} + +export type { + AnalyticsType, + AnalyticsDetailType, + AnalyticsMetaType, + // [API] Req / Res ----- + ReqGetAnalytics, + ResGetAnalytics +} diff --git a/layers/types/Stove81Plug.ts b/layers/types/Stove81Plug.ts new file mode 100644 index 0000000..1cdc79a --- /dev/null +++ b/layers/types/Stove81Plug.ts @@ -0,0 +1,38 @@ +export interface IdentityInfo { + app_id: string + log_source_type: string + country: string + locale: string + lang_cd: string + member_no: string + channeling_cd: string +} + +export interface ClickItem { + game_no: string +} + +export interface ActionParam { + click_area?: string + click_sarea?: string + click_item?: ClickItem + view_area?: string + view_type?: string + view_info?: { + game_no: string + lang_cd: string + } +} + +export interface MarketingInfo { + marketing_code: string + device_type: string + media_type: string + media_page: string +} + +export interface ActionInfo { + action_type: string + action_param: ActionParam + marketing_info?: MarketingInfo +} diff --git a/nuxt.config.ts b/nuxt.config.ts index de3a4d5..7a0106f 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -29,6 +29,8 @@ export default defineNuxtConfig({ '@nuxtjs/i18n', '@pinia/nuxt', '@nuxtjs/tailwindcss', + 'nuxt-gtag', + '@nuxtjs/device', ], imports: { dirs: [ diff --git a/package.json b/package.json index ccdf8ef..8a607b1 100644 --- a/package.json +++ b/package.json @@ -19,12 +19,16 @@ "check": "pnpm typecheck && pnpm lint && pnpm format:check" }, "dependencies": { + "@amplitude/analytics-browser": "^2.24.0", + "@amplitude/analytics-node": "^1.5.9", + "@nuxtjs/device": "^3.2.4", "@nuxtjs/i18n": "^10.0.6", "@pinia/nuxt": "^0.6.1", "@vueuse/core": "^13.6.0", "@vueuse/nuxt": "^13.6.0", "h3": "^1.15.4", "nuxt": "^4.0.3", + "nuxt-gtag": "^4.0.0", "pinia": "^2.3.1", "vue": "^3.5.0", "vue-dompurify-html": "^5.3.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8b024b..842630d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,15 @@ importers: .: dependencies: + '@amplitude/analytics-browser': + specifier: ^2.24.0 + version: 2.24.0 + '@amplitude/analytics-node': + specifier: ^1.5.9 + version: 1.5.9 + '@nuxtjs/device': + specifier: ^3.2.4 + version: 3.2.4 '@nuxtjs/i18n': specifier: ^10.0.6 version: 10.0.6(@vue/compiler-dom@3.5.21)(db0@0.3.2)(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(magicast@0.3.5)(rollup@4.50.0)(vue@3.5.21(typescript@5.9.2)) @@ -26,6 +35,9 @@ importers: nuxt: specifier: ^4.0.3 version: 4.1.1(@parcel/watcher@2.5.1)(@types/node@24.3.1)(@vue/compiler-sfc@3.5.21)(db0@0.3.2)(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.0)(terser@5.44.0)(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.7(typescript@5.9.2))(yaml@2.8.1) + nuxt-gtag: + specifier: ^4.0.0 + version: 4.0.0(magicast@0.3.5) pinia: specifier: ^2.3.1 version: 2.3.1(typescript@5.9.2)(vue@3.5.21(typescript@5.9.2)) @@ -97,6 +109,48 @@ packages: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} + '@amplitude/analytics-browser@2.24.0': + resolution: {integrity: sha512-tlr5V3WjIf+Lv9AMVPs5OBbDo6n9VWz2sKXap86jYlKgnZz6++AEYHVw88rC9i+OdXeqMOvhxgIK6hT2N/1M2A==} + + '@amplitude/analytics-client-common@2.3.41': + resolution: {integrity: sha512-yIzPSsf0DZQEU9TAR2ugfNtWRhuoGi+554qBBH/H3AzY/2TI3peuXmnmah8/cK/HdHg4dyln08/scRGL83Z8lg==} + + '@amplitude/analytics-connector@1.6.4': + resolution: {integrity: sha512-SpIv0IQMNIq6SH3UqFGiaZyGSc7PBZwRdq7lvP0pBxW8i4Ny+8zwI0pV+VMfMHQwWY3wdIbWw5WQphNjpdq1/Q==} + + '@amplitude/analytics-core@1.2.8': + resolution: {integrity: sha512-Krxpr5uvS3HmmjvpYqPfbMbs2kcZZu09L+6KwQnPiofWRzoXWIM217fRfy6aSD/QrAoPGbZjvtVitw9cB7Cx+A==} + + '@amplitude/analytics-core@2.24.0': + resolution: {integrity: sha512-hYjVIme2tpW+dgDVVAbgrpjTosgrAg2m3M5/kgXEObnitw36BPnwKL6d8EyJPsx5O+bRal5E0txIsu39I4LM2w==} + + '@amplitude/analytics-node@1.5.9': + resolution: {integrity: sha512-BTB7zrUOGhM8NRCYFdNas+9eIJtMitK0KZ55N+qnSc2HbiJBvGjx/pfnAdSeHpbts6jQ8075YIuCEIQw077RJA==} + + '@amplitude/analytics-remote-config@0.4.1': + resolution: {integrity: sha512-BYl6kQ9qjztrCACsugpxO+foLaQIC0aSEzoXEAb/gwOzInmqkyyI+Ub+aWTBih4xgB/lhWlOcidWHAmNiTJTNw==} + + '@amplitude/analytics-remote-config@0.6.3': + resolution: {integrity: sha512-icE0ogCzdHAtQi9jiOFQUmKrvWQc5YEO6bLZUfQXCT/yTTNXppWnT1zHMKzXa3SMDosfrLwU/X8sro1PTI+jZQ==} + + '@amplitude/analytics-types@1.4.0': + resolution: {integrity: sha512-RiMPHBqdrJ8ktTqG+Wzj2htnN/PCG9jGZG0SXtTFnWwVvcAJYbYm55/nrP1TTyrx1OlLhvF2VG3lVUP/xGAU8w==} + + '@amplitude/analytics-types@2.10.0': + resolution: {integrity: sha512-WP8eEbJh10MmFVnxkHjg92i5DBxBFsRvSZxjDQPXEGL8ZP+i7rSsleiH2K3VrwoKksYfZ/1eAqrZvevAmjSlig==} + + '@amplitude/plugin-autocapture-browser@1.12.2': + resolution: {integrity: sha512-Rs/GyQv8OsllNb1EzFvHYtys+2INkMEuy9aSMfJjN+/Hke87en9tVSTi+lQLe1aTCz5y+4fZ5V1+GOG65Xh5CA==} + + '@amplitude/plugin-network-capture-browser@1.6.0': + resolution: {integrity: sha512-KlnRkhchrbDMIEG+P+IuWg6c985rp2IbODVCrzNzHaX/DIN/N+xhPOh+ZZYoSKUsD2q70z6471A84lvB8CmZ3A==} + + '@amplitude/plugin-page-view-tracking-browser@2.3.47': + resolution: {integrity: sha512-rJSNt8DZUb0L6wKp6IHVur6qad4WreR7OnLnOdCou3Tv30F6x7KXQbW+pBJmuXDZkInkibeG7tAExRaXW80JUA==} + + '@amplitude/plugin-web-vitals-browser@0.1.0-frustrationanalytics.0': + resolution: {integrity: sha512-xv4sje6/D8r+SgNFTA22FJ5PhtdhN+VSydvs63Frll+qWlyQwaZ1IgDbPyqjzryEkldHRPD7GUaQual+geoIYg==} + '@antfu/install-pkg@1.1.0': resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==} @@ -666,6 +720,9 @@ packages: peerDependencies: vue: ^3.3.4 + '@nuxtjs/device@3.2.4': + resolution: {integrity: sha512-jIvN6QeodBNrUrL/1FCHk4bebsiLsGHlJd8c/m2ksLrGY4IZ0npA8IYhDTdYV92epGxoe8+3iZOzCjav+6TshQ==} + '@nuxtjs/i18n@10.0.6': resolution: {integrity: sha512-SQqJP6NDlmaoLzs7A74cx0Q3W4Vc+JSBlu3AN0q9+Q07Nvba5osab99GJEQ+PGnjaRwBFh35braUA2hRz9bdSA==} engines: {node: '>=20.11.1'} @@ -3378,6 +3435,9 @@ packages: nuxt-define@1.0.0: resolution: {integrity: sha512-CYZ2WjU+KCyCDVzjYUM4eEpMF0rkPmkpiFrybTqqQCRpUbPt2h3snswWIpFPXTi+osRCY6Og0W/XLAQgDL4FfQ==} + nuxt-gtag@4.0.0: + resolution: {integrity: sha512-7Mz8d3Cbrp2WsskJmzTsxO5lYpX7oVLsmsMQPInM+r0/8aGM1LnDnQYdFtTO+j7fsVhMuCa+XZyNrH43EKNfHA==} + nuxt@4.1.1: resolution: {integrity: sha512-xLDbWgz3ggAfUjcbmTzmLLPWOEB61thnjnqyasZlYyh/Ty2EDT1qvOiM9HT+9ycBxElI2DmyYewY8WOPRxWMiQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3964,6 +4024,9 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -4618,6 +4681,9 @@ packages: typescript: optional: true + web-vitals@5.1.0: + resolution: {integrity: sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -4726,6 +4792,83 @@ snapshots: '@alloc/quick-lru@5.2.0': {} + '@amplitude/analytics-browser@2.24.0': + dependencies: + '@amplitude/analytics-core': 2.24.0 + '@amplitude/analytics-remote-config': 0.4.1 + '@amplitude/plugin-autocapture-browser': 1.12.2 + '@amplitude/plugin-network-capture-browser': 1.6.0 + '@amplitude/plugin-page-view-tracking-browser': 2.3.47 + '@amplitude/plugin-web-vitals-browser': 0.1.0-frustrationanalytics.0 + tslib: 2.8.1 + + '@amplitude/analytics-client-common@2.3.41': + dependencies: + '@amplitude/analytics-connector': 1.6.4 + '@amplitude/analytics-core': 2.24.0 + '@amplitude/analytics-types': 2.10.0 + tslib: 2.8.1 + + '@amplitude/analytics-connector@1.6.4': {} + + '@amplitude/analytics-core@1.2.8': + dependencies: + '@amplitude/analytics-types': 1.4.0 + tslib: 2.8.1 + + '@amplitude/analytics-core@2.24.0': + dependencies: + '@amplitude/analytics-connector': 1.6.4 + tslib: 2.8.1 + + '@amplitude/analytics-node@1.5.9': + dependencies: + '@amplitude/analytics-core': 2.24.0 + tslib: 2.8.1 + + '@amplitude/analytics-remote-config@0.4.1': + dependencies: + '@amplitude/analytics-client-common': 2.3.41 + '@amplitude/analytics-core': 2.24.0 + '@amplitude/analytics-types': 2.10.0 + tslib: 2.8.1 + + '@amplitude/analytics-remote-config@0.6.3': + dependencies: + '@amplitude/analytics-core': 1.2.8 + '@amplitude/analytics-types': 1.4.0 + tslib: 2.8.1 + + '@amplitude/analytics-types@1.4.0': {} + + '@amplitude/analytics-types@2.10.0': {} + + '@amplitude/plugin-autocapture-browser@1.12.2': + dependencies: + '@amplitude/analytics-core': 2.24.0 + '@amplitude/analytics-remote-config': 0.6.3 + rxjs: 7.8.2 + tslib: 2.8.1 + + '@amplitude/plugin-network-capture-browser@1.6.0': + dependencies: + '@amplitude/analytics-core': 2.24.0 + rxjs: 7.8.2 + tslib: 2.8.1 + + '@amplitude/plugin-page-view-tracking-browser@2.3.47': + dependencies: + '@amplitude/analytics-client-common': 2.3.41 + '@amplitude/analytics-types': 2.10.0 + tslib: 2.8.1 + + '@amplitude/plugin-web-vitals-browser@0.1.0-frustrationanalytics.0': + dependencies: + '@amplitude/analytics-core': 2.24.0 + rxjs: 7.8.2 + tslib: 2.8.1 + web-vitals: 5.1.0 + '@antfu/install-pkg@1.1.0': dependencies: package-manager-detector: 1.3.0 @@ -5529,6 +5672,10 @@ snapshots: - vue-tsc - yaml + '@nuxtjs/device@3.2.4': + dependencies: + defu: 6.1.4 + '@nuxtjs/i18n@10.0.6(@vue/compiler-dom@3.5.21)(db0@0.3.2)(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(magicast@0.3.5)(rollup@4.50.0)(vue@3.5.21(typescript@5.9.2))': dependencies: '@intlify/core': 11.1.12 @@ -8223,6 +8370,15 @@ snapshots: nuxt-define@1.0.0: {} + nuxt-gtag@4.0.0(magicast@0.3.5): + dependencies: + '@nuxt/kit': 4.1.1(magicast@0.3.5) + defu: 6.1.4 + pathe: 2.0.3 + ufo: 1.6.1 + transitivePeerDependencies: + - magicast + nuxt@4.1.1(@parcel/watcher@2.5.1)(@types/node@24.3.1)(@vue/compiler-sfc@3.5.21)(db0@0.3.2)(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.0)(terser@5.44.0)(typescript@5.9.2)(vite@7.1.4(@types/node@24.3.1)(jiti@2.5.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.7(typescript@5.9.2))(yaml@2.8.1): dependencies: '@nuxt/cli': 3.28.0(magicast@0.3.5) @@ -8980,6 +9136,10 @@ snapshots: dependencies: queue-microtask: 1.2.3 + rxjs@7.8.2: + dependencies: + tslib: 2.8.1 + safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -9303,8 +9463,7 @@ snapshots: ts-interface-checker@0.1.13: {} - tslib@2.8.1: - optional: true + tslib@2.8.1: {} tsscmp@1.0.6: {} @@ -9688,6 +9847,8 @@ snapshots: optionalDependencies: typescript: 5.9.2 + web-vitals@5.1.0: {} + webidl-conversions@3.0.1: {} webpack-virtual-modules@0.6.2: {} diff --git a/public/images/GR_GALLERY_01/ko/bg01.jpg b/public/images/GR_DETAIL_01/common/bg01.jpg similarity index 100% rename from public/images/GR_GALLERY_01/ko/bg01.jpg rename to public/images/GR_DETAIL_01/common/bg01.jpg diff --git a/public/images/GR_GALLERY_01/ko/bg01_m.jpg b/public/images/GR_DETAIL_01/common/bg01_m.jpg similarity index 100% rename from public/images/GR_GALLERY_01/ko/bg01_m.jpg rename to public/images/GR_DETAIL_01/common/bg01_m.jpg diff --git a/public/images/GR_DETAIL_01/common/bg02.jpg b/public/images/GR_DETAIL_01/common/bg02.jpg new file mode 100644 index 0000000..4250e0a Binary files /dev/null and b/public/images/GR_DETAIL_01/common/bg02.jpg differ diff --git a/public/images/GR_VISUAL_03/common/bg02_m.jpg b/public/images/GR_DETAIL_01/common/bg02_m.jpg similarity index 100% rename from public/images/GR_VISUAL_03/common/bg02_m.jpg rename to public/images/GR_DETAIL_01/common/bg02_m.jpg diff --git a/public/images/GR_DETAIL_01/common/bg03.jpg b/public/images/GR_DETAIL_01/common/bg03.jpg new file mode 100644 index 0000000..4250e0a Binary files /dev/null and b/public/images/GR_DETAIL_01/common/bg03.jpg differ diff --git a/public/images/GR_VISUAL_03/common/bg03_m.jpg b/public/images/GR_DETAIL_01/common/bg03_m.jpg similarity index 100% rename from public/images/GR_VISUAL_03/common/bg03_m.jpg rename to public/images/GR_DETAIL_01/common/bg03_m.jpg diff --git a/public/images/GR_GALLERY_01/ko/bgVideo01.mp4 b/public/images/GR_DETAIL_01/common/bgVideo01.mp4 similarity index 100% rename from public/images/GR_GALLERY_01/ko/bgVideo01.mp4 rename to public/images/GR_DETAIL_01/common/bgVideo01.mp4 diff --git a/public/images/GR_DETAIL_01/common/bgVideo02.mp4 b/public/images/GR_DETAIL_01/common/bgVideo02.mp4 new file mode 100644 index 0000000..6e984e1 Binary files /dev/null and b/public/images/GR_DETAIL_01/common/bgVideo02.mp4 differ diff --git a/public/images/GR_DETAIL_02/common/bg01.jpg b/public/images/GR_DETAIL_02/common/bg01.jpg new file mode 100644 index 0000000..83a4714 Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bg01.jpg differ diff --git a/public/images/GR_DETAIL_02/common/bg01_m.jpg b/public/images/GR_DETAIL_02/common/bg01_m.jpg new file mode 100644 index 0000000..30a84dc Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bg01_m.jpg differ diff --git a/public/images/GR_DETAIL_02/common/bg01_thumb.png b/public/images/GR_DETAIL_02/common/bg01_thumb.png new file mode 100644 index 0000000..6486c11 Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bg01_thumb.png differ diff --git a/public/images/GR_DETAIL_02/common/bg02.jpg b/public/images/GR_DETAIL_02/common/bg02.jpg new file mode 100644 index 0000000..4250e0a Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bg02.jpg differ diff --git a/public/images/GR_DETAIL_02/common/bg02_m.jpg b/public/images/GR_DETAIL_02/common/bg02_m.jpg new file mode 100644 index 0000000..30a84dc Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bg02_m.jpg differ diff --git a/public/images/GR_DETAIL_02/common/bg02_thumb.png b/public/images/GR_DETAIL_02/common/bg02_thumb.png new file mode 100644 index 0000000..6486c11 Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bg02_thumb.png differ diff --git a/public/images/GR_DETAIL_02/common/bg03.jpg b/public/images/GR_DETAIL_02/common/bg03.jpg new file mode 100644 index 0000000..4250e0a Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bg03.jpg differ diff --git a/public/images/GR_DETAIL_02/common/bg03_m.jpg b/public/images/GR_DETAIL_02/common/bg03_m.jpg new file mode 100644 index 0000000..30a84dc Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bg03_m.jpg differ diff --git a/public/images/GR_DETAIL_02/common/bg03_thumb.png b/public/images/GR_DETAIL_02/common/bg03_thumb.png new file mode 100644 index 0000000..6486c11 Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bg03_thumb.png differ diff --git a/public/images/GR_DETAIL_02/common/bgVideo01.mp4 b/public/images/GR_DETAIL_02/common/bgVideo01.mp4 new file mode 100644 index 0000000..6e984e1 Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bgVideo01.mp4 differ diff --git a/public/images/GR_DETAIL_02/common/bgVideo02.mp4 b/public/images/GR_DETAIL_02/common/bgVideo02.mp4 new file mode 100644 index 0000000..6e984e1 Binary files /dev/null and b/public/images/GR_DETAIL_02/common/bgVideo02.mp4 differ diff --git a/public/images/GR_DETAIL_03/common/bg01.jpg b/public/images/GR_DETAIL_03/common/bg01.jpg new file mode 100644 index 0000000..403118e Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bg01.jpg differ diff --git a/public/images/GR_DETAIL_03/common/bg01_m.jpg b/public/images/GR_DETAIL_03/common/bg01_m.jpg new file mode 100644 index 0000000..ba2229c Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bg01_m.jpg differ diff --git a/public/images/GR_DETAIL_03/common/bg01_thumb.png b/public/images/GR_DETAIL_03/common/bg01_thumb.png new file mode 100644 index 0000000..05cae24 Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bg01_thumb.png differ diff --git a/public/images/GR_DETAIL_03/common/bg02.jpg b/public/images/GR_DETAIL_03/common/bg02.jpg new file mode 100644 index 0000000..4250e0a Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bg02.jpg differ diff --git a/public/images/GR_DETAIL_03/common/bg02_m.jpg b/public/images/GR_DETAIL_03/common/bg02_m.jpg new file mode 100644 index 0000000..30a84dc Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bg02_m.jpg differ diff --git a/public/images/GR_DETAIL_03/common/bg02_thumb.png b/public/images/GR_DETAIL_03/common/bg02_thumb.png new file mode 100644 index 0000000..05cae24 Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bg02_thumb.png differ diff --git a/public/images/GR_DETAIL_03/common/bg03.jpg b/public/images/GR_DETAIL_03/common/bg03.jpg new file mode 100644 index 0000000..4250e0a Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bg03.jpg differ diff --git a/public/images/GR_DETAIL_03/common/bg03_m.jpg b/public/images/GR_DETAIL_03/common/bg03_m.jpg new file mode 100644 index 0000000..30a84dc Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bg03_m.jpg differ diff --git a/public/images/GR_DETAIL_03/common/bg03_thumb.png b/public/images/GR_DETAIL_03/common/bg03_thumb.png new file mode 100644 index 0000000..05cae24 Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bg03_thumb.png differ diff --git a/public/images/GR_DETAIL_03/common/bgVideo01.mp4 b/public/images/GR_DETAIL_03/common/bgVideo01.mp4 new file mode 100644 index 0000000..6e984e1 Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bgVideo01.mp4 differ diff --git a/public/images/GR_DETAIL_03/common/bgVideo02.mp4 b/public/images/GR_DETAIL_03/common/bgVideo02.mp4 new file mode 100644 index 0000000..6e984e1 Binary files /dev/null and b/public/images/GR_DETAIL_03/common/bgVideo02.mp4 differ diff --git a/public/images/GR_GALLERY_01/ko/img_slide01.png b/public/images/GR_GALLERY_01/ko/img_slide01.png new file mode 100644 index 0000000..b5242d6 Binary files /dev/null and b/public/images/GR_GALLERY_01/ko/img_slide01.png differ diff --git a/public/images/GR_GALLERY_01/ko/img_slide02.png b/public/images/GR_GALLERY_01/ko/img_slide02.png new file mode 100644 index 0000000..295e4bb Binary files /dev/null and b/public/images/GR_GALLERY_01/ko/img_slide02.png differ diff --git a/public/images/GR_GALLERY_01/ko/img_slide03.png b/public/images/GR_GALLERY_01/ko/img_slide03.png new file mode 100644 index 0000000..b40a163 Binary files /dev/null and b/public/images/GR_GALLERY_01/ko/img_slide03.png differ diff --git a/public/images/GR_GALLERY_01/zh-tw/img_slide01.png b/public/images/GR_GALLERY_01/zh-tw/img_slide01.png new file mode 100644 index 0000000..b5242d6 Binary files /dev/null and b/public/images/GR_GALLERY_01/zh-tw/img_slide01.png differ diff --git a/public/images/GR_GALLERY_01/zh-tw/img_slide02.png b/public/images/GR_GALLERY_01/zh-tw/img_slide02.png new file mode 100644 index 0000000..295e4bb Binary files /dev/null and b/public/images/GR_GALLERY_01/zh-tw/img_slide02.png differ diff --git a/public/images/GR_GALLERY_01/zh-tw/img_slide03.png b/public/images/GR_GALLERY_01/zh-tw/img_slide03.png new file mode 100644 index 0000000..b40a163 Binary files /dev/null and b/public/images/GR_GALLERY_01/zh-tw/img_slide03.png differ diff --git a/public/images/GR_GALLERY_02/common/bg01.jpg b/public/images/GR_GALLERY_02/common/bg01.jpg new file mode 100644 index 0000000..4250e0a Binary files /dev/null and b/public/images/GR_GALLERY_02/common/bg01.jpg differ diff --git a/public/images/GR_VISUAL_03/common/bg01_m.jpg b/public/images/GR_GALLERY_02/common/bg01_m.jpg similarity index 100% rename from public/images/GR_VISUAL_03/common/bg01_m.jpg rename to public/images/GR_GALLERY_02/common/bg01_m.jpg diff --git a/public/images/GR_GALLERY_02/common/bgVideo01.mp4 b/public/images/GR_GALLERY_02/common/bgVideo01.mp4 new file mode 100644 index 0000000..6e984e1 Binary files /dev/null and b/public/images/GR_GALLERY_02/common/bgVideo01.mp4 differ diff --git a/public/images/GR_GALLERY_02/ko/img_slide01.png b/public/images/GR_GALLERY_02/ko/img_slide01.png new file mode 100644 index 0000000..352df50 Binary files /dev/null and b/public/images/GR_GALLERY_02/ko/img_slide01.png differ diff --git a/public/images/GR_GALLERY_02/ko/img_slide02.png b/public/images/GR_GALLERY_02/ko/img_slide02.png new file mode 100644 index 0000000..352df50 Binary files /dev/null and b/public/images/GR_GALLERY_02/ko/img_slide02.png differ diff --git a/public/images/GR_GALLERY_02/ko/img_slide03.png b/public/images/GR_GALLERY_02/ko/img_slide03.png new file mode 100644 index 0000000..352df50 Binary files /dev/null and b/public/images/GR_GALLERY_02/ko/img_slide03.png differ diff --git a/public/images/GR_GALLERY_02/zh-tw/img_slide01.png b/public/images/GR_GALLERY_02/zh-tw/img_slide01.png new file mode 100644 index 0000000..352df50 Binary files /dev/null and b/public/images/GR_GALLERY_02/zh-tw/img_slide01.png differ diff --git a/public/images/GR_GALLERY_02/zh-tw/img_slide02.png b/public/images/GR_GALLERY_02/zh-tw/img_slide02.png new file mode 100644 index 0000000..352df50 Binary files /dev/null and b/public/images/GR_GALLERY_02/zh-tw/img_slide02.png differ diff --git a/public/images/GR_GALLERY_02/zh-tw/img_slide03.png b/public/images/GR_GALLERY_02/zh-tw/img_slide03.png new file mode 100644 index 0000000..352df50 Binary files /dev/null and b/public/images/GR_GALLERY_02/zh-tw/img_slide03.png differ diff --git a/public/images/GR_GALLERY_03/common/bg01.jpg b/public/images/GR_GALLERY_03/common/bg01.jpg new file mode 100644 index 0000000..4250e0a Binary files /dev/null and b/public/images/GR_GALLERY_03/common/bg01.jpg differ diff --git a/public/images/GR_GALLERY_03/common/bg01_m.jpg b/public/images/GR_GALLERY_03/common/bg01_m.jpg new file mode 100644 index 0000000..6c6e2d8 Binary files /dev/null and b/public/images/GR_GALLERY_03/common/bg01_m.jpg differ diff --git a/public/images/GR_GALLERY_03/common/bgVideo01.mp4 b/public/images/GR_GALLERY_03/common/bgVideo01.mp4 new file mode 100644 index 0000000..6e984e1 Binary files /dev/null and b/public/images/GR_GALLERY_03/common/bgVideo01.mp4 differ diff --git a/public/images/GR_GALLERY_03/ko/img_slide01.png b/public/images/GR_GALLERY_03/ko/img_slide01.png new file mode 100644 index 0000000..2e4791e Binary files /dev/null and b/public/images/GR_GALLERY_03/ko/img_slide01.png differ diff --git a/public/images/GR_GALLERY_03/ko/img_slide02.png b/public/images/GR_GALLERY_03/ko/img_slide02.png new file mode 100644 index 0000000..2e4791e Binary files /dev/null and b/public/images/GR_GALLERY_03/ko/img_slide02.png differ diff --git a/public/images/GR_GALLERY_03/ko/img_slide03.png b/public/images/GR_GALLERY_03/ko/img_slide03.png new file mode 100644 index 0000000..2e4791e Binary files /dev/null and b/public/images/GR_GALLERY_03/ko/img_slide03.png differ diff --git a/public/images/GR_GALLERY_03/zh-tw/img_slide01.png b/public/images/GR_GALLERY_03/zh-tw/img_slide01.png new file mode 100644 index 0000000..2e4791e Binary files /dev/null and b/public/images/GR_GALLERY_03/zh-tw/img_slide01.png differ diff --git a/public/images/GR_GALLERY_03/zh-tw/img_slide02.png b/public/images/GR_GALLERY_03/zh-tw/img_slide02.png new file mode 100644 index 0000000..2e4791e Binary files /dev/null and b/public/images/GR_GALLERY_03/zh-tw/img_slide02.png differ diff --git a/public/images/GR_GALLERY_03/zh-tw/img_slide03.png b/public/images/GR_GALLERY_03/zh-tw/img_slide03.png new file mode 100644 index 0000000..2e4791e Binary files /dev/null and b/public/images/GR_GALLERY_03/zh-tw/img_slide03.png differ diff --git a/public/images/GR_VISUAL_01/common/bg01_m.jpg b/public/images/GR_VISUAL_01/common/bg01_m.jpg index 85dd350..169d11c 100644 Binary files a/public/images/GR_VISUAL_01/common/bg01_m.jpg and b/public/images/GR_VISUAL_01/common/bg01_m.jpg differ diff --git a/public/images/GR_VISUAL_02/common/bg01_m.jpg b/public/images/GR_VISUAL_02/common/bg01_m.jpg index 85dd350..182d717 100644 Binary files a/public/images/GR_VISUAL_02/common/bg01_m.jpg and b/public/images/GR_VISUAL_02/common/bg01_m.jpg differ diff --git a/public/images/GR_VISUAL_03/common/bg01.jpg b/public/images/GR_VISUAL_03/common/bg01.jpg index 4250e0a..2fd9b4e 100644 Binary files a/public/images/GR_VISUAL_03/common/bg01.jpg and b/public/images/GR_VISUAL_03/common/bg01.jpg differ diff --git a/public/images/common/btn_logo-apple.svg b/public/images/common/btn_logo-apple.svg new file mode 100644 index 0000000..6baf4fd --- /dev/null +++ b/public/images/common/btn_logo-apple.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/images/common/btn_logo-google.svg b/public/images/common/btn_logo-google.svg new file mode 100644 index 0000000..fc39dd0 --- /dev/null +++ b/public/images/common/btn_logo-google.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/images/common/btn_logo-pc.svg b/public/images/common/btn_logo-pc.svg new file mode 100644 index 0000000..155cb8a --- /dev/null +++ b/public/images/common/btn_logo-pc.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/public/images/common/ic-v2-logo-apple-fill.svg b/public/images/common/ic-v2-logo-apple-fill.svg new file mode 100644 index 0000000..d80a7f0 --- /dev/null +++ b/public/images/common/ic-v2-logo-apple-fill.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/images/common/ic-v2-logo-google-playstore-color.svg b/public/images/common/ic-v2-logo-google-playstore-color.svg new file mode 100644 index 0000000..201f547 --- /dev/null +++ b/public/images/common/ic-v2-logo-google-playstore-color.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/public/images/common/ic-v2-logo-window-fill.svg b/public/images/common/ic-v2-logo-window-fill.svg new file mode 100644 index 0000000..1c5fccb --- /dev/null +++ b/public/images/common/ic-v2-logo-window-fill.svg @@ -0,0 +1,6 @@ + + + + + +