Video options and initial setup page
parent
811207dc87
commit
ca264d4e6b
@ -1,11 +1,72 @@
|
||||
import React from 'react'
|
||||
import useGameState from '../../hooks/useGameState'
|
||||
import useLocalStorage from '../../hooks/useLocalStorage'
|
||||
|
||||
import styles from './Options.module.css'
|
||||
import useSharedState from '../../hooks/useSharedState'
|
||||
|
||||
export default function () {
|
||||
const [currentTab, setCurrentTab] = useSharedState('optionsTab', 'video')
|
||||
|
||||
const gameState = useGameState()
|
||||
const saveFile1 = useLocalStorage('save1', null)
|
||||
const saveFile2 = useLocalStorage('save2', null)
|
||||
const saveFile3 = useLocalStorage('save3', null)
|
||||
|
||||
const [videoOptions, setVideoOptions] = useLocalStorage('video')
|
||||
console.log(videoOptions)
|
||||
|
||||
function OptionButton({name}) {
|
||||
return (
|
||||
<button
|
||||
className={styles.optionMenuButton + (currentTab === name ? ' ' + styles.selected : '')}
|
||||
onClick={ev => setCurrentTab(name)}
|
||||
>
|
||||
{name}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
function OptionSetting({name, label}){
|
||||
return (
|
||||
<div className={styles.optionContainer}>
|
||||
<input
|
||||
name={name}
|
||||
type="checkbox"
|
||||
checked={videoOptions[name]}
|
||||
onChange={ev => setVideoOptions(current => ({
|
||||
...current,
|
||||
[name]: ev.target.checked
|
||||
}))}
|
||||
/>
|
||||
<label htmlFor={name}>{label}</label>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ul>
|
||||
<li>Nothing</li>
|
||||
</ul>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.sidebar}>
|
||||
<OptionButton name="video"/>
|
||||
<OptionButton name="save / load"/>
|
||||
</div>
|
||||
<div className={styles.settings}>
|
||||
{currentTab === 'video' && (
|
||||
<>
|
||||
<h3>Video Options</h3>
|
||||
<p>Feel free to tweak these to your liking - they have no effect on gameplay.</p>
|
||||
<OptionSetting name="fuzzing" label="Text Glow"/>
|
||||
<OptionSetting name="flickering" label="Screen Flickering"/>
|
||||
<OptionSetting name="scanLines" label="Scan Lines"/>
|
||||
<OptionSetting name="imageBackground" label="Image Background"/>
|
||||
</>
|
||||
)}
|
||||
{currentTab === 'save / load' && (
|
||||
<p>Save / load</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -0,0 +1,37 @@
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
padding-top: 10px;
|
||||
width: 100px;
|
||||
border-right: solid 1px rgba(255,255,255,.2);
|
||||
}
|
||||
|
||||
.settings {
|
||||
flex: 1;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.optionMenuButton {
|
||||
display: block;
|
||||
width: 80px;
|
||||
margin: 10px;
|
||||
background: transparent;
|
||||
color: white;
|
||||
border: solid 1px white;
|
||||
padding: 4px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.optionMenuButton.selected {
|
||||
color: black;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.optionContainer input {
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
import React from 'react'
|
||||
|
||||
import styles from './Setup.module.css'
|
||||
|
||||
export default function Setup() {
|
||||
return (
|
||||
<div className={styles.options}>
|
||||
<h1>Setup</h1>
|
||||
<p>
|
||||
This game has visual effects which could be problematic for players
|
||||
with photosensitive epilepsy or impaired vision, including:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Rapid pulsing text glow</li>
|
||||
<li>Screen flickering</li>
|
||||
<li>Moving and repeating screen overlays</li>
|
||||
<li>An image background that may lower visual contrast in reading text</li>
|
||||
</ul>
|
||||
<p>
|
||||
These effects are <strong><em>entirely optional</em></strong>, and do not affect
|
||||
the gameplay in any way. Do you wish to start with these effects turned
|
||||
on?
|
||||
</p>
|
||||
<p style={{textAlign: 'center'}}>
|
||||
<button onClick={startWithEffects}>Start with effects</button>
|
||||
<button onClick={startWithoutEffects}>Start without effects</button>
|
||||
</p>
|
||||
<p style={{opacity: .6}}>
|
||||
<strong>Note:</strong> Each of these options can be enabled or disabled
|
||||
later via the in-game video options menu.
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function startWithEffects() {
|
||||
window.localStorage.setItem('video', JSON.stringify({
|
||||
fuzzing: true,
|
||||
flickering: true,
|
||||
scanLines: true,
|
||||
imageBackground: true
|
||||
}))
|
||||
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
function startWithoutEffects() {
|
||||
window.localStorage.setItem('video', JSON.stringify({
|
||||
fuzzing: false,
|
||||
flickering: false,
|
||||
scanLines: false,
|
||||
imageBackground: false
|
||||
}))
|
||||
|
||||
window.location.reload()
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
.options {
|
||||
max-width: 800px;
|
||||
width: calc(100vw - 200px);
|
||||
}
|
||||
|
||||
.options button {
|
||||
background: transparent;
|
||||
border: solid 1px white;
|
||||
margin: 5px 15px;
|
||||
color: white;
|
||||
padding: 5px 10px;
|
||||
font-family: inherit;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.options {
|
||||
color: rgba(255,255,255,.7);
|
||||
}
|
||||
|
||||
.options strong {
|
||||
color: white;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import {useState, useEffect} from 'react'
|
||||
import useSharedState from './useSharedState'
|
||||
|
||||
export default function useLocalStorage(key, initialValue) {
|
||||
const raw = window.localStorage.getItem(key)
|
||||
|
||||
let init
|
||||
try {
|
||||
init = raw ? JSON.parse(raw) : initialValue
|
||||
} catch {
|
||||
init = initialValue
|
||||
}
|
||||
|
||||
const [storedValue, setStoredValue] = useSharedState('localstorage_' + key, init)
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
window.localStorage.setItem(key, JSON.stringify(storedValue));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}, [storedValue])
|
||||
|
||||
return [storedValue, setStoredValue];
|
||||
}
|
Loading…
Reference in New Issue