diff --git a/app.js b/app.js index 5c3b540..e65d543 100644 --- a/app.js +++ b/app.js @@ -34,6 +34,12 @@ const decrypt =(secret)=> } }; +const copyToClipboard =(str)=> +{ + alert("copied to clipboard") + // todo copy string to clipboard; +} + /** @typedef {[domain:string, username:string, password:string, codegen:string, timestamp:number, custom_kvp:Record]} CredSet */ const vault = van.state(/**@type{CredSet[]}*/([])); const vaultSerialized = van.state(""); @@ -42,6 +48,10 @@ const password = van.state(""); const attemptsFailed = van.state(0); const preexisting = (localStorage.getItem(writeKey)||""); + +const editCred = van.state(/**@type{null|CredSet}*/null); +const editInd = van.state(0); + const PasswordChange =()=> { if(preexisting && attemptsFailed.val > -1) @@ -112,6 +122,54 @@ const Components = { ) }, + /**@type {(label:string, cred:CredSet, credIndex:Util.Indices)=>HTMLFieldSetElement} */ + SingleFieldForm(label, cred, credIndex){ + + const edit = van.state(false); + const show = van.state(false); + + return $.fieldset( + $.label( + + {onclick(){ + if(!edit.rawVal) + { + copyToClipboard() + } + }}, + label), + + + $.button({onclick(){editCred.val = cred; editInd.val = credIndex;}}, "Edit") + + //()=> $.button({onclick(){show.val = !show.val}}, show.val ? "Hide":"Show"), + //()=> $.button({onclick(){edit.val = !edit.val}}, edit.val ? "Cancel":"Edit"), + //()=> edit.val ? $.input({type:"text", value:cred[credIndex].toString()}) : null, + //()=> edit.val ? $.button({onclick(){}}, "Save") : null, + ) + }, + + /**@type {(cred:CredSet)=>HTMLDivElement} */ + ExistingForm(cred) + { + return $.div( + $.details( + $.summary( + $.h2(cred[0]), + ), + + Components.SingleFieldForm("User", cred, 1), + Components.SingleFieldForm("Pass", cred, 2), + + $.details( + $.summary("Delete this record"), + $.button("Delete") + ) + ) + + ) + }, + Root() { const input = $.input({id:"passwordField", value:password.val}); @@ -140,6 +198,7 @@ const Components = { else { message = `You are starting a new session.`; + button = `Encrypt`; showVault = true; } return [message, button, showVault] @@ -170,20 +229,36 @@ const Components = { }, + Modal() + { + if(editCred.val) + { + const input = $.input({value:editCred.val[editInd.val]}); + return $.div( + input, + $.button({onclick(){ + editCred.val[editInd.val] = input.value; + editCred.val = null; + encrypt(password.val); + }}, "Save"), + $.button({onclick(){ + editCred.val = null; + }}, "Cancel") + ) + } + else + { + return "no compoent" + } + }, + Vault() { return $.div( $.h2("Vault"), Components.Form, - vault.val.map((cred)=>{ - return $.details( - $.summary(cred[0]), - $.p( - $.strong("User Name:"), - cred[1] - ) - ) - }) + Components.Modal, + vault.val.map(Components.ExistingForm) ); } } diff --git a/types.d.ts b/types.d.ts index b3c58df..15114dd 100644 --- a/types.d.ts +++ b/types.d.ts @@ -45,4 +45,16 @@ declare global readonly tags: Van.Tags & ((namespaceURI: string) => Readonly>>) readonly hydrate: (dom: T, f: (dom: T) => T | null | undefined) => T }; -} \ No newline at end of file + + + namespace Util + { + type Indices = + Exclude extends infer K + ? K extends `${infer N extends number}` ? N : never + : never; + } + +} + +