refactor(directory): use VoiceElement instead of useAudio
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
showcase:
|
showcase:
|
||||||
|
2023/03/15:
|
||||||
|
- Added background music
|
||||||
2023/03/03:
|
2023/03/03:
|
||||||
- Performance optimization
|
- Performance optimization
|
||||||
2023/02/26:
|
2023/02/26:
|
||||||
@@ -38,10 +40,12 @@ showcase:
|
|||||||
2021/05/26:
|
2021/05/26:
|
||||||
- First commit
|
- First commit
|
||||||
directory:
|
directory:
|
||||||
|
2023/03/15:
|
||||||
|
- Added background music
|
||||||
2023/03/03:
|
2023/03/03:
|
||||||
- Fixed Voice and VCs issues
|
- Fixed Voice and VLs issues
|
||||||
2023/03/02:
|
2023/03/02:
|
||||||
- Added Voice, VCs, Operator Logo
|
- Added Voice, VLs, Operator Logo
|
||||||
2023/03/01:
|
2023/03/01:
|
||||||
- Added Operator page
|
- Added Operator page
|
||||||
- Added Changelogs page
|
- Added Changelogs page
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ localization:
|
|||||||
ui_privacy_do_not_track: Send usage data
|
ui_privacy_do_not_track: Send usage data
|
||||||
ui_music_title: <hr><h4>📝 Music</h4><hr>
|
ui_music_title: <hr><h4>📝 Music</h4><hr>
|
||||||
ui_music_notice: <span><b>Please adjust the 'Offset' value if you notice audio cutoff</b></span>
|
ui_music_notice: <span><b>Please adjust the 'Offset' value if you notice audio cutoff</b></span>
|
||||||
|
ui_music_notice1: <span><b>'bg_rhodes_day.png' and 'operator_bg.png' use the same music, it is not a bug.</b></span>
|
||||||
ui_music_selection: Music
|
ui_music_selection: Music
|
||||||
ui_music_volume: Volume
|
ui_music_volume: Volume
|
||||||
ui_music_offset: Offset
|
ui_music_offset: Offset
|
||||||
@@ -71,6 +72,7 @@ localization:
|
|||||||
ui_privacy_do_not_track: 发送使用数据
|
ui_privacy_do_not_track: 发送使用数据
|
||||||
ui_music_title: <hr><h4>🎵 音乐</h4><hr>
|
ui_music_title: <hr><h4>🎵 音乐</h4><hr>
|
||||||
ui_music_notice: <span><b>如若发现音频截止,请调节 '弥补' 数值</b></span>
|
ui_music_notice: <span><b>如若发现音频截止,请调节 '弥补' 数值</b></span>
|
||||||
|
ui_music_notice1: <span><b>'bg_rhodes_day.png' 和 'operator_bg.png' 使用同样的音乐,并非Bug</b></span>
|
||||||
ui_music_selection: 音乐
|
ui_music_selection: 音乐
|
||||||
ui_music_volume: 音量
|
ui_music_volume: 音量
|
||||||
ui_music_offset: 弥补
|
ui_music_offset: 弥补
|
||||||
@@ -233,6 +235,10 @@ properties:
|
|||||||
value:
|
value:
|
||||||
text: ui_music_notice
|
text: ui_music_notice
|
||||||
condition: music_title.value == true
|
condition: music_title.value == true
|
||||||
|
- key: music_notice1
|
||||||
|
value:
|
||||||
|
text: ui_music_notice1
|
||||||
|
condition: music_title.value == true
|
||||||
- key: music_selection
|
- key: music_selection
|
||||||
value:
|
value:
|
||||||
text: ui_music_selection
|
text: ui_music_selection
|
||||||
|
|||||||
@@ -5,3 +5,5 @@ VITE_DIRECTORY_FOLDER="_assets"
|
|||||||
VITE_BACKGROUND_FOLDER="background"
|
VITE_BACKGROUND_FOLDER="background"
|
||||||
VITE_AVAILABLE_OPERATORS=["chen","dusk","dusk_everything_is_a_miracle","ling","nearl","nian","nian_unfettered_freedom","phatom_focus","rosmontis","skadi","skadi_sublimation","w","w_wonder","specter","gavial","surtr_colorful_wonderland","lee_trust_your_eyes","texas_the_omertosa","nearl_relight","rosmontis_become_anew","passager_dream_in_a_moment","mizuki_summer_feast","chongyue","ling_it_does_wash_the_strings","pozemka_snowy_plains_in_words"]
|
VITE_AVAILABLE_OPERATORS=["chen","dusk","dusk_everything_is_a_miracle","ling","nearl","nian","nian_unfettered_freedom","phatom_focus","rosmontis","skadi","skadi_sublimation","w","w_wonder","specter","gavial","surtr_colorful_wonderland","lee_trust_your_eyes","texas_the_omertosa","nearl_relight","rosmontis_become_anew","passager_dream_in_a_moment","mizuki_summer_feast","chongyue","ling_it_does_wash_the_strings","pozemka_snowy_plains_in_words"]
|
||||||
VITE_ERROR_FILES={"files":[{"key":"build_char_128_plosis_epoque%233","paddings":{"left":-120,"right":150,"top":10,"bottom":0}},{"key":"build_char_128_plosis","paddings":{"left":-90,"right":100,"top":10,"bottom":0}}],"voice":"CN_034.ogg"}
|
VITE_ERROR_FILES={"files":[{"key":"build_char_128_plosis_epoque%233","paddings":{"left":-120,"right":150,"top":10,"bottom":0}},{"key":"build_char_128_plosis","paddings":{"left":-90,"right":100,"top":10,"bottom":0}}],"voice":"CN_034.ogg"}
|
||||||
|
VITE_MUSIC_FOLDER=music
|
||||||
|
VITE_MUSIC_MAPPING={"operator_bg.png":{"intro":"m_sys_void_intro.ogg","loop":"m_sys_void_loop.ogg"},"bg_anniversary_1.png":{"intro":"m_dia_nightoflongmen_intro.ogg","loop":"m_dia_nightoflongmen_loop.ogg"},"bg_iberia_1.png":{"intro":"m_sys_act18d3d0_intro.ogg","loop":"m_sys_act18d3d0_loop.ogg"},"bg_kazimierz_1.png":{"intro":"m_dia_street_intro.ogg","loop":"m_dia_street_loop.ogg"},"bg_main_victoria_1.png":{"intro":"m_avg_ghosthunter_intro.ogg","loop":"m_avg_ghosthunter_loop.ogg"},"bg_rhodes_day.png":{"intro":"m_sys_void_intro.ogg","loop":"m_sys_void_loop.ogg"},"bg_rhodes_night.png":{"intro":"m_sys_tech_intro.ogg","loop":"m_sys_tech_loop.ogg"},"bg_rogue_1.png":{"intro":null,"loop":"m_avg_rglk1secretevent_loop.ogg"},"bg_siesta_1.png":{"intro":"m_sys_ddd_intro.ogg","loop":"m_sys_ddd_loop.ogg"},"bg_ursus_1.png":{"intro":"m_avg_loneliness_intro.ogg","loop":"m_avg_loneliness_loop.ogg"},"bg_yan_1.png":{"intro":null,"loop":"m_sys_bitw_loop.ogg"}}
|
||||||
@@ -1 +1 @@
|
|||||||
1.0.18
|
1.0.22
|
||||||
@@ -16,7 +16,11 @@ export default function Switch(props) {
|
|||||||
return (
|
return (
|
||||||
<section
|
<section
|
||||||
className={`${classes.switch} ${on ? classes.active : ''}`}
|
className={`${classes.switch} ${on ? classes.active : ''}`}
|
||||||
onClick={() => props.handleOnClick()}
|
onClick={() => {
|
||||||
|
if (props.handleOnClick) {
|
||||||
|
props.handleOnClick(!on)
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<span className={classes.text}>{i18n(props.text)}</span>
|
<span className={classes.text}>{i18n(props.text)}</span>
|
||||||
<section className={classes.wrapper}>
|
<section className={classes.wrapper}>
|
||||||
|
|||||||
53
directory/src/component/voice.jsx
Normal file
53
directory/src/component/voice.jsx
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import React, {
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
} from "react"
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
|
export default function VoiceElement({
|
||||||
|
src,
|
||||||
|
replay,
|
||||||
|
handleAduioStateChange,
|
||||||
|
}) {
|
||||||
|
const audioRef = useRef(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (src) {
|
||||||
|
audioRef.current.src = src
|
||||||
|
audioRef.current.play()
|
||||||
|
} else {
|
||||||
|
audioRef.current.pause()
|
||||||
|
}
|
||||||
|
}, [src])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (replay) {
|
||||||
|
audioRef.current.currentTime = 0
|
||||||
|
audioRef.current.play()
|
||||||
|
}
|
||||||
|
}, [replay])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<audio
|
||||||
|
ref={audioRef}
|
||||||
|
preload="auto"
|
||||||
|
autoPlay
|
||||||
|
onEnded={(e) => {
|
||||||
|
if (handleAduioStateChange) handleAduioStateChange(e, 'ended')
|
||||||
|
}}
|
||||||
|
onPlay={(e) => {
|
||||||
|
if (handleAduioStateChange) handleAduioStateChange(e, 'play')
|
||||||
|
}}
|
||||||
|
onPause={(e) => {
|
||||||
|
if (handleAduioStateChange) handleAduioStateChange(e, 'pause')
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<source type="audio/ogg" />
|
||||||
|
</audio>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
VoiceElement.propTypes = {
|
||||||
|
src: PropTypes.string,
|
||||||
|
handleAduioStateChange: PropTypes.func,
|
||||||
|
replay: PropTypes.bool,
|
||||||
|
}
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
import {
|
|
||||||
useState,
|
|
||||||
useEffect,
|
|
||||||
useRef,
|
|
||||||
} from "react"
|
|
||||||
import { useCallback } from "react"
|
|
||||||
const audioEl = new Audio()
|
|
||||||
let lastSrc = ''
|
|
||||||
export default function useAudio() {
|
|
||||||
const [isPlaying, _setIsPlaying] = useState(false)
|
|
||||||
const isPlayingRef = useRef(isPlaying)
|
|
||||||
const setIsPlaying = (data) => {
|
|
||||||
isPlayingRef.current = data
|
|
||||||
_setIsPlaying(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
audioEl.addEventListener('ended', () => setIsPlaying(false))
|
|
||||||
return () => {
|
|
||||||
audioEl.removeEventListener('ended', () => setIsPlaying(false))
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const play = useCallback(
|
|
||||||
(
|
|
||||||
link,
|
|
||||||
options = {
|
|
||||||
overwrite: false
|
|
||||||
},
|
|
||||||
callback = () => { }
|
|
||||||
) => {
|
|
||||||
if (!options.overwrite && link === lastSrc) return
|
|
||||||
audioEl.src = link
|
|
||||||
let startPlayPromise = audioEl.play()
|
|
||||||
if (startPlayPromise !== undefined) {
|
|
||||||
setIsPlaying(true)
|
|
||||||
startPlayPromise
|
|
||||||
.then(() => {
|
|
||||||
lastSrc = link
|
|
||||||
callback()
|
|
||||||
return
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
console.log(e)
|
|
||||||
return
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const stop = useCallback(() => {
|
|
||||||
audioEl.pause()
|
|
||||||
setIsPlaying(false)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const getSrc = useCallback(() => audioEl.src, [])
|
|
||||||
const resetSrc = useCallback(() => {
|
|
||||||
audioEl.src = ''
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return {
|
|
||||||
play,
|
|
||||||
stop,
|
|
||||||
getSrc,
|
|
||||||
resetSrc,
|
|
||||||
isPlaying,
|
|
||||||
isPlayingRef,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -17,7 +17,7 @@ import Switch from '@/component/switch';
|
|||||||
import ReturnButton from "@/component/return_button";
|
import ReturnButton from "@/component/return_button";
|
||||||
import { Typewriter } from 'react-simple-typewriter'
|
import { Typewriter } from 'react-simple-typewriter'
|
||||||
import { useHeader } from '@/state/header';
|
import { useHeader } from '@/state/header';
|
||||||
import useAudio from '@/libs/voice';
|
import VoiceElement from '@/component/voice';
|
||||||
import spine from '!/libs/spine-player'
|
import spine from '!/libs/spine-player'
|
||||||
import '!/libs/spine-player.css'
|
import '!/libs/spine-player.css'
|
||||||
import useUmami from '@parcellab/react-use-umami';
|
import useUmami from '@parcellab/react-use-umami';
|
||||||
@@ -27,6 +27,7 @@ const config = JSON.parse(import.meta.env.VITE_ERROR_FILES)
|
|||||||
const obj = config.files[Math.floor((Math.random() * config.files.length))]
|
const obj = config.files[Math.floor((Math.random() * config.files.length))]
|
||||||
const filename = obj.key.replace("#", "%23")
|
const filename = obj.key.replace("#", "%23")
|
||||||
const padding = obj.paddings
|
const padding = obj.paddings
|
||||||
|
let lastVoiceState = 'ended'
|
||||||
|
|
||||||
export default function Error() {
|
export default function Error() {
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
@@ -40,9 +41,11 @@ export default function Error() {
|
|||||||
const [spineDone, _setSpineDone] = useState(false)
|
const [spineDone, _setSpineDone] = useState(false)
|
||||||
const spineRef = useRef(null)
|
const spineRef = useRef(null)
|
||||||
const [spineData, setSpineData] = useState(null)
|
const [spineData, setSpineData] = useState(null)
|
||||||
const { play, stop } = useAudio()
|
|
||||||
const spineDoneRef = useRef(spineDone)
|
const spineDoneRef = useRef(spineDone)
|
||||||
const voiceOnRef = useRef(voiceOn)
|
const voiceOnRef = useRef(voiceOn)
|
||||||
|
const [voiceSrc, setVoiceSrc] = useState(null)
|
||||||
|
const [voiceReplay, setVoiceReplay] = useState(false)
|
||||||
|
const [spinePlayer, setSpinePlayer] = useState(null)
|
||||||
|
|
||||||
const setSpineDone = (data) => {
|
const setSpineDone = (data) => {
|
||||||
spineDoneRef.current = data
|
spineDoneRef.current = data
|
||||||
@@ -60,26 +63,40 @@ export default function Error() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTitle(content[0])
|
setTitle(content[0])
|
||||||
stop()
|
}, [content, setTitle])
|
||||||
}, [content, setTitle, stop])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!voiceOn) {
|
if (!voiceOn) {
|
||||||
stop()
|
setVoiceSrc(null)
|
||||||
|
} else {
|
||||||
|
setVoiceSrc(`/${import.meta.env.VITE_DIRECTORY_FOLDER}/error.ogg`)
|
||||||
|
if (spinePlayer) {
|
||||||
|
spinePlayer.animationState.setAnimation(0, "Interact", false, 0);
|
||||||
|
spinePlayer.animationState.addAnimation(0, "Relax", true, 0);
|
||||||
}
|
}
|
||||||
}, [voiceOn, stop])
|
}
|
||||||
|
}, [voiceOn])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
voiceOnRef.current = voiceOn
|
voiceOnRef.current = voiceOn
|
||||||
}, [voiceOn])
|
}, [voiceOn])
|
||||||
|
|
||||||
const playVoice = useCallback(() => {
|
const playVoice = useCallback(() => {
|
||||||
play(`/${import.meta.env.VITE_DIRECTORY_FOLDER}/error.ogg`, { overwrite: true })
|
if (lastVoiceState === 'ended' && voiceSrc !== null) {
|
||||||
}, [play])
|
setVoiceReplay(true)
|
||||||
|
}
|
||||||
|
}, [voiceSrc])
|
||||||
|
|
||||||
|
const handleAduioStateChange = useCallback((e, state) => {
|
||||||
|
lastVoiceState = state
|
||||||
|
if (state === 'ended') {
|
||||||
|
setVoiceReplay(false)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (spineRef.current?.children.length === 0 && spineData) {
|
if (spineRef.current?.children.length === 0 && spineData) {
|
||||||
new spine.SpinePlayer(spineRef.current, {
|
setSpinePlayer(new spine.SpinePlayer(spineRef.current, {
|
||||||
skelUrl: `./assets/${filename}.skel`,
|
skelUrl: `./assets/${filename}.skel`,
|
||||||
atlasUrl: `./assets/${filename}.atlas`,
|
atlasUrl: `./assets/${filename}.atlas`,
|
||||||
rawDataURIs: spineData,
|
rawDataURIs: spineData,
|
||||||
@@ -99,7 +116,7 @@ export default function Error() {
|
|||||||
showControls: false,
|
showControls: false,
|
||||||
touch: false,
|
touch: false,
|
||||||
fps: 60,
|
fps: 60,
|
||||||
defaultMix: 0,
|
defaultMix: 0.3,
|
||||||
success: (player) => {
|
success: (player) => {
|
||||||
let isPlayingInteract = false
|
let isPlayingInteract = false
|
||||||
player.animationState.addListener({
|
player.animationState.addListener({
|
||||||
@@ -127,7 +144,7 @@ export default function Error() {
|
|||||||
ani()
|
ani()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
}))
|
||||||
}
|
}
|
||||||
}, [playVoice, spineData]);
|
}, [playVoice, spineData]);
|
||||||
|
|
||||||
@@ -163,6 +180,11 @@ export default function Error() {
|
|||||||
className={`${classes.spine} ${spineDone ? classes.active : ''}`}
|
className={`${classes.spine} ${spineDone ? classes.active : ''}`}
|
||||||
ref={spineRef}
|
ref={spineRef}
|
||||||
/>
|
/>
|
||||||
|
<VoiceElement
|
||||||
|
src={voiceSrc}
|
||||||
|
replay={voiceReplay}
|
||||||
|
handleAduioStateChange={handleAduioStateChange}
|
||||||
|
/>
|
||||||
</main>
|
</main>
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
} from '@/state/language'
|
} from '@/state/language'
|
||||||
import { useHeader } from '@/state/header';
|
import { useHeader } from '@/state/header';
|
||||||
import { useAppbar } from '@/state/appbar';
|
import { useAppbar } from '@/state/appbar';
|
||||||
import useAudio from '@/libs/voice';
|
import VoiceElement from '@/component/voice';
|
||||||
import { useAtom } from 'jotai'
|
import { useAtom } from 'jotai'
|
||||||
import { atomWithStorage } from 'jotai/utils';
|
import { atomWithStorage } from 'jotai/utils';
|
||||||
import CharIcon from '@/component/char_icon';
|
import CharIcon from '@/component/char_icon';
|
||||||
@@ -24,6 +24,7 @@ import useUmami from '@parcellab/react-use-umami';
|
|||||||
import Switch from '@/component/switch';
|
import Switch from '@/component/switch';
|
||||||
|
|
||||||
const voiceOnAtom = atomWithStorage('voiceOn', false)
|
const voiceOnAtom = atomWithStorage('voiceOn', false)
|
||||||
|
let lastVoiceState = 'ended'
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
@@ -36,7 +37,9 @@ export default function Home() {
|
|||||||
} = useHeader()
|
} = useHeader()
|
||||||
const { config } = useConfig()
|
const { config } = useConfig()
|
||||||
const [content, setContent] = useState([])
|
const [content, setContent] = useState([])
|
||||||
const { stop } = useAudio()
|
const [voiceOn] = useAtom(voiceOnAtom)
|
||||||
|
const [voiceSrc, setVoiceSrc] = useState(null)
|
||||||
|
const [voiceReplay, setVoiceReplay] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTitle('dynamic_compile')
|
setTitle('dynamic_compile')
|
||||||
@@ -48,15 +51,33 @@ export default function Home() {
|
|||||||
key: 'skin'
|
key: 'skin'
|
||||||
}])
|
}])
|
||||||
setHeaderIcon(null)
|
setHeaderIcon(null)
|
||||||
stop()
|
}, [setHeaderIcon, setTabs, setTitle])
|
||||||
}, [setHeaderIcon, setTabs, setTitle, stop])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setContent(config?.operators || [])
|
setContent(config?.operators || [])
|
||||||
}, [config])
|
}, [config])
|
||||||
|
|
||||||
|
const handleAduioStateChange = useCallback((e, state) => {
|
||||||
|
lastVoiceState = state
|
||||||
|
if (state === 'ended') {
|
||||||
|
setVoiceReplay(false)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const isShown = useCallback((type) => currentTab === 'all' || currentTab === type, [currentTab])
|
const isShown = useCallback((type) => currentTab === 'all' || currentTab === type, [currentTab])
|
||||||
|
|
||||||
|
const handleVoicePlay = useCallback((src) => {
|
||||||
|
if (!voiceOn) {
|
||||||
|
setVoiceSrc(null)
|
||||||
|
} else {
|
||||||
|
if (src === voiceSrc && lastVoiceState === 'ended') {
|
||||||
|
setVoiceReplay(true)
|
||||||
|
} else {
|
||||||
|
setVoiceSrc(src)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [voiceOn, voiceSrc])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
{
|
{
|
||||||
@@ -71,6 +92,7 @@ export default function Home() {
|
|||||||
key={item.link}
|
key={item.link}
|
||||||
item={item}
|
item={item}
|
||||||
hidden={!isShown(item.type)}
|
hidden={!isShown(item.type)}
|
||||||
|
handleVoicePlay={handleVoicePlay}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
@@ -81,27 +103,17 @@ export default function Home() {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
<VoiceSwitchElement />
|
<VoiceSwitchElement
|
||||||
|
src={voiceSrc}
|
||||||
|
handleAduioStateChange={handleAduioStateChange}
|
||||||
|
replay={voiceReplay}
|
||||||
|
/>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function OperatorElement({ item, hidden }) {
|
function OperatorElement({ item, hidden, handleVoicePlay }) {
|
||||||
const { textDefaultLang, language, alternateLang } = useLanguage()
|
const { textDefaultLang, language, alternateLang } = useLanguage()
|
||||||
const { play, stop, resetSrc } = useAudio()
|
|
||||||
const [voiceOn] = useAtom(voiceOnAtom)
|
|
||||||
|
|
||||||
const playVoice = useCallback(() => {
|
|
||||||
if (!voiceOn) return
|
|
||||||
play(`/${item.link}/assets/${JSON.parse(import.meta.env.VITE_VOICE_FOLDERS).main}/${import.meta.env.VITE_APP_VOICE_URL}`)
|
|
||||||
}, [voiceOn, play, item.link])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!voiceOn) {
|
|
||||||
stop()
|
|
||||||
resetSrc()
|
|
||||||
}
|
|
||||||
}, [voiceOn, stop, resetSrc])
|
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return (
|
return (
|
||||||
@@ -111,7 +123,7 @@ function OperatorElement({ item, hidden }) {
|
|||||||
hidden={hidden}
|
hidden={hidden}
|
||||||
>
|
>
|
||||||
<section
|
<section
|
||||||
onMouseEnter={() => playVoice()}
|
onMouseEnter={() => handleVoicePlay(`/${item.link}/assets/${JSON.parse(import.meta.env.VITE_VOICE_FOLDERS).main}/${import.meta.env.VITE_APP_VOICE_URL}`)}
|
||||||
>
|
>
|
||||||
<section className={classes['background-filler']} />
|
<section className={classes['background-filler']} />
|
||||||
<section className={classes.outline} />
|
<section className={classes.outline} />
|
||||||
@@ -141,10 +153,10 @@ function OperatorElement({ item, hidden }) {
|
|||||||
</section>
|
</section>
|
||||||
</NavLink>
|
</NavLink>
|
||||||
)
|
)
|
||||||
}, [item, hidden, language, alternateLang, textDefaultLang, playVoice])
|
}, [item, hidden, language, alternateLang, textDefaultLang, handleVoicePlay])
|
||||||
}
|
}
|
||||||
|
|
||||||
function VoiceSwitchElement() {
|
function VoiceSwitchElement({ src, replay, handleAduioStateChange }) {
|
||||||
const [voiceOn, setVoiceOn] = useAtom(voiceOnAtom)
|
const [voiceOn, setVoiceOn] = useAtom(voiceOnAtom)
|
||||||
const {
|
const {
|
||||||
setExtraArea,
|
setExtraArea,
|
||||||
@@ -163,7 +175,19 @@ function VoiceSwitchElement() {
|
|||||||
])
|
])
|
||||||
}, [voiceOn, setExtraArea, setVoiceOn])
|
}, [voiceOn, setExtraArea, setVoiceOn])
|
||||||
|
|
||||||
return null
|
return (
|
||||||
|
<VoiceElement
|
||||||
|
src={src}
|
||||||
|
replay={replay}
|
||||||
|
handleAduioStateChange={handleAduioStateChange}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
VoiceSwitchElement.propTypes = {
|
||||||
|
src: PropTypes.string,
|
||||||
|
replay: PropTypes.bool,
|
||||||
|
handleAduioStateChange: PropTypes.func,
|
||||||
}
|
}
|
||||||
|
|
||||||
function ImageElement({ item }) {
|
function ImageElement({ item }) {
|
||||||
|
|||||||
@@ -18,19 +18,23 @@ import {
|
|||||||
import { useHeader } from '@/state/header';
|
import { useHeader } from '@/state/header';
|
||||||
import { useAppbar } from '@/state/appbar';
|
import { useAppbar } from '@/state/appbar';
|
||||||
import { useBackgrounds } from '@/state/background';
|
import { useBackgrounds } from '@/state/background';
|
||||||
import useAudio from '@/libs/voice';
|
import VoiceElement from '@/component/voice';
|
||||||
import useUmami from '@parcellab/react-use-umami'
|
import useUmami from '@parcellab/react-use-umami'
|
||||||
import spine from '!/libs/spine-player'
|
import spine from '!/libs/spine-player'
|
||||||
import '!/libs/spine-player.css'
|
import '!/libs/spine-player.css'
|
||||||
import Border from '@/component/border';
|
import Border from '@/component/border';
|
||||||
import { useI18n } from '@/state/language';
|
import { useI18n } from '@/state/language';
|
||||||
|
import Switch from '@/component/switch';
|
||||||
|
import { atom, useAtom } from 'jotai'
|
||||||
|
|
||||||
|
const musicMapping = JSON.parse(import.meta.env.VITE_MUSIC_MAPPING)
|
||||||
const getVoiceFoler = (lang) => {
|
const getVoiceFoler = (lang) => {
|
||||||
const folderObject = JSON.parse(import.meta.env.VITE_VOICE_FOLDERS)
|
const folderObject = JSON.parse(import.meta.env.VITE_VOICE_FOLDERS)
|
||||||
const voiceFolder = folderObject.sub.find(e => e.lang === lang) || folderObject.sub.find(e => e.name === 'custom')
|
const voiceFolder = folderObject.sub.find(e => e.lang === lang) || folderObject.sub.find(e => e.name === 'custom')
|
||||||
return `${folderObject.main}/${voiceFolder.name}`
|
return `${folderObject.main}/${voiceFolder.name}`
|
||||||
}
|
}
|
||||||
const defaultSpineAnimation = 'Idle'
|
const defaultSpineAnimation = 'Idle'
|
||||||
|
const backgroundAtom = atom(null)
|
||||||
|
|
||||||
const getTabName = (item, language) => {
|
const getTabName = (item, language) => {
|
||||||
if (item.type === 'operator') {
|
if (item.type === 'operator') {
|
||||||
@@ -61,16 +65,18 @@ export default function Operator() {
|
|||||||
const [spinePlayer, setSpinePlayer] = useState(null)
|
const [spinePlayer, setSpinePlayer] = useState(null)
|
||||||
const [voiceLang, _setVoiceLang] = useState(null)
|
const [voiceLang, _setVoiceLang] = useState(null)
|
||||||
const { backgrounds } = useBackgrounds()
|
const { backgrounds } = useBackgrounds()
|
||||||
const [currentBackground, setCurrentBackground] = useState(null)
|
const [currentBackground, setCurrentBackground] = useAtom(backgroundAtom)
|
||||||
const [voiceConfig, setVoiceConfig] = useState(null)
|
const [voiceConfig, setVoiceConfig] = useState(null)
|
||||||
const [subtitleLang, setSubtitleLang] = useState(null)
|
const [subtitleLang, setSubtitleLang] = useState(null)
|
||||||
const [hideSubtitle, setHideSubtitle] = useState(true)
|
const [hideSubtitle, setHideSubtitle] = useState(true)
|
||||||
const { play, stop, getSrc, isPlaying, isPlayingRef } = useAudio()
|
|
||||||
const [subtitleObj, _setSubtitleObj] = useState(null)
|
const [subtitleObj, _setSubtitleObj] = useState(null)
|
||||||
const [currentVoiceId, setCurrentVoiceId] = useState(null)
|
const [currentVoiceId, setCurrentVoiceId] = useState(null)
|
||||||
const voiceLangRef = useRef(voiceLang)
|
const voiceLangRef = useRef(voiceLang)
|
||||||
const subtitleObjRef = useRef(subtitleObj)
|
const subtitleObjRef = useRef(subtitleObj)
|
||||||
const configRef = useRef(config)
|
const configRef = useRef(config)
|
||||||
|
const [voiceSrc, setVoiceSrc] = useState(null)
|
||||||
|
const [isVoicePlaying, _setIsVoicePlaying] = useState(false)
|
||||||
|
const isVoicePlayingRef = useRef(isVoicePlaying)
|
||||||
|
|
||||||
const setVoiceLang = (value) => {
|
const setVoiceLang = (value) => {
|
||||||
voiceLangRef.current = value
|
voiceLangRef.current = value
|
||||||
@@ -82,18 +88,18 @@ export default function Operator() {
|
|||||||
_setSubtitleObj(value)
|
_setSubtitleObj(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setIsVoicePlaying = (value) => {
|
||||||
|
isVoicePlayingRef.current = value
|
||||||
|
_setIsVoicePlaying(value)
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setExtraArea([])
|
setExtraArea([])
|
||||||
stop()
|
}, [setExtraArea])
|
||||||
}, [setExtraArea, stop])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!voiceLang) stop()
|
if (backgrounds.length > 0) setCurrentBackground(backgrounds[0])
|
||||||
}, [stop, voiceLang])
|
}, [backgrounds, setCurrentBackground])
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (backgrounds) setCurrentBackground(backgrounds[0])
|
|
||||||
}, [backgrounds])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSpineData(null)
|
setSpineData(null)
|
||||||
@@ -175,7 +181,7 @@ export default function Operator() {
|
|||||||
showControls: false,
|
showControls: false,
|
||||||
touch: false,
|
touch: false,
|
||||||
fps: 60,
|
fps: 60,
|
||||||
defaultMix: 0,
|
defaultMix: 0.3,
|
||||||
success: (player) => {
|
success: (player) => {
|
||||||
let lastVoiceId = null
|
let lastVoiceId = null
|
||||||
let currentVoiceId = null
|
let currentVoiceId = null
|
||||||
@@ -189,17 +195,13 @@ export default function Operator() {
|
|||||||
const id = voiceId()
|
const id = voiceId()
|
||||||
currentVoiceId = id
|
currentVoiceId = id
|
||||||
setCurrentVoiceId(id)
|
setCurrentVoiceId(id)
|
||||||
play(
|
setVoiceSrc(`/${configRef.current.link}/assets/${getVoiceFoler(voiceLangRef.current)}/${id}.ogg`)
|
||||||
`/${configRef.current.link}/assets/${getVoiceFoler(voiceLangRef.current)}/${id}.ogg`,
|
|
||||||
() => {
|
|
||||||
lastVoiceId = currentVoiceId
|
lastVoiceId = currentVoiceId
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}, [config, spineData, setSpinePlayer, spineAnimation, play]);
|
}, [config, spineData, spineAnimation]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (voiceConfig && voiceLang) {
|
if (voiceConfig && voiceLang) {
|
||||||
@@ -212,13 +214,24 @@ export default function Operator() {
|
|||||||
}
|
}
|
||||||
}, [subtitleLang, voiceConfig, voiceLang])
|
}, [subtitleLang, voiceConfig, voiceLang])
|
||||||
|
|
||||||
|
const handleAduioStateChange = useCallback((e, state) => {
|
||||||
|
switch (state) {
|
||||||
|
case 'play':
|
||||||
|
setIsVoicePlaying(true)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
setIsVoicePlaying(false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (subtitleLang) {
|
if (subtitleLang) {
|
||||||
if (isPlaying) {
|
if (isVoicePlaying) {
|
||||||
setHideSubtitle(false)
|
setHideSubtitle(false)
|
||||||
} else {
|
} else {
|
||||||
const autoHide = () => {
|
const autoHide = () => {
|
||||||
if (isPlayingRef.current) return
|
if (isVoicePlayingRef.current) return
|
||||||
setHideSubtitle(true)
|
setHideSubtitle(true)
|
||||||
}
|
}
|
||||||
setTimeout(autoHide, 5 * 1000)
|
setTimeout(autoHide, 5 * 1000)
|
||||||
@@ -229,29 +242,35 @@ export default function Operator() {
|
|||||||
} else {
|
} else {
|
||||||
setHideSubtitle(true)
|
setHideSubtitle(true)
|
||||||
}
|
}
|
||||||
}, [subtitleLang, isPlaying, isPlayingRef])
|
}, [subtitleLang, isVoicePlaying])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (voiceLang && isPlaying) {
|
if (voiceLang && isVoicePlaying) {
|
||||||
const audioUrl = `/assets/${getVoiceFoler(voiceLang)}/${currentVoiceId}.ogg`
|
const audioUrl = `/assets/${getVoiceFoler(voiceLang)}/${currentVoiceId}.ogg`
|
||||||
if (getSrc() !== (window.location.href.replace(/\/$/g, '') + audioUrl)) {
|
if (voiceSrc !== (window.location.href.replace(/\/$/g, '') + audioUrl)) {
|
||||||
play(`/${config.link}${audioUrl}`)
|
setVoiceSrc(`/${config.link}${audioUrl}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [voiceLang, isPlaying, currentVoiceId, config, getSrc, play])
|
}, [voiceLang, isVoicePlaying, currentVoiceId, config, voiceSrc])
|
||||||
|
|
||||||
|
const playAnimationVoice = useCallback((animation) => {
|
||||||
|
if (voiceLangRef.current) {
|
||||||
|
let id = null
|
||||||
|
if (animation === 'Idle') id = 'CN_011'
|
||||||
|
if (animation === 'Interact') id = 'CN_034'
|
||||||
|
if (animation === 'Special') id = 'CN_042'
|
||||||
|
if (id) {
|
||||||
|
setCurrentVoiceId(id)
|
||||||
|
setVoiceSrc(`/${key}/assets/${getVoiceFoler(voiceLangRef.current)}/${id}.ogg`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [key])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (voiceLang && config) {
|
if (!voiceLang) {
|
||||||
let id = ''
|
setVoiceSrc(null)
|
||||||
if (spineAnimation === 'Idle') id = 'CN_011'
|
|
||||||
if (spineAnimation === 'Interact') id = 'CN_034'
|
|
||||||
if (spineAnimation === 'Special') id = 'CN_042'
|
|
||||||
setCurrentVoiceId(id)
|
|
||||||
play(
|
|
||||||
`/${config.link}/assets/${getVoiceFoler(voiceLang)}/${id}.ogg`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}, [voiceLang, config, spineAnimation, play])
|
}, [voiceLang])
|
||||||
|
|
||||||
const spineSettings = [
|
const spineSettings = [
|
||||||
{
|
{
|
||||||
@@ -260,8 +279,10 @@ export default function Operator() {
|
|||||||
{
|
{
|
||||||
name: 'idle',
|
name: 'idle',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
spinePlayer.animationState.setAnimation(0, "Idle", true, 0)
|
const animation = "Idle"
|
||||||
setSpineAnimation('Idle')
|
playAnimationVoice(animation)
|
||||||
|
spinePlayer.animationState.setAnimation(0, animation, true, 0)
|
||||||
|
setSpineAnimation(animation)
|
||||||
},
|
},
|
||||||
activeRule: () => {
|
activeRule: () => {
|
||||||
return spineAnimation === 'Idle'
|
return spineAnimation === 'Idle'
|
||||||
@@ -269,8 +290,10 @@ export default function Operator() {
|
|||||||
}, {
|
}, {
|
||||||
name: 'interact',
|
name: 'interact',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
spinePlayer.animationState.setAnimation(0, "Interact", true, 0)
|
const animation = "Interact"
|
||||||
setSpineAnimation('Interact')
|
playAnimationVoice(animation)
|
||||||
|
spinePlayer.animationState.setAnimation(0, animation, true, 0)
|
||||||
|
setSpineAnimation(animation)
|
||||||
},
|
},
|
||||||
activeRule: () => {
|
activeRule: () => {
|
||||||
return spineAnimation === 'Interact'
|
return spineAnimation === 'Interact'
|
||||||
@@ -278,8 +301,10 @@ export default function Operator() {
|
|||||||
}, {
|
}, {
|
||||||
name: 'special',
|
name: 'special',
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
spinePlayer.animationState.setAnimation(0, "Special", true, 0)
|
const animation = "Special"
|
||||||
setSpineAnimation('Special')
|
playAnimationVoice(animation)
|
||||||
|
spinePlayer.animationState.setAnimation(0, animation, true, 0)
|
||||||
|
setSpineAnimation(animation)
|
||||||
},
|
},
|
||||||
activeRule: () => {
|
activeRule: () => {
|
||||||
return spineAnimation === 'Special'
|
return spineAnimation === 'Special'
|
||||||
@@ -297,6 +322,9 @@ export default function Operator() {
|
|||||||
} else {
|
} else {
|
||||||
setVoiceLang(null)
|
setVoiceLang(null)
|
||||||
}
|
}
|
||||||
|
if (!isVoicePlayingRef.current) {
|
||||||
|
playAnimationVoice(spineAnimation)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
activeRule: () => {
|
activeRule: () => {
|
||||||
return voiceLang === item
|
return voiceLang === item
|
||||||
@@ -320,6 +348,9 @@ export default function Operator() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}) || []
|
}) || []
|
||||||
|
}, {
|
||||||
|
name: 'music',
|
||||||
|
el: <MusicElement />
|
||||||
}, {
|
}, {
|
||||||
name: 'backgrounds',
|
name: 'backgrounds',
|
||||||
options: backgrounds.map((item) => {
|
options: backgrounds.map((item) => {
|
||||||
@@ -348,6 +379,13 @@ export default function Operator() {
|
|||||||
}}>
|
}}>
|
||||||
{
|
{
|
||||||
spineSettings.map((item) => {
|
spineSettings.map((item) => {
|
||||||
|
if (item.el) {
|
||||||
|
return (
|
||||||
|
<section key={item.name}>
|
||||||
|
{item.el}
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
if (item.options.length === 0) return null
|
if (item.options.length === 0) return null
|
||||||
return (
|
return (
|
||||||
<section key={item.name}>
|
<section key={item.name}>
|
||||||
@@ -417,7 +455,7 @@ export default function Operator() {
|
|||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section className={classes.container} style={currentBackground && {
|
<section className={classes.container} style={currentBackground && {
|
||||||
backgroundImage: `url(/${key}/assets/${import.meta.env.VITE_BACKGROUND_FOLDER}/${currentBackground})`
|
backgroundImage: `url(/chen/assets/${import.meta.env.VITE_BACKGROUND_FOLDER}/${currentBackground})`
|
||||||
}} >
|
}} >
|
||||||
{
|
{
|
||||||
config && (
|
config && (
|
||||||
@@ -426,7 +464,7 @@ export default function Operator() {
|
|||||||
}
|
}
|
||||||
<section ref={spineRef} className={classes.wrapper} />
|
<section ref={spineRef} className={classes.wrapper} />
|
||||||
{currentVoiceId && subtitleObj && (
|
{currentVoiceId && subtitleObj && (
|
||||||
<section className={`${classes.voice} ${hideSubtitle ? '' : classes.active }`}>
|
<section className={`${classes.voice} ${hideSubtitle ? '' : classes.active}`}>
|
||||||
<section className={classes.type}>{subtitleObj[currentVoiceId]?.title}</section>
|
<section className={classes.type}>{subtitleObj[currentVoiceId]?.title}</section>
|
||||||
<section className={classes.subtitle}>
|
<section className={classes.subtitle}>
|
||||||
<span>{subtitleObj[currentVoiceId]?.text}</span>
|
<span>{subtitleObj[currentVoiceId]?.text}</span>
|
||||||
@@ -437,6 +475,80 @@ export default function Operator() {
|
|||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<Border />
|
<Border />
|
||||||
|
<VoiceElement
|
||||||
|
src={voiceSrc}
|
||||||
|
handleAduioStateChange={handleAduioStateChange}
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function MusicElement() {
|
||||||
|
const [enableMusic, setEnableMusic] = useState(false)
|
||||||
|
const { i18n } = useI18n()
|
||||||
|
const musicIntroRef = useRef(null)
|
||||||
|
const musicLoopRef = useRef(null)
|
||||||
|
const [background,] = useAtom(backgroundAtom)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (musicIntroRef.current && musicIntroRef.current) {
|
||||||
|
musicIntroRef.current.volume = 0.5
|
||||||
|
musicLoopRef.current.volume = 0.5
|
||||||
|
}
|
||||||
|
}, [musicIntroRef, musicLoopRef])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!enableMusic || background) {
|
||||||
|
musicIntroRef.current.pause()
|
||||||
|
musicLoopRef.current.pause()
|
||||||
|
}
|
||||||
|
}, [enableMusic, background])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (background && enableMusic) {
|
||||||
|
const introOgg = musicMapping[background].intro
|
||||||
|
const intro = `./chen/assets/${import.meta.env.VITE_MUSIC_FOLDER}/${introOgg}`
|
||||||
|
const loop = `./chen/assets/${import.meta.env.VITE_MUSIC_FOLDER}/${musicMapping[background].loop}`
|
||||||
|
musicLoopRef.current.src = loop
|
||||||
|
if (introOgg) {
|
||||||
|
musicIntroRef.current.src = intro || loop
|
||||||
|
} else {
|
||||||
|
musicLoopRef.current.play()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [background, enableMusic])
|
||||||
|
|
||||||
|
const handleIntroTimeUpdate = useCallback(() => {
|
||||||
|
if (musicIntroRef.current.currentTime >= musicIntroRef.current.duration - 0.3) {
|
||||||
|
musicIntroRef.current.pause()
|
||||||
|
musicLoopRef.current.play()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const handleLoopTimeUpdate = useCallback(() => {
|
||||||
|
if (musicLoopRef.current.currentTime >= musicLoopRef.current.duration - 0.3) {
|
||||||
|
musicLoopRef.current.currentTime = 0
|
||||||
|
musicLoopRef.current.play()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section>
|
||||||
|
<section
|
||||||
|
className={classes.titleWithSwitch}
|
||||||
|
onClick={() => setEnableMusic(!enableMusic)}
|
||||||
|
>
|
||||||
|
<section className={classes.text}>{i18n('music')}</section>
|
||||||
|
<section className={classes.switch}>
|
||||||
|
<Switch on={enableMusic} />
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
<audio ref={musicIntroRef} preload="auto" autoPlay onTimeUpdate={() => handleIntroTimeUpdate()}>
|
||||||
|
<source type="audio/ogg" />
|
||||||
|
</audio>
|
||||||
|
<audio ref={musicLoopRef} preload="auto" onTimeUpdate={() => handleLoopTimeUpdate()}>
|
||||||
|
<source type="audio/ogg"/>
|
||||||
|
</audio>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
padding-top: 10rem;
|
padding-top: 10rem;
|
||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
gap: 2rem;
|
gap: 2rem;
|
||||||
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spine {
|
.spine {
|
||||||
@@ -38,6 +39,7 @@
|
|||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.main {
|
.main {
|
||||||
padding-top: 6rem;
|
padding-top: 6rem;
|
||||||
|
max-height: calc(100vh - 6rem);
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
@@ -46,6 +48,7 @@
|
|||||||
@media (max-width: 480px) {
|
@media (max-width: 480px) {
|
||||||
.main {
|
.main {
|
||||||
padding-top: 4rem;
|
padding-top: 4rem;
|
||||||
|
max-height: calc(100vh - 4rem);
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { read } from './yaml.js';
|
|||||||
import AssetsProcessor from './assets_processor.js'
|
import AssetsProcessor from './assets_processor.js'
|
||||||
import EnvGenerator from './env_generator.js'
|
import EnvGenerator from './env_generator.js'
|
||||||
|
|
||||||
export default function ({ backgrounds }) {
|
export default function ({ backgrounds, musicMapping }) {
|
||||||
const extractedFolder = path.join(__projectRoot, __config.folder.operator, '_directory')
|
const extractedFolder = path.join(__projectRoot, __config.folder.operator, '_directory')
|
||||||
const targetFolder = path.join(__projectRoot, __config.folder.release, __config.folder.directory);
|
const targetFolder = path.join(__projectRoot, __config.folder.release, __config.folder.directory);
|
||||||
const sourceFolder = path.join(__projectRoot, __config.folder.operator);
|
const sourceFolder = path.join(__projectRoot, __config.folder.operator);
|
||||||
@@ -78,6 +78,12 @@ export default function ({ backgrounds }) {
|
|||||||
}, {
|
}, {
|
||||||
key: "error_files",
|
key: "error_files",
|
||||||
value: JSON.stringify(__config.directory.error).replace('#', '%23')
|
value: JSON.stringify(__config.directory.error).replace('#', '%23')
|
||||||
|
}, {
|
||||||
|
key: "music_folder",
|
||||||
|
value: __config.folder.music
|
||||||
|
}, {
|
||||||
|
key: "music_mapping",
|
||||||
|
value: JSON.stringify(musicMapping)
|
||||||
}
|
}
|
||||||
]), path.join(__projectRoot, 'directory', '.env'))
|
]), path.join(__projectRoot, 'directory', '.env'))
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ export default class Music {
|
|||||||
}
|
}
|
||||||
|
|
||||||
success() {
|
success() {
|
||||||
this.changeMusic(window.settings.currentBackground)
|
if (this.#currentMusic === null) this.changeMusic(window.settings.currentBackground)
|
||||||
}
|
}
|
||||||
|
|
||||||
changeMusic(name) {
|
changeMusic(name) {
|
||||||
|
|||||||
@@ -93,10 +93,10 @@ window.wallpaperPropertyListener = {
|
|||||||
}
|
}
|
||||||
if (properties.music_title) {
|
if (properties.music_title) {
|
||||||
window.music.useMusic = properties.music_title.value
|
window.music.useMusic = properties.music_title.value
|
||||||
|
window.music.changeMusic(properties.music_selection.value)
|
||||||
window.settings.functionInsights("useMusic", Object.keys(properties) !== 1)
|
window.settings.functionInsights("useMusic", Object.keys(properties) !== 1)
|
||||||
}
|
}
|
||||||
if (properties.music_selection) {
|
if (properties.music_selection) {
|
||||||
// TODO: not working
|
|
||||||
window.music.changeMusic(properties.music_selection.value)
|
window.music.changeMusic(properties.music_selection.value)
|
||||||
window.settings.functionInsights("music_selection", Object.keys(properties) !== 1)
|
window.settings.functionInsights("music_selection", Object.keys(properties) !== 1)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user