feat(images): default frontend assets to image service
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { configuredGameAssetUrl } from '../utils/imageAssets';
|
||||
|
||||
interface MapSummary {
|
||||
year: number;
|
||||
@@ -40,7 +41,7 @@ const props = defineProps<{
|
||||
const BASE_MAP_WIDTH = 700;
|
||||
const BASE_MAP_HEIGHT = 500;
|
||||
|
||||
const assetBase = computed(() => (import.meta.env.VITE_GAME_ASSET_URL ?? '/image').replace(/\/+$/, ''));
|
||||
const assetBase = computed(configuredGameAssetUrl);
|
||||
const season = computed(() => {
|
||||
if (props.mapData.month <= 3) return 'spring';
|
||||
if (props.mapData.month <= 6) return 'summer';
|
||||
@@ -49,11 +50,11 @@ const season = computed(() => {
|
||||
});
|
||||
const mapBackground = computed(() => {
|
||||
const theme = props.mapLayout.mapName;
|
||||
if (theme === 'ludo_rathowm') return `${assetBase.value}/game/map/ludo_rathowm/back.jpg`;
|
||||
if (theme === 'chess') return `${assetBase.value}/game/map/chess/chessboard.png`;
|
||||
if (theme === 'pokemon_v1') return `${assetBase.value}/game/map/pokemon_v1/back_pal8.png`;
|
||||
if (theme === 'cr') return `${assetBase.value}/game/map/cr/bg-fs8.png`;
|
||||
return `${assetBase.value}/game/map/che/bg_${season.value}.jpg`;
|
||||
if (theme === 'ludo_rathowm') return `${assetBase.value}/map/ludo_rathowm/back.jpg`;
|
||||
if (theme === 'chess') return `${assetBase.value}/map/chess/chessboard.png`;
|
||||
if (theme === 'pokemon_v1') return `${assetBase.value}/map/pokemon_v1/back_pal8.png`;
|
||||
if (theme === 'cr') return `${assetBase.value}/map/cr/bg-fs8.png`;
|
||||
return `${assetBase.value}/map/che/bg_${season.value}.jpg`;
|
||||
});
|
||||
|
||||
const nationById = computed(() => {
|
||||
|
||||
Vendored
+2
@@ -11,6 +11,8 @@ interface ImportMetaEnv {
|
||||
readonly VITE_GATEWAY_API_URL?: string;
|
||||
readonly VITE_GAME_API_URL_TEMPLATE?: string;
|
||||
readonly VITE_GAME_ASSET_URL?: string;
|
||||
readonly VITE_IMAGE_PUBLIC_URL?: string;
|
||||
readonly VITE_GATEWAY_USER_ICON_BASE_URL?: string;
|
||||
readonly VITE_GAME_WEB_URL?: string;
|
||||
readonly VITE_GAME_WEB_URL_TEMPLATE?: string;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ import { createPinia } from 'pinia';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import './assets/main.css';
|
||||
import { installImageAssetCssVariables } from './utils/imageAssets';
|
||||
|
||||
installImageAssetCssVariables();
|
||||
|
||||
const app = createApp(App);
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
export const DEFAULT_IMAGE_PUBLIC_URL = 'https://sam-image.hided.net';
|
||||
export const DEFAULT_SHARED_ICON_PUBLIC_URL = `${DEFAULT_IMAGE_PUBLIC_URL}/icons`;
|
||||
export const DEFAULT_USER_ICON_PUBLIC_URL = DEFAULT_SHARED_ICON_PUBLIC_URL;
|
||||
|
||||
const trimTrailingSlashes = (value: string): string => value.replace(/\/+$/u, '');
|
||||
|
||||
const configuredValue = (value: string | undefined, fallback: string): string => {
|
||||
const normalized = value?.trim();
|
||||
return trimTrailingSlashes(normalized || fallback);
|
||||
};
|
||||
|
||||
export const configuredImagePublicUrl = (): string =>
|
||||
configuredValue(import.meta.env?.VITE_IMAGE_PUBLIC_URL, DEFAULT_IMAGE_PUBLIC_URL);
|
||||
|
||||
export const configuredSharedIconPublicUrl = (): string => `${configuredImagePublicUrl()}/icons`;
|
||||
|
||||
export const configuredUserIconPublicUrl = (): string =>
|
||||
configuredValue(
|
||||
import.meta.env?.VITE_GATEWAY_USER_ICON_BASE_URL,
|
||||
`${configuredImagePublicUrl()}/icons`
|
||||
);
|
||||
|
||||
export const configuredGameAssetUrl = (): string => {
|
||||
const explicit = import.meta.env?.VITE_GAME_ASSET_URL?.trim();
|
||||
if (!explicit) {
|
||||
return `${configuredImagePublicUrl()}/game`;
|
||||
}
|
||||
const normalized = trimTrailingSlashes(explicit);
|
||||
return normalized.endsWith('/game') ? normalized : `${normalized}/game`;
|
||||
};
|
||||
|
||||
export const installImageAssetCssVariables = (): void => {
|
||||
const root = document.documentElement.style;
|
||||
const gameAssetUrl = configuredGameAssetUrl();
|
||||
root.setProperty('--sammo-texture-walnut', `url(${JSON.stringify(`${gameAssetUrl}/back_walnut.jpg`)})`);
|
||||
root.setProperty('--sammo-texture-green', `url(${JSON.stringify(`${gameAssetUrl}/back_green.jpg`)})`);
|
||||
root.setProperty('--sammo-texture-blue', `url(${JSON.stringify(`${gameAssetUrl}/back_blue.jpg`)})`);
|
||||
};
|
||||
@@ -713,17 +713,17 @@ onBeforeUnmount(() => {
|
||||
|
||||
.legacy-bg0 {
|
||||
background-color: #302016;
|
||||
background-image: url('/image/game/back_walnut.jpg');
|
||||
background-image: var(--sammo-texture-walnut, url('https://sam-image.hided.net/game/back_walnut.jpg'));
|
||||
}
|
||||
|
||||
.legacy-bg1 {
|
||||
background-color: #14241b;
|
||||
background-image: url('/image/game/back_green.jpg');
|
||||
background-image: var(--sammo-texture-green, url('https://sam-image.hided.net/game/back_green.jpg'));
|
||||
}
|
||||
|
||||
.legacy-bg2 {
|
||||
background-color: #172a52;
|
||||
background-image: url('/image/game/back_blue.jpg');
|
||||
background-image: var(--sammo-texture-blue, url('https://sam-image.hided.net/game/back_blue.jpg'));
|
||||
}
|
||||
|
||||
#account-table caption {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { trpc } from '../utils/trpc';
|
||||
import { createGameTrpc } from '../utils/gameTrpc';
|
||||
import type { GameRouter } from '../utils/gameTrpc';
|
||||
import { resolveServerSeasonStatus } from '../utils/serverSeasonStatus';
|
||||
import { configuredSharedIconPublicUrl, configuredUserIconPublicUrl } from '../utils/imageAssets';
|
||||
|
||||
type GatewayRouterOutput = inferRouterOutputs<AppRouter>;
|
||||
type GameRouterOutput = inferRouterOutputs<GameRouter>;
|
||||
@@ -40,7 +41,8 @@ const canAccessAdmin = computed(
|
||||
) ?? false
|
||||
);
|
||||
const needsKakaoVerification = computed(() => me.value !== null && !me.value.kakaoVerified);
|
||||
const userIconBaseUrl = import.meta.env.VITE_GATEWAY_USER_ICON_BASE_URL ?? '/gateway/api/user-icons';
|
||||
const userIconBaseUrl = configuredUserIconPublicUrl();
|
||||
const sharedIconBaseUrl = configuredSharedIconPublicUrl();
|
||||
|
||||
const formatGraceEndsAt = (value: string | null | undefined): string =>
|
||||
value ? new Date(value).toLocaleString('ko-KR') : '';
|
||||
@@ -57,8 +59,8 @@ const encodeLegacyIconPath = (value: string): string =>
|
||||
const resolveGeneralPicture = (general: LobbyGeneral): string => {
|
||||
const picture = general.picture?.trim() || 'default.jpg';
|
||||
return general.imageServer
|
||||
? `${userIconBaseUrl.replace(/\/$/, '')}/${encodeURIComponent(picture)}`
|
||||
: `/image/icons/${encodeLegacyIconPath(picture)}`;
|
||||
? `${userIconBaseUrl.replace(/\/$/, '')}/${encodeLegacyIconPath(picture)}`
|
||||
: `${sharedIconBaseUrl}/${encodeLegacyIconPath(picture)}`;
|
||||
};
|
||||
const handleGeneralPictureError = (event: Event): void => {
|
||||
const image = event.currentTarget as HTMLImageElement;
|
||||
@@ -66,7 +68,7 @@ const handleGeneralPictureError = (event: Event): void => {
|
||||
return;
|
||||
}
|
||||
image.dataset.generalIconFallbackSource = image.currentSrc;
|
||||
image.src = '/image/icons/default.jpg';
|
||||
image.src = `${sharedIconBaseUrl}/default.jpg`;
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
|
||||
Reference in New Issue
Block a user