feat: Add remote splash text loading via URLs

This commit is contained in:
Maxim Grigorev 2025-05-16 20:19:23 +07:00
commit 6302a3815f
3 changed files with 62 additions and 5 deletions

View file

@ -26,7 +26,7 @@
}
],
"rightSideText": "A Minecraft client clone in the browser!",
"splashText": "Gen is cooking!",
"splashText": "https://jsonplaceholder.typicode.com/posts/1",
"pauseLinks": [
[
{
@ -37,4 +37,4 @@
}
]
]
}
}

View file

@ -1,9 +1,10 @@
import React from 'react'
import React, { useEffect, useState } from 'react'
import { openURL } from 'renderer/viewer/lib/simpleUtils'
import { useSnapshot } from 'valtio'
import { haveDirectoryPicker } from '../utils'
import { ConnectOptions } from '../connect'
import { miscUiState } from '../globalState'
import { isRemoteSplashText, loadRemoteSplashText } from '../utils/splashText'
import styles from './mainMenu.module.css'
import Button from './Button'
import ButtonWithTooltip from './ButtonWithTooltip'
@ -47,6 +48,19 @@ export default ({
singleplayerAvailable = true
}: Props) => {
const { appConfig } = useSnapshot(miscUiState)
const [splashText, setSplashText] = useState(appConfig?.splashText || '')
useEffect(() => {
const loadSplashText = async () => {
if (appConfig?.splashText && isRemoteSplashText(appConfig.splashText)) {
const text = await loadRemoteSplashText(appConfig.splashText)
setSplashText(text)
} else {
setSplashText(appConfig?.splashText || '')
}
}
void loadSplashText()
}, [appConfig?.splashText])
if (!bottomRightLinks?.trim()) bottomRightLinks = undefined
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
@ -75,7 +89,7 @@ export default ({
const connectToServerLongPress = useLongPress(
() => {
if (process.env.NODE_ENV === 'development') {
// Connect to <origin>:25565
// Connect to <origin>:25565
const origin = window.location.hostname
const connectOptions: ConnectOptions = {
server: `${origin}:25565`,
@ -93,7 +107,7 @@ export default ({
<div className={styles['game-title']}>
<div className={styles.minecraft}>
<div className={styles.edition} />
<span className={styles.splash}>{appConfig?.splashText}</span>
<span className={styles.splash}>{splashText}</span>
</div>
</div>

43
src/utils/splashText.ts Normal file
View file

@ -0,0 +1,43 @@
const MAX_WORDS = 5
const HTTPS_REGEX = /^https?:\/\//
const limitWords = (text: string): string => {
const words = text.split(/\s+/)
if (words.length <= MAX_WORDS) {
return text
}
return words.slice(0, MAX_WORDS).join(' ') + '...'
}
export const isRemoteSplashText = (text: string): boolean => {
return HTTPS_REGEX.test(text)
}
export const loadRemoteSplashText = async (url: string): Promise<string> => {
try {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`Failed to fetch splash text: ${response.statusText}`)
}
try {
const json = await response.json()
if (typeof json === 'object' && json !== null) {
if (json.title) return limitWords(json.title)
if (json.text) return limitWords(json.text)
if (json.message) return limitWords(json.message)
return limitWords(JSON.stringify(json))
}
return limitWords(String(json))
} catch (jsonError) {
const text = await response.text()
return limitWords(text.trim())
}
} catch (error) {
console.error('Error loading remote splash text:', error)
return 'Failed to load splash text!'
}
}