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 LoadingLocal from '#layers/components/blocks/loading/Local.vue'
|
||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
||||
import { useGameColors } from '#layers/composables/useGameColors'
|
||||
import type { GameDataMetaTag, GameDataValue } from '#layers/types/api/gameData'
|
||||
|
||||
const nuxtApp = useNuxtApp()
|
||||
const getGameData = ref<GameDataValue | null>(null)
|
||||
const metaData = ref<GameDataMetaTag | null>(null)
|
||||
const { setGameData } = useGameDataStore()
|
||||
const { applyGameColors } = useGameColors()
|
||||
|
||||
// SSR에서만 접근 가능
|
||||
const gameDataFromServer = import.meta.server
|
||||
@@ -30,6 +32,14 @@ if (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 theme = gameDataFromServer?.design_theme === 1 ? 'dark' : 'light'
|
||||
|
||||
|
||||
@@ -8,13 +8,6 @@
|
||||
--foreground-reversal-30: #ebebeb; /* gray-80 */
|
||||
--foreground-reversal-40: rgba(0, 0, 0, 0.4);
|
||||
--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-40: rgba(255, 255, 255, 0.4);
|
||||
--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 정의
|
||||
const props = withDefaults(defineProps<ButtonProps>(), {
|
||||
size: 'medium',
|
||||
backgroundColor: 'var(--game-primary)',
|
||||
textColor: 'var(--game-text-primary)',
|
||||
backgroundColor: 'var(--primary)',
|
||||
textColor: 'var(--text-primary)',
|
||||
icon: '',
|
||||
disabled: false,
|
||||
})
|
||||
|
||||
@@ -1,160 +1,26 @@
|
||||
import { useGameDataStore } from '#layers/stores/useGameDataStore'
|
||||
import type { ParsedKeyColorCodes } from '#layers/types/api/gameData'
|
||||
|
||||
/**
|
||||
* 게임별 색상 코드를 CSS 변수로 설정하는 컴포저블
|
||||
* 게임 데이터의 key_color_codes를 CSS 커스텀 프로퍼티로 적용하는 기능을 제공합니다.
|
||||
*/
|
||||
export const useGameColors = () => {
|
||||
const gameDataStore = useGameDataStore()
|
||||
|
||||
/**
|
||||
* CSS에 정의된 기본 색상으로 리셋
|
||||
* @param keyColorCodes
|
||||
*/
|
||||
const resetToDefaultColors = () => {
|
||||
if (typeof document !== 'undefined') {
|
||||
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()
|
||||
const applyGameColors = (keyColorCodes: ParsedKeyColorCodes | null) => {
|
||||
if (!keyColorCodes || import.meta.server) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 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 root = document.documentElement
|
||||
|
||||
const colors = colorCodes as ParsedKeyColorCodes
|
||||
|
||||
// CSS 변수 설정
|
||||
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
|
||||
Object.entries(keyColorCodes).forEach(([key, value]) => {
|
||||
const cssVarName = `--${key}`
|
||||
root.style.setProperty(cssVarName, String(value))
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
setGameColors,
|
||||
getGameColors,
|
||||
getColor,
|
||||
resetToDefaultColors,
|
||||
applyGameColors,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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-40': 'var(--foreground-reversal-40)',
|
||||
'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