feat. 게임 컬러 루트에 동적으로 적용
This commit is contained in:
10
app/app.vue
10
app/app.vue
@@ -13,12 +13,14 @@ import { useNuxtApp } from 'nuxt/app'
|
|||||||
import LoadingFull from '#layers/components/blocks/loading/Full.vue'
|
import LoadingFull from '#layers/components/blocks/loading/Full.vue'
|
||||||
import LoadingLocal from '#layers/components/blocks/loading/Local.vue'
|
import LoadingLocal from '#layers/components/blocks/loading/Local.vue'
|
||||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
||||||
|
import { useGameColors } from '#layers/composables/useGameColors'
|
||||||
import type { GameDataMetaTag, GameDataValue } from '#layers/types/api/gameData'
|
import type { GameDataMetaTag, GameDataValue } from '#layers/types/api/gameData'
|
||||||
|
|
||||||
const nuxtApp = useNuxtApp()
|
const nuxtApp = useNuxtApp()
|
||||||
const getGameData = ref<GameDataValue | null>(null)
|
const getGameData = ref<GameDataValue | null>(null)
|
||||||
const metaData = ref<GameDataMetaTag | null>(null)
|
const metaData = ref<GameDataMetaTag | null>(null)
|
||||||
const { setGameData } = useGameDataStore()
|
const { setGameData } = useGameDataStore()
|
||||||
|
const { applyGameColors } = useGameColors()
|
||||||
|
|
||||||
// SSR에서만 접근 가능
|
// SSR에서만 접근 가능
|
||||||
const gameDataFromServer = import.meta.server
|
const gameDataFromServer = import.meta.server
|
||||||
@@ -30,6 +32,14 @@ if (gameDataFromServer) {
|
|||||||
setGameData(gameDataFromServer)
|
setGameData(gameDataFromServer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (import.meta.client) {
|
||||||
|
const gameDataStore = useGameDataStore()
|
||||||
|
|
||||||
|
if (gameDataStore.gameData?.key_color_codes) {
|
||||||
|
applyGameColors(gameDataStore.gameData.key_color_codes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const meta = gameDataFromServer?.meta_tag ?? null
|
const meta = gameDataFromServer?.meta_tag ?? null
|
||||||
const theme = gameDataFromServer?.design_theme === 1 ? 'dark' : 'light'
|
const theme = gameDataFromServer?.design_theme === 1 ? 'dark' : 'light'
|
||||||
|
|
||||||
|
|||||||
@@ -8,13 +8,6 @@
|
|||||||
--foreground-reversal-30: #ebebeb; /* gray-80 */
|
--foreground-reversal-30: #ebebeb; /* gray-80 */
|
||||||
--foreground-reversal-40: rgba(0, 0, 0, 0.4);
|
--foreground-reversal-40: rgba(0, 0, 0, 0.4);
|
||||||
--foreground-reversal-70: #666666; /* gray-700 */
|
--foreground-reversal-70: #666666; /* gray-700 */
|
||||||
|
|
||||||
/* 게임별 동적 색상 기본값 */
|
|
||||||
--game-primary: transparent;
|
|
||||||
--game-alternative-01: transparent;
|
|
||||||
--game-alternative-02: transparent;
|
|
||||||
--game-text-primary: transparent;
|
|
||||||
--game-text-secondary: transparent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 다크 테마 색상 */
|
/* 다크 테마 색상 */
|
||||||
@@ -27,13 +20,6 @@
|
|||||||
--foreground-reversal-30: #404040; /* gray-750 */
|
--foreground-reversal-30: #404040; /* gray-750 */
|
||||||
--foreground-reversal-40: rgba(255, 255, 255, 0.4);
|
--foreground-reversal-40: rgba(255, 255, 255, 0.4);
|
||||||
--foreground-reversal-70: #b2b2b2; /* gray-300 */
|
--foreground-reversal-70: #b2b2b2; /* gray-300 */
|
||||||
|
|
||||||
/* 게임별 동적 색상 기본값 */
|
|
||||||
--game-primary: transparent;
|
|
||||||
--game-alternative-01: transparent;
|
|
||||||
--game-alternative-02: transparent;
|
|
||||||
--game-text-primary: transparent;
|
|
||||||
--game-text-secondary: transparent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 커스텀 컴포넌트 스타일 */
|
/* 커스텀 컴포넌트 스타일 */
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import type {
|
|||||||
// Props 정의
|
// Props 정의
|
||||||
const props = withDefaults(defineProps<ButtonProps>(), {
|
const props = withDefaults(defineProps<ButtonProps>(), {
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
backgroundColor: 'var(--game-primary)',
|
backgroundColor: 'var(--primary)',
|
||||||
textColor: 'var(--game-text-primary)',
|
textColor: 'var(--text-primary)',
|
||||||
icon: '',
|
icon: '',
|
||||||
disabled: false,
|
disabled: false,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,160 +1,26 @@
|
|||||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
|
||||||
import type { ParsedKeyColorCodes } from '#layers/types/api/gameData'
|
import type { ParsedKeyColorCodes } from '#layers/types/api/gameData'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 게임별 색상 코드를 CSS 변수로 설정하는 컴포저블
|
* 게임 데이터의 key_color_codes를 CSS 커스텀 프로퍼티로 적용하는 기능을 제공합니다.
|
||||||
*/
|
*/
|
||||||
export const useGameColors = () => {
|
export const useGameColors = () => {
|
||||||
const gameDataStore = useGameDataStore()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CSS에 정의된 기본 색상으로 리셋
|
* @param keyColorCodes
|
||||||
*/
|
*/
|
||||||
const resetToDefaultColors = () => {
|
const applyGameColors = (keyColorCodes: ParsedKeyColorCodes | null) => {
|
||||||
if (typeof document !== 'undefined') {
|
if (!keyColorCodes || import.meta.server) {
|
||||||
const root = document.documentElement
|
|
||||||
|
|
||||||
// CSS에 정의된 기본값으로 리셋 (브라우저가 자동으로 CSS 값을 사용하도록 함)
|
|
||||||
root.style.removeProperty('--game-primary')
|
|
||||||
root.style.removeProperty('--game-alternative-01')
|
|
||||||
root.style.removeProperty('--game-alternative-02')
|
|
||||||
root.style.removeProperty('--game-text-primary')
|
|
||||||
root.style.removeProperty('--game-text-secondary')
|
|
||||||
|
|
||||||
console.log('게임 색상을 CSS 기본값으로 리셋했습니다.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 게임 색상 코드를 파싱하여 CSS 변수로 설정
|
|
||||||
*/
|
|
||||||
const setGameColors = () => {
|
|
||||||
if (!gameDataStore.gameData?.key_color_codes) {
|
|
||||||
console.warn(
|
|
||||||
'게임 색상 데이터가 없습니다. CSS에 정의된 기본 색상을 사용합니다.'
|
|
||||||
)
|
|
||||||
// CSS에 정의된 기본값을 명시적으로 설정 (혹시 모를 경우를 대비)
|
|
||||||
resetToDefaultColors()
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const root = document.documentElement
|
||||||
// key_color_codes가 문자열인 경우 파싱
|
|
||||||
const colorCodes =
|
|
||||||
typeof gameDataStore.gameData.key_color_codes === 'string'
|
|
||||||
? JSON.parse(gameDataStore.gameData.key_color_codes)
|
|
||||||
: gameDataStore.gameData.key_color_codes
|
|
||||||
|
|
||||||
const colors = colorCodes as ParsedKeyColorCodes
|
Object.entries(keyColorCodes).forEach(([key, value]) => {
|
||||||
|
const cssVarName = `--${key}`
|
||||||
// CSS 변수 설정
|
root.style.setProperty(cssVarName, String(value))
|
||||||
if (typeof document !== 'undefined') {
|
})
|
||||||
const root = document.documentElement
|
|
||||||
|
|
||||||
// 색상 유효성 검사 함수
|
|
||||||
const isValidColor = (color: string): boolean => {
|
|
||||||
return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(color)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 기본 색상 설정 (유효성 검사 포함)
|
|
||||||
if (colors.primary && isValidColor(colors.primary)) {
|
|
||||||
root.style.setProperty('--game-primary', colors.primary)
|
|
||||||
console.log('게임 Primary 색상 설정:', colors.primary)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colors.secondary && isValidColor(colors.secondary)) {
|
|
||||||
root.style.setProperty('--game-secondary', colors.secondary)
|
|
||||||
console.log('게임 Secondary 색상 설정:', colors.secondary)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (colors['text-primary'] && isValidColor(colors['text-primary'])) {
|
|
||||||
root.style.setProperty('--game-text-primary', colors['text-primary'])
|
|
||||||
console.log('게임 텍스트 Primary 색상 설정:', colors['text-primary'])
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
colors['text-secondary'] &&
|
|
||||||
isValidColor(colors['text-secondary'])
|
|
||||||
) {
|
|
||||||
root.style.setProperty(
|
|
||||||
'--game-text-secondary',
|
|
||||||
colors['text-secondary']
|
|
||||||
)
|
|
||||||
console.log(
|
|
||||||
'게임 텍스트 Secondary 색상 설정:',
|
|
||||||
colors['text-secondary']
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// alternative 색상들 설정
|
|
||||||
if (
|
|
||||||
colors['alternative-01'] &&
|
|
||||||
isValidColor(colors['alternative-01'])
|
|
||||||
) {
|
|
||||||
root.style.setProperty(
|
|
||||||
'--game-alternative-01',
|
|
||||||
colors['alternative-01']
|
|
||||||
)
|
|
||||||
console.log(
|
|
||||||
'게임 Alternative-01 색상 설정:',
|
|
||||||
colors['alternative-01']
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
colors['alternative-02'] &&
|
|
||||||
isValidColor(colors['alternative-02'])
|
|
||||||
) {
|
|
||||||
root.style.setProperty(
|
|
||||||
'--game-alternative-02',
|
|
||||||
colors['alternative-02']
|
|
||||||
)
|
|
||||||
console.log(
|
|
||||||
'게임 Alternative-02 색상 설정:',
|
|
||||||
colors['alternative-02']
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('게임 색상 코드 파싱 오류:', error)
|
|
||||||
console.warn('CSS에 정의된 기본 색상을 사용합니다.')
|
|
||||||
resetToDefaultColors()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 게임 색상 코드를 반환
|
|
||||||
*/
|
|
||||||
const getGameColors = (): ParsedKeyColorCodes | null => {
|
|
||||||
if (!gameDataStore.gameData?.key_color_codes) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const colorCodes =
|
|
||||||
typeof gameDataStore.gameData.key_color_codes === 'string'
|
|
||||||
? JSON.parse(gameDataStore.gameData.key_color_codes)
|
|
||||||
: gameDataStore.gameData.key_color_codes
|
|
||||||
|
|
||||||
return colorCodes as ParsedKeyColorCodes
|
|
||||||
} catch (error) {
|
|
||||||
console.error('게임 색상 코드 파싱 오류:', error)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 특정 색상 코드를 반환
|
|
||||||
*/
|
|
||||||
const getColor = (colorKey: keyof ParsedKeyColorCodes): string | null => {
|
|
||||||
const colors = getGameColors()
|
|
||||||
return colors?.[colorKey] || null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
setGameColors,
|
applyGameColors,
|
||||||
getGameColors,
|
|
||||||
getColor,
|
|
||||||
resetToDefaultColors,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
export default defineNuxtPlugin(() => {
|
|
||||||
const { setGameColors } = useGameColors()
|
|
||||||
|
|
||||||
// 게임 데이터가 로드된 후 색상 설정
|
|
||||||
const gameDataStore = useGameDataStore()
|
|
||||||
|
|
||||||
// 게임 데이터가 변경될 때마다 색상 업데이트
|
|
||||||
watch(
|
|
||||||
() => gameDataStore.gameData,
|
|
||||||
newGameData => {
|
|
||||||
if (newGameData) {
|
|
||||||
setGameColors()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ immediate: true }
|
|
||||||
)
|
|
||||||
})
|
|
||||||
@@ -20,13 +20,6 @@ export default {
|
|||||||
'theme-foreground-reversal-30': 'var(--foreground-reversal-30)',
|
'theme-foreground-reversal-30': 'var(--foreground-reversal-30)',
|
||||||
'theme-foreground-reversal-40': 'var(--foreground-reversal-40)',
|
'theme-foreground-reversal-40': 'var(--foreground-reversal-40)',
|
||||||
'theme-foreground-reversal-70': 'var(--foreground-reversal-70)',
|
'theme-foreground-reversal-70': 'var(--foreground-reversal-70)',
|
||||||
|
|
||||||
// 게임별 동적 색상 (CSS 변수로 설정)
|
|
||||||
'game-primary': 'var(--game-primary)',
|
|
||||||
'game-alternative-01': 'var(--game-alternative-01)',
|
|
||||||
'game-alternative-02': 'var(--game-alternative-02)',
|
|
||||||
'game-text-primary': 'var(--game-text-primary)',
|
|
||||||
'game-text-secondary': 'var(--game-text-secondary)',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user