Merge pull request #2 from TreetopFlyer/feature/layout-updates
Feature/layout updates
This commit is contained in:
		
						commit
						a32415f952
					
				
							
								
								
									
										29
									
								
								js/store.js
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								js/store.js
									
									
									
									
									
								
							@ -77,12 +77,29 @@ export const Grade =(inTest)=>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ErrorCol = 
 | 
				
			||||||
 | 
					    [30,   25,   20,   15,   10,   5,    0,    -5,   -10,  -15 ]
 | 
				
			||||||
 | 
					const ErrorLUT = [
 | 
				
			||||||
 | 
					    [0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00],
 | 
				
			||||||
 | 
					    [0.00, 0.00, 0.00, 0.00, 0.10, 0.15, 0.10, 0.10, 0.00, 0.00],
 | 
				
			||||||
 | 
					    [0.00, 0.00, 0.02, 0.05, 0.15, 0.20, 0.30, 0.15, 0.05, 0.00],
 | 
				
			||||||
 | 
					    [0.00, 0.02, 0.05, 0.10, 0.20, 0.40, 0.60, 0.30, 0.05, 0.00]
 | 
				
			||||||
 | 
					];
 | 
				
			||||||
 | 
					/** @type {(inState:Store.State)=>void} */
 | 
				
			||||||
 | 
					const ErrorProbability =(inState)=>
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    const miss = inState.Stim.Value - (inState.Live.Mark.Test?.Stim ?? inState.Stim.Value);
 | 
				
			||||||
 | 
					    inState.Live.Mark.Errs = ErrorLUT[inState.Errs]?.[ErrorCol.indexOf(miss)] ?? 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Creates a new Store.Context object that contain the current selections 
 | 
					/** Creates a new Store.Context object that contain the current selections 
 | 
				
			||||||
 * @type {(inState:Store.State, inTest?:Store.Test)=>Store.Context} */
 | 
					 * @type {(inState:Store.State, inTest?:Store.Test)=>Store.Context} */
 | 
				
			||||||
const Reselect =(inState, inTest)=>
 | 
					const Reselect =(inState, inTest)=>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /** @type {Store.Context} */
 | 
					    /** @type {Store.Context} */
 | 
				
			||||||
    const output = { Test:inTest??inState.Live.Test };
 | 
					    const output = { Test:inTest??inState.Live.Test, Mark:{User:undefined} };
 | 
				
			||||||
    const column = ColumnMapping[inState.Freq.Value];
 | 
					    const column = ColumnMapping[inState.Freq.Value];
 | 
				
			||||||
    if(column && output.Test)
 | 
					    if(column && output.Test)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -93,7 +110,8 @@ const Reselect =(inState, inTest)=>
 | 
				
			|||||||
            if(plot.Hz == hz)
 | 
					            if(plot.Hz == hz)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                output.Freq = plot;
 | 
					                output.Freq = plot;
 | 
				
			||||||
                output.Mark = inState.Chan.Value ? plot.UserR : plot.UserL;
 | 
					                output.Mark.User = inState.Chan.Value ? plot.UserR : plot.UserL;
 | 
				
			||||||
 | 
					                output.Mark.Test = inState.Chan.Value ? plot.TestR : plot.TestL;
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -179,8 +197,8 @@ export function Reducer(inState, inAction)
 | 
				
			|||||||
        if(clone.Live.Test && clone.Live.Freq)
 | 
					        if(clone.Live.Test && clone.Live.Freq)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            const key = clone.Chan.Value == 0 ? "UserL" : "UserR";
 | 
					            const key = clone.Chan.Value == 0 ? "UserL" : "UserR";
 | 
				
			||||||
            clone.Live.Mark = Data !== null ? {Stim:clone.Stim.Value, Resp:Data} : undefined;
 | 
					            clone.Live.Mark.User = Data !== null ? {Stim:clone.Stim.Value, Resp:Data} : undefined;
 | 
				
			||||||
            clone.Live.Freq[key] = clone.Live.Mark;
 | 
					            clone.Live.Freq[key] = clone.Live.Mark.User;
 | 
				
			||||||
            clone.Draw[key] = Redraw(clone.Live.Test, clone.Chan.Value, clone.Stim, true);
 | 
					            clone.Draw[key] = Redraw(clone.Live.Test, clone.Chan.Value, clone.Stim, true);
 | 
				
			||||||
            clone.Live.Test.Done = Grade(clone.Live.Test);
 | 
					            clone.Live.Test.Done = Grade(clone.Live.Test);
 | 
				
			||||||
            SaveTests(clone);
 | 
					            SaveTests(clone);
 | 
				
			||||||
@ -227,6 +245,7 @@ export function Reducer(inState, inAction)
 | 
				
			|||||||
        clone.Show.Answer = Data;
 | 
					        clone.Show.Answer = Data;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ErrorProbability(clone);
 | 
				
			||||||
    SaveSettings(clone);
 | 
					    SaveSettings(clone);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return clone;
 | 
					    return clone;
 | 
				
			||||||
@ -328,7 +347,7 @@ export const Initial = Reducer(
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        Test: undefined,
 | 
					        Test: undefined,
 | 
				
			||||||
        Freq: undefined,
 | 
					        Freq: undefined,
 | 
				
			||||||
        Mark: undefined
 | 
					        Mark: {User: undefined}
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    Draw:
 | 
					    Draw:
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										47
									
								
								js/ui.js
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								js/ui.js
									
									
									
									
									
								
							@ -5,8 +5,8 @@ import * as Tone from "./tone.js";
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
/** @typedef {({children, classes}:{children?:preact.ComponentChildren, classes?:string})=>preact.VNode} BasicElement */
 | 
					/** @typedef {({children, classes}:{children?:preact.ComponentChildren, classes?:string})=>preact.VNode} BasicElement */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @type {({children, icon, light, disabled, inactive, onClick, classes}:{children:preact.VNode, icon?:preact.VNode, light:boolean, disabled:boolean, inactive:boolean, onClick:()=>void, classes?:string})=>preact.VNode} */
 | 
					/** @type {({children, icon, light, disabled, inactive, onClick, classes, classesActive}:{children:preact.VNode, icon?:preact.VNode, light:boolean, disabled:boolean, inactive:boolean, onClick:()=>void, classes?:string, classesActive?:string})=>preact.VNode} */
 | 
				
			||||||
export function Button({children, icon, light, disabled, inactive, onClick, classes})
 | 
					export function Button({children, icon, light, disabled, inactive, onClick, classes, classesActive})
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    const [FlashGet, FlashSet] = React.useState(0);
 | 
					    const [FlashGet, FlashSet] = React.useState(0);
 | 
				
			||||||
    const handleClick =()=>
 | 
					    const handleClick =()=>
 | 
				
			||||||
@ -19,7 +19,7 @@ export function Button({children, icon, light, disabled, inactive, onClick, clas
 | 
				
			|||||||
    return html`
 | 
					    return html`
 | 
				
			||||||
    <button
 | 
					    <button
 | 
				
			||||||
        onClick=${handleClick}
 | 
					        onClick=${handleClick}
 | 
				
			||||||
        class="relative flex items-stretch rounded-lg text(lg white) border-t(1 solid [#00000011]) border-b(2 solid [#ffffff]) ring-inset ring-black font-sans group transition-all duration-500 ${classes} ${disabled ? "bg-zinc-400" : "bg-earmark"} ${(inactive||disabled) && "cursor-default"}"
 | 
					        class="relative flex items-stretch rounded-lg text(lg white) border-t(1 solid [#00000011]) border-b(2 solid [#ffffff]) ring-inset ring-black font-sans group transition-all duration-500 ${classes} ${disabled ? "bg-zinc-400" : (classesActive||"bg-earmark")} ${(inactive||disabled) && "cursor-default"}"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
        <span class="absolute top-0 left-0 w-full h-full rounded-lg bg-black transition-opacity duration-300 opacity-0 ${(!inactive && !disabled) && "group-hover:opacity-50"}"></span>
 | 
					        <span class="absolute top-0 left-0 w-full h-full rounded-lg bg-black transition-opacity duration-300 opacity-0 ${(!inactive && !disabled) && "group-hover:opacity-50"}"></span>
 | 
				
			||||||
        ${ FlashGet > 0 && html`<span key=${FlashGet} class="absolute top-0 left-0 w-full h-full rounded-lg bg-green-400 shadow-glow-green-300 animate-flash"></span>` }
 | 
					        ${ FlashGet > 0 && html`<span key=${FlashGet} class="absolute top-0 left-0 w-full h-full rounded-lg bg-green-400 shadow-glow-green-300 animate-flash"></span>` }
 | 
				
			||||||
@ -58,11 +58,11 @@ export const Header =()=>
 | 
				
			|||||||
                </select>
 | 
					                </select>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="box-buttons w-full mt-2">
 | 
					            <div class="box-buttons w-full mt-2">
 | 
				
			||||||
                <p>Patient Error:</p>
 | 
					                <p class="px-2">Patient Reliability:</p>
 | 
				
			||||||
                <${Button} inactive=${State.Errs == 0.0} light=${State.Errs == 0.0} classes="flex-1 text-xs" onClick=${()=>Dispatch({Name:"Errs", Data:0.0})}>None<//>
 | 
					                <${Button} inactive=${State.Errs == 0} light=${State.Errs == 0} classes="flex-[1.5] text-xs" classesActive="" onClick=${()=>Dispatch({Name:"Errs", Data:0})}>Perfect (Training Mode)<//>
 | 
				
			||||||
                <${Button} inactive=${State.Errs == 0.1} light=${State.Errs == 0.1} classes="flex-1 text-xs" onClick=${()=>Dispatch({Name:"Errs", Data:0.1})}>Slight<//>
 | 
					                <${Button} inactive=${State.Errs == 1} light=${State.Errs == 1} classes="flex-1     text-xs" classesActive="bg-yellow-600" onClick=${()=>Dispatch({Name:"Errs", Data:1})}>Good<//>
 | 
				
			||||||
                <${Button} inactive=${State.Errs == 0.3} light=${State.Errs == 0.3} classes="flex-1 text-xs" onClick=${()=>Dispatch({Name:"Errs", Data:0.3})}>Moderate<//>
 | 
					                <${Button} inactive=${State.Errs == 2} light=${State.Errs == 2} classes="flex-1     text-xs" classesActive="bg-orange-600" onClick=${()=>Dispatch({Name:"Errs", Data:2})}>Reduced<//>
 | 
				
			||||||
                <${Button} inactive=${State.Errs == 0.6} light=${State.Errs == 0.6} classes="flex-1 text-xs" onClick=${()=>Dispatch({Name:"Errs", Data:0.6})}>Severe<//>
 | 
					                <${Button} inactive=${State.Errs == 3} light=${State.Errs == 3} classes="flex-1     text-xs" classesActive="bg-red-600" onClick=${()=>Dispatch({Name:"Errs", Data:3})}>Poor<//>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -95,6 +95,7 @@ export const Display =()=>
 | 
				
			|||||||
    `;
 | 
					    `;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** @type {BasicElement} */
 | 
					/** @type {BasicElement} */
 | 
				
			||||||
export const Controls =()=>
 | 
					export const Controls =()=>
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -113,27 +114,14 @@ export const Controls =()=>
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if(State.Live.Freq)
 | 
					            if(State.Live.Freq)
 | 
				
			||||||
            {
 | 
					            {
 | 
				
			||||||
                const testMark = State.Live.Freq[/** @type {"TestL"|"TestR"}*/(`Test${State.Chan.Value ? "R":"L"}`)];
 | 
					                const audible = State.Stim.Value >= (State.Live.Mark.Test?.Stim??0);
 | 
				
			||||||
                const audible = State.Stim.Value >= testMark.Stim;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const error = State.Stim.Value - testMark.Stim;
 | 
					                const errorScaled = State.Live.Mark.Errs;
 | 
				
			||||||
                let errorMapped = error;
 | 
					 | 
				
			||||||
                     if(error >= 30){ errorMapped = 0.0; }
 | 
					 | 
				
			||||||
                else if(error >= 25){ errorMapped = 0.1; }
 | 
					 | 
				
			||||||
                else if(error >= 20){ errorMapped = 0.2; }
 | 
					 | 
				
			||||||
                else if(error >= 15){ errorMapped = 0.3; }
 | 
					 | 
				
			||||||
                else if(error >= 10){ errorMapped = 0.5; }
 | 
					 | 
				
			||||||
                else if(error >=  5){ errorMapped = 0.7; }
 | 
					 | 
				
			||||||
                else if(error ==  0){ errorMapped = 1.0; }
 | 
					 | 
				
			||||||
                else if(error >= -5){ errorMapped = 0.5; }
 | 
					 | 
				
			||||||
                else if(error >=-10){ errorMapped = 0.1; }
 | 
					 | 
				
			||||||
                else if(error >=-15){ errorMapped = 0.0; }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                const errorScaled = State.Errs*errorMapped;
 | 
					 | 
				
			||||||
                const errorSampled = Math.random() < errorScaled;
 | 
					                const errorSampled = Math.random() < errorScaled;
 | 
				
			||||||
                const percieved = errorSampled ? !audible : audible
 | 
					                const percieved = errorSampled ? !audible : audible;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const handler = percieved ? ()=>playSet(2) : ()=>playSet(0);
 | 
					                const handler = percieved ? ()=>playSet(2) : ()=>playSet(0);
 | 
				
			||||||
                console.log("Error:", error, "Error Mapped:", errorMapped, "Error Scaled:", errorScaled, "Error Sampled:", errorSampled);
 | 
					                console.log("Audible:", audible, "Error Scaled:", errorScaled, "Error Sampled:", errorSampled, "Percieved", percieved);
 | 
				
			||||||
                timer = setTimeout(handler, 800 + Math.random()*1300);
 | 
					                timer = setTimeout(handler, 800 + Math.random()*1300);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -205,6 +193,7 @@ export const Controls =()=>
 | 
				
			|||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
 | 
					                <p class="text-center mt-2">Response${State.Live.Mark.Errs > 0 && ` (${State.Live.Mark.Errs*100}% Error Chance)` }:</p>
 | 
				
			||||||
                <svg width="80" height="80" preserveAspectRatio="none" viewBox="0 0 79 79" fill="none" class="mx-auto mt-2">
 | 
					                <svg width="80" height="80" preserveAspectRatio="none" viewBox="0 0 79 79" fill="none" class="mx-auto mt-2">
 | 
				
			||||||
                    <circle fill="url(#metal)" cx="39" cy="40" r="35"></circle>
 | 
					                    <circle fill="url(#metal)" cx="39" cy="40" r="35"></circle>
 | 
				
			||||||
                    <circle fill="url(#metal)" cx="39.5" cy="39.5" r="29.5" transform="rotate(180 39.5 39.5)"></circle>
 | 
					                    <circle fill="url(#metal)" cx="39.5" cy="39.5" r="29.5" transform="rotate(180 39.5 39.5)"></circle>
 | 
				
			||||||
@ -267,7 +256,7 @@ export const Controls =()=>
 | 
				
			|||||||
                        `}
 | 
					                        `}
 | 
				
			||||||
                        onClick=${()=>Dispatch({Name:"Mark", Data:null })}
 | 
					                        onClick=${()=>Dispatch({Name:"Mark", Data:null })}
 | 
				
			||||||
                        classes="text-sm w-full"
 | 
					                        classes="text-sm w-full"
 | 
				
			||||||
                        disabled=${State.Live.Mark == undefined}
 | 
					                        disabled=${State.Live.Mark.User == undefined}
 | 
				
			||||||
                    >
 | 
					                    >
 | 
				
			||||||
                        Clear
 | 
					                        Clear
 | 
				
			||||||
                    <//>
 | 
					                    <//>
 | 
				
			||||||
@ -284,9 +273,9 @@ export const Audiogram =()=>
 | 
				
			|||||||
    const [State] = Store.Consumer();
 | 
					    const [State] = Store.Consumer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const testMarksL = State.Draw.TestL.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${false}/>`);
 | 
					    const testMarksL = State.Draw.TestL.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${false}/>`);
 | 
				
			||||||
    const userMarksL = State.Draw.UserL.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${false} classes=${State.Live.Mark == p.Mark ? "stroke-bold":""}/>`);
 | 
					    const userMarksL = State.Draw.UserL.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${false} classes=${State.Live.Mark.User == p.Mark ? "stroke-bold":""}/>`);
 | 
				
			||||||
    const testMarksR = State.Draw.TestR.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${true} />`);
 | 
					    const testMarksR = State.Draw.TestR.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${true} />`);
 | 
				
			||||||
    const userMarksR = State.Draw.UserR.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${true} classes=${State.Live.Mark == p.Mark ? "stroke-bold":""}/>`);
 | 
					    const userMarksR = State.Draw.UserR.Points.map(p=>html`<${Mark} x=${p.X} y=${p.Y} response=${p.Mark?.Resp} right=${true} classes=${State.Live.Mark.User == p.Mark ? "stroke-bold":""}/>`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const testLinesL = State.Draw.TestL.Paths.map( p=>html`<line class="opacity-60" x1=${p.Head.X} y1=${p.Head.Y} x2=${p.Tail.X} y2=${p.Tail.Y} />`);
 | 
					    const testLinesL = State.Draw.TestL.Paths.map( p=>html`<line class="opacity-60" x1=${p.Head.X} y1=${p.Head.Y} x2=${p.Tail.X} y2=${p.Tail.Y} />`);
 | 
				
			||||||
    const userLinesL = State.Draw.UserL.Paths.map( p=>html`<line class="opacity-60" x1=${p.Head.X} y1=${p.Head.Y} x2=${p.Tail.X} y2=${p.Tail.Y} />`);
 | 
					    const userLinesL = State.Draw.UserL.Paths.map( p=>html`<line class="opacity-60" x1=${p.Head.X} y1=${p.Head.Y} x2=${p.Tail.X} y2=${p.Tail.Y} />`);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										7
									
								
								ts/store.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								ts/store.d.ts
									
									
									
									
										vendored
									
									
								
							@ -21,7 +21,12 @@ declare namespace Store {
 | 
				
			|||||||
  type Context = {
 | 
					  type Context = {
 | 
				
			||||||
    Test?: Test;
 | 
					    Test?: Test;
 | 
				
			||||||
    Freq?: TestFrequency;
 | 
					    Freq?: TestFrequency;
 | 
				
			||||||
    Mark?: TestFrequencySample;
 | 
					    Mark:
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      User?: TestFrequencySample,
 | 
				
			||||||
 | 
					      Test?: TestFrequencySample,
 | 
				
			||||||
 | 
					      Errs : number
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
  type StatePartSimple =
 | 
					  type StatePartSimple =
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user