Added language provider, fixed race condition on emulator
This commit is contained in:
@ -34,6 +34,10 @@
|
||||
<script type="text/javascript" language="javascript">
|
||||
let scriptElement = null;
|
||||
|
||||
let initInterval = setInterval(() => {
|
||||
send({ message: 'iframe_loaded' });
|
||||
}, 500);
|
||||
|
||||
EJS_player = "#game";
|
||||
EJS_pathtodata = "https://cdn.emulatorjs.org/stable/data/";
|
||||
EJS_language = "en-US";
|
||||
@ -77,6 +81,8 @@
|
||||
scriptElement = document.createElement('script');
|
||||
scriptElement.src = 'https://cdn.emulatorjs.org/stable/data/loader.js';
|
||||
document.body.appendChild(scriptElement);
|
||||
|
||||
clearInterval(initInterval);
|
||||
}
|
||||
|
||||
const send = data => {
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import styles from './Emulator.module.scss';
|
||||
import { GAME_SYSTEM_CORES, GameSystem, GameSystemCore } from '@/lib/game';
|
||||
import { useLanguage } from '@/providers/LanguageProvider';
|
||||
|
||||
type SendEmulatorMessageInit = {
|
||||
message:'init';
|
||||
@ -21,6 +22,7 @@ type SendEmulatorMessage = (
|
||||
);
|
||||
|
||||
type ReceiveEmulatorMessage = (
|
||||
{ message: 'iframe_loaded' } |
|
||||
{ message: 'start' } |
|
||||
{ message: 'ready' } |
|
||||
{ message: 'save' } |
|
||||
@ -36,6 +38,7 @@ export type EmulatorProps = {
|
||||
export const Emulator:React.FC<EmulatorProps> = props => {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
const [ hasInit, setHasInit ] = useState(false);
|
||||
const { t } = useLanguage();
|
||||
|
||||
const send = (msg:SendEmulatorMessage) => {
|
||||
iframeRef.current?.contentWindow?.postMessage(msg, '*');
|
||||
@ -45,14 +48,6 @@ export const Emulator:React.FC<EmulatorProps> = props => {
|
||||
if(hasInit) return;
|
||||
setHasInit(true);
|
||||
|
||||
send({
|
||||
message: 'init',
|
||||
core: GAME_SYSTEM_CORES[props.system],
|
||||
system: props.system,
|
||||
gameId: props.gameId,
|
||||
gameName: props.gameName
|
||||
});
|
||||
|
||||
window.onmessage = e => {
|
||||
if(!e.data) {
|
||||
console.error('Invalid message received:', e.data);
|
||||
@ -61,6 +56,17 @@ export const Emulator:React.FC<EmulatorProps> = props => {
|
||||
|
||||
const msg = e.data as ReceiveEmulatorMessage;
|
||||
switch(msg.message) {
|
||||
case 'iframe_loaded':
|
||||
if(hasInit) return;
|
||||
send({
|
||||
message: 'init',
|
||||
core: GAME_SYSTEM_CORES[props.system],
|
||||
system: props.system,
|
||||
gameId: props.gameId,
|
||||
gameName: props.gameName
|
||||
});
|
||||
break;
|
||||
|
||||
case 'start':
|
||||
case 'ready':
|
||||
case 'load':
|
||||
@ -71,7 +77,17 @@ export const Emulator:React.FC<EmulatorProps> = props => {
|
||||
break
|
||||
}
|
||||
};
|
||||
}, [ iframeRef ]);
|
||||
|
||||
window.onbeforeunload = (e: BeforeUnloadEvent) => {
|
||||
e.preventDefault();
|
||||
return t('emulator.exit_unsaved');
|
||||
};
|
||||
|
||||
|
||||
return () => {
|
||||
window.onbeforeunload = null;
|
||||
};
|
||||
}, [ ]);
|
||||
|
||||
return (
|
||||
<div className={styles.emulator}>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { GAME_SYSTEMS } from "@/lib/game";
|
||||
import { ApolloError, gql } from "apollo-server-micro";
|
||||
import { pageTypeDefs } from "./page";
|
||||
import { GAME_SYSTEMS } from "@/lib/game";
|
||||
|
||||
export const gameTypeDefs = gql`
|
||||
${pageTypeDefs}
|
||||
|
@ -7,9 +7,12 @@ export const GAME_SYSTEM_CORES = <const>{
|
||||
'gba': 'mgba'
|
||||
};
|
||||
|
||||
|
||||
export type GameSystem = keyof typeof GAME_SYSTEM_CORES;
|
||||
export type GameSystemCore = typeof GAME_SYSTEM_CORES[GameSystem];
|
||||
|
||||
export const GAME_SYSTEMS = Object.keys(GAME_SYSTEM_CORES) as GameSystem[];
|
||||
|
||||
export type GameLight = {
|
||||
id:string;
|
||||
name:string;
|
||||
|
10
src/lib/language.ts
Normal file
10
src/lib/language.ts
Normal file
@ -0,0 +1,10 @@
|
||||
export const LANGUAGE_ENGLISH = <const>{
|
||||
'emulator.exit_unsaved': 'Your game may not be saved. Are you sure you want to exit?',
|
||||
};
|
||||
|
||||
export const LANGUAGES = <const>{
|
||||
'en': LANGUAGE_ENGLISH
|
||||
}
|
||||
|
||||
export type LanguageKey = keyof typeof LANGUAGE_ENGLISH;
|
||||
export type Language = keyof typeof LANGUAGES;
|
@ -1,11 +1,14 @@
|
||||
import React from 'react';
|
||||
import { AppProps } from 'next/app';
|
||||
import './globals.scss';
|
||||
import { LanguageProvider } from '@/providers/LanguageProvider';
|
||||
|
||||
const RootLayout:React.FC<AppProps> = ({ Component, pageProps }) => {
|
||||
return (
|
||||
<>
|
||||
<LanguageProvider>
|
||||
<Component {...pageProps} />
|
||||
</LanguageProvider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { LanguageProvider } from '@/providers/LanguageProvider';
|
||||
import { Html, Head, Main, NextScript, DocumentProps } from 'next/document';
|
||||
|
||||
const RootDocument:React.FC<DocumentProps> = props => {
|
||||
|
47
src/providers/LanguageProvider.tsx
Normal file
47
src/providers/LanguageProvider.tsx
Normal file
@ -0,0 +1,47 @@
|
||||
import { Language, LanguageKey, LANGUAGES } from '@/lib/language';
|
||||
import React, { createContext, useContext, useState, ReactNode } from 'react';
|
||||
|
||||
type LanguageContextType = {
|
||||
lang:Language;
|
||||
t:(key:LanguageKey, p?:{ [key:string]:string }) => string;
|
||||
};
|
||||
|
||||
const LanguageContext = createContext<LanguageContextType | undefined>(undefined);
|
||||
|
||||
export const LanguageProvider: React.FC<{ children: ReactNode }> = ({
|
||||
children
|
||||
}) => {
|
||||
const [ lang, setLang ] = useState<Language>('en');
|
||||
|
||||
const t:LanguageContextType['t'] = (key, p) => {
|
||||
const str = LANGUAGES[lang][key];
|
||||
|
||||
if(!str) {
|
||||
console.error(`Invalid language key: ${key}`);
|
||||
return '';
|
||||
}
|
||||
|
||||
if(!p) return str;
|
||||
|
||||
return Object.keys(p).reduce((acc, k, v) => {
|
||||
return acc.replace(`{{${k}}}`, p[k]);
|
||||
}, str);
|
||||
};
|
||||
|
||||
return (
|
||||
<LanguageContext.Provider value={{
|
||||
lang,
|
||||
t
|
||||
}}>
|
||||
{children}
|
||||
</LanguageContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
export const useLanguage = (): LanguageContextType => {
|
||||
const context = useContext(LanguageContext);
|
||||
if (!context) {
|
||||
throw new Error('useLanguage must be used within a LanguageProvider');
|
||||
}
|
||||
return context;
|
||||
};
|
Reference in New Issue
Block a user