diff --git a/app.js b/app.js index 374c9b3..6355aad 100644 --- a/app.js +++ b/app.js @@ -3,7 +3,64 @@ import * as TW from "https://esm.sh/@twind/core@1.0.1"; import TWPreTail from "https://esm.sh/@twind/preset-tailwind@1.0.1"; import TWPreAuto from "https://esm.sh/@twind/preset-autoprefix@1.0.1"; -const Configure = {presets: [TWPreTail(), TWPreAuto()]}; +const Configure = { + theme: + { + extend: + { + keyframes: + { + flash: + { + '0%': { opacity: 1.0 }, + '50%': { opacity: 0.3 }, + '100%': { opacity: 0.0 } + }, + pulse: + { + "0%": { opacity: 0.0 }, + "10%": { opacity: 0.0 }, + "12%": { opacity: 1.0 }, + "22%": { opacity: 1.0 }, + "42%": { opacity: 0.2 }, + "100%": { opacity: 0.0 } + } + }, + animation: + { + flash: "flash 1s both" + }, + strokeWidth: + { + "bold": "3px" + } + } + }, + rules: + [ + [ + "stroke-draw", + { + "vector-effect":"non-scaling-stroke", + "stroke-linecap":"square" + }, + ], + [ + 'shadow-glow-(.*)', + (match, context)=> + { + return { "box-shadow": `0px 0px 5px 2px ${context.theme().colors[match[1]]}` }; + } + ], + [ + 'shadow-sss', + { + "box-shadow": "rgb(0 0 0 / 50%) 0px -3px 2px inset, rgb(255 255 255 / 50%) 0px 10px 10px inset" + } + ] + ], + presets: [TWPreTail(), TWPreAuto()] +}; const ShadowDOM = document.querySelector("#app").attachShadow({mode: "open"}); const ShadowDiv = document.createElement("div"); const ShadowCSS = document.createElement("style"); @@ -11,10 +68,17 @@ ShadowDOM.append(ShadowCSS); ShadowDOM.append(ShadowDiv); TW.observe(TW.twind(Configure, TW.cssom(ShadowCSS)), ShadowDiv); -import UI from "./ui.js"; +import * as UI from "./ui.js"; import {render} from "https://esm.sh/preact@10.11.3/compat"; import {html} from "https://esm.sh/htm@3.1.1/preact"; render(html` <${UI.Button} icon="+">hey! - <${UI.Chart}>

SUP

+ <${UI.Button} light>Left + <${UI.Button} inactive>Right + <${UI.Button} disabled>Right + <${UI.Chart}> + + <${UI.Mark} /> + + `, ShadowDiv); \ No newline at end of file diff --git a/ui.js b/ui.js index 9e7405e..994b75d 100644 --- a/ui.js +++ b/ui.js @@ -3,72 +3,123 @@ import React from "https://esm.sh/preact@10.11.3/compat"; /// import {html} from "https://esm.sh/htm@3.1.1/preact"; -export default { - Button({children, icon, light, disabled}) - { - return html` - `; - }, +/** @typedef {({children}:{children:React.ReactNode})=>JSX.Element} BasicElement */ - /** @type {({children}:{inset:number, children:React.ReactNode})=>JSX.Element} */ - Chart({children}) +export function Button({children, icon, light, disabled, inactive}) +{ + const [LightGet, LightSet] = React.useState(light); + const [FlashGet, FlashSet] = React.useState(0); + const handleClick =()=> + { + if(inactive||disabled){ return; } + LightSet(!LightGet); + FlashSet(FlashGet+1); + }; + + return html` + `; +} + +/** @type {BasicElement} */ +export function Chart({children}) +{ + const inset = 20 + + const size = 1/6; + /** @type {Record} */ + const rulesXMapping = { + "125": [size*0.0, true ], + "250": [size*1.0, true ], + "500": [size*2.0, true ], + "1000": [size*3.0, true ], + "2000": [size*4.0, true ], + "3000": [size*4.5, false], + "4000": [size*5.0, true ], + "6000": [size*5.5, false], + "8000": [size*6.0, true ] + }; + const rulesX = Object.entries(rulesXMapping).map(([label, [position, normal]])=> { - const inset = 20 - const size = 1/6; - /** @type {Record} */ - const mappingX = { - "125": [size*0.0, true ], - "250": [size*1.0, true ], - "500": [size*2.0, true ], - "1000": [size*3.0, true ], - "2000": [size*4.0, true ], - "3000": [size*4.5, false], - "4000": [size*5.0, true ], - "6000": [size*5.5, false], - "8000": [size*6.0, true ], - }; - const rulesX = Object.entries(mappingX).map(([label, [position, normal]])=> - { - return html` - - ${label} - `; - }); - const rulesY = []; - const rulesYMin = -10; - const rulesYMax = 120; - for(let db = rulesYMin; db <= rulesYMax; db+=10) - { - const percent = ((db-rulesYMin) / (rulesYMax-rulesYMin))*100; - rulesY.push(html` - - `); - } return html` -
-
- Frequency in Hz - - - Hearing Level (dbHL) - + + ${label} + `; + }); + const rulesY = []; + const rulesYMin = -10; + const rulesYMax = 120; + for(let db = rulesYMin; db <= rulesYMax; db+=10) + { + const percent = ((db-rulesYMin) / (rulesYMax-rulesYMin))*100; + rulesY.push(html` + + `); + } + return html` +
+
+ Frequency in Hz + + + Hearing Level (dbHL) -
- - ${ rulesX } - ${ rulesY } + +
+ + ${ rulesX } + ${ rulesY } +
${ children }
- `; - } +
+ `; +} + +/** @type {Record} */ +const Glyph = { + Arrow:({children})=> html` + + + `, + + //style="transform: translate(50%, 50%) rotate(-15deg) scale(0.5);" + X: ({children})=> html` + + + ${children}`, + + O: ({children})=> html` + + ${children}` +}; + +/** @type {({right, response, x, y}:{right:boolean, response?:boolean, x:string|number, y:string|number})=>JSX.Element} */ +export function Mark({right, response, x, y}) +{ + return html` + + <${ right ? Glyph.O : Glyph.X }> + ${ !response && html`<${Glyph.Arrow}/>` } + + + `; } \ No newline at end of file