consolidate save buttons
This commit is contained in:
@@ -10,15 +10,19 @@ function Options() {
|
||||
let [privKey, setPrivKey] = useState('')
|
||||
let [relays, setRelays] = useState([])
|
||||
let [newRelayURL, setNewRelayURL] = useState('')
|
||||
let [policies, setPermissions] = useState()
|
||||
let [protocolHandler, setProtocolHandler] = useState(null)
|
||||
let [policies, setPermissions] = useState([])
|
||||
let [protocolHandler, setProtocolHandler] = useState('')
|
||||
let [hidingPrivateKey, hidePrivateKey] = useState(true)
|
||||
let [showNotifications, setNotifications] = useState(false)
|
||||
let [message, setMessage] = useState('')
|
||||
let [messages, setMessages] = useState([])
|
||||
let [handleNostrLinks, setHandleNostrLinks] = useState(false)
|
||||
let [showProtocolHandlerHelp, setShowProtocolHandlerHelp] = useState(false)
|
||||
let [unsavedChanges, setUnsavedChanges] = useState([])
|
||||
|
||||
const showMessage = useCallback(msg => {
|
||||
setMessage(msg)
|
||||
setTimeout(setMessage, 3000)
|
||||
messages.push(msg)
|
||||
setMessages(messages)
|
||||
setTimeout(() => setMessages([]), 3000)
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
@@ -40,6 +44,8 @@ function Options() {
|
||||
}
|
||||
if (results.protocol_handler) {
|
||||
setProtocolHandler(results.protocol_handler)
|
||||
setHandleNostrLinks(true)
|
||||
setShowProtocolHandlerHelp(false)
|
||||
}
|
||||
if (results.notifications) {
|
||||
setNotifications(true)
|
||||
@@ -74,65 +80,32 @@ function Options() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<h1>nos2x</h1>
|
||||
<p>nostr signer extension</p>
|
||||
<h2>options</h2>
|
||||
<div style={{marginBottom: '10px'}}>
|
||||
<div style={{display: 'flex', alignItems: 'center'}}>
|
||||
<span>preferred relays:</span>
|
||||
<button style={{marginLeft: '20px'}} onClick={saveRelays}>
|
||||
save
|
||||
</button>
|
||||
</div>
|
||||
<div style={{marginLeft: '10px'}}>
|
||||
{relays.map(({url, policy}, i) => (
|
||||
<div key={i} style={{display: 'flex'}}>
|
||||
<input
|
||||
style={{marginRight: '10px', width: '400px'}}
|
||||
value={url}
|
||||
onChange={changeRelayURL.bind(null, i)}
|
||||
/>
|
||||
<label>
|
||||
read
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={policy.read}
|
||||
onChange={toggleRelayPolicy.bind(null, i, 'read')}
|
||||
/>
|
||||
</label>
|
||||
<label>
|
||||
write
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={policy.write}
|
||||
onChange={toggleRelayPolicy.bind(null, i, 'write')}
|
||||
/>
|
||||
</label>
|
||||
<button style={{marginLeft: '10px'}} onClick={removeRelay.bind(null, i)}>
|
||||
remove
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
<div style={{display: 'flex'}}>
|
||||
<input
|
||||
style={{width: '400px'}}
|
||||
value={newRelayURL}
|
||||
onChange={e => setNewRelayURL(e.target.value)}
|
||||
onBlur={addNewRelay}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{marginBottom: '10px'}}>
|
||||
<label>
|
||||
<h1 style={{fontSize: '25px', marginBlockEnd: '0px'}}>nos2x</h1>
|
||||
<p style={{marginBlockStart: '0px'}}>nostr signer extension</p>
|
||||
<h2 style={{marginBlockStart: '20px', marginBlockEnd: '5px'}}>options</h2>
|
||||
<div style={{marginBottom: '10px', display: 'flex', flexDirection: 'column', gap: '10px', width: 'fit-content'}}>
|
||||
<div>
|
||||
<div>private key: </div>
|
||||
<div style={{marginLeft: '10px'}}>
|
||||
{!hidingPrivateKey && (
|
||||
<div style={{marginLeft: '10px', display: 'flex', flexDirection: 'column', gap: '10px'}}>
|
||||
<div style={{display: 'flex', gap: '10px'}}>
|
||||
<input
|
||||
type={hidingPrivateKey ? 'password' : 'text'}
|
||||
style={{width: '600px'}}
|
||||
value={privKey}
|
||||
onChange={handleKeyChange}
|
||||
/>
|
||||
{privKey === '' && <button onClick={generate}>generate</button>}
|
||||
{privKey && hidingPrivateKey && <button onClick={() => hidePrivateKey(false)}>show key</button>}
|
||||
{privKey && !hidingPrivateKey && <button onClick={() => hidePrivateKey(true)}>hide key</button>}
|
||||
</div>
|
||||
{privKey && !isKeyValid() && <div style={{color: 'red'}}>private key is invalid!</div>}
|
||||
{!hidingPrivateKey && isKeyValid() && (
|
||||
<div
|
||||
style={{
|
||||
height: 'auto',
|
||||
maxWidth: 256,
|
||||
width: '100%'
|
||||
width: '100%',
|
||||
marginTop: '5px'
|
||||
}}
|
||||
>
|
||||
<QRCode
|
||||
@@ -143,43 +116,115 @@ function Options() {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{display: 'flex'}}>
|
||||
<input
|
||||
type={hidingPrivateKey ? 'password' : 'text'}
|
||||
style={{width: '600px'}}
|
||||
value={privKey}
|
||||
onChange={handleKeyChange}
|
||||
onFocus={() => hidePrivateKey(false)}
|
||||
onBlur={() => hidePrivateKey(true)}
|
||||
/>
|
||||
{privKey === '' && <button onClick={generate}>generate</button>}
|
||||
</div>
|
||||
|
||||
<button disabled={!isKeyValid()} onClick={saveKey}>
|
||||
save
|
||||
</div>
|
||||
<div>
|
||||
<div>preferred relays:</div>
|
||||
<div style={{marginLeft: '10px', display: 'flex', flexDirection: 'column', gap: '1px'}}>
|
||||
{relays.map(({url, policy}, i) => (
|
||||
<div key={i} style={{display: 'flex', alignItems: 'center', gap: '15px'}}>
|
||||
<input
|
||||
style={{width: '400px'}}
|
||||
value={url}
|
||||
onChange={changeRelayURL.bind(null, i)}
|
||||
/>
|
||||
<div style={{display: 'flex', gap: '5px'}}>
|
||||
<label style={{display: 'flex', alignItems: 'center'}}>
|
||||
read
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={policy.read}
|
||||
onChange={toggleRelayPolicy.bind(null, i, 'read')}
|
||||
/>
|
||||
</label>
|
||||
<label style={{display: 'flex', alignItems: 'center'}}>
|
||||
write
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={policy.write}
|
||||
onChange={toggleRelayPolicy.bind(null, i, 'write')}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<button onClick={removeRelay.bind(null, i)}>
|
||||
remove
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
<div style={{display: 'flex', gap: '10px', marginTop: '5px'}}>
|
||||
<input
|
||||
style={{width: '400px'}}
|
||||
value={newRelayURL}
|
||||
onChange={e => setNewRelayURL(e.target.value)}
|
||||
onKeyDown={e => { if (e.key === 'Enter') addNewRelay()}}
|
||||
/>
|
||||
<button disabled={!newRelayURL} onClick={addNewRelay}>add relay</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<div>
|
||||
handle{' '}
|
||||
<span style={{padding: '2px', background: 'silver'}}>nostr:</span>{' '}
|
||||
links:
|
||||
</div>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={handleNostrLinks}
|
||||
onChange={changeHandleNostrLinks}
|
||||
/>
|
||||
</label>
|
||||
{policies?.length > 0 && (
|
||||
<>
|
||||
<div style={{display: 'flex', alignItems: 'center'}}>
|
||||
<h2>policies</h2>
|
||||
<label
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginLeft: '14px'
|
||||
}}
|
||||
>
|
||||
show a notification when a permission is used by a page
|
||||
<div style={{marginLeft: '10px'}}>
|
||||
{handleNostrLinks && (
|
||||
<div>
|
||||
<div style={{display: 'flex'}}>
|
||||
<input
|
||||
placeholder="url template"
|
||||
value={protocolHandler}
|
||||
onChange={handleChangeProtocolHandler}
|
||||
style={{width: '680px', maxWidth: '90%'}}
|
||||
/>
|
||||
{!showProtocolHandlerHelp && <button onClick={changeShowProtocolHandlerHelp}>?</button>}
|
||||
</div>
|
||||
{showProtocolHandlerHelp && (<pre>{`
|
||||
{hex} = hex pubkey for npub or nprofile, hex event id for note or nevent
|
||||
{p_or_e} = "p" for npub or nprofile, "e" for note or nevent
|
||||
{u_or_n} = "u" for npub or nprofile, "n" for note or nevent
|
||||
{relay0} = first relay in a nprofile or nevent
|
||||
{relay1} = second relay in a nprofile or nevent
|
||||
{relay2} = third relay in a nprofile or nevent
|
||||
{raw} = anything after the colon, i.e. the full nip19 bech32 string
|
||||
{hrp} = human-readable prefix of the nip19 string
|
||||
|
||||
examples:
|
||||
- https://nostr.guru/{p_or_e}/{hex}
|
||||
- https://brb.io/{u_or_n}/{hex}
|
||||
- https://notes.blockcore.net/{p_or_e}/{hex}
|
||||
`}</pre>)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<label style={{ display: 'flex', alignItems: 'center' }}>
|
||||
show notifications when permissions are used:
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={showNotifications}
|
||||
onClick={handleNotifications}
|
||||
onChange={handleNotifications}
|
||||
/>
|
||||
</label>
|
||||
<button disabled={!unsavedChanges.length} onClick={saveChanges} style={{padding: '5px 20px'}}>
|
||||
save
|
||||
</button>
|
||||
<div style={{fontSize: '120%'}}>
|
||||
{messages.map((message, i) => (
|
||||
<div key={i}>{message}</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h2>permissions</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -223,90 +268,30 @@ function Options() {
|
||||
</tr>
|
||||
)
|
||||
)}
|
||||
{!policies.length && <tr>{Array(5).fill('N/A').map((v, i) => (<td key={i}>{v}</td>))}</tr>}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
{!policies.length && <div style={{marginTop: '5px'}}>no permissions have been granted yet</div>}
|
||||
</div>
|
||||
<div>
|
||||
<h2>
|
||||
handle{' '}
|
||||
<span style={{padding: '2px', background: 'silver'}}>nostr:</span>{' '}
|
||||
links:
|
||||
</h2>
|
||||
<div style={{marginLeft: '10px'}}>
|
||||
<div>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="ph"
|
||||
value="no"
|
||||
checked={protocolHandler === null}
|
||||
onChange={handleChangeProtocolHandler}
|
||||
/>{' '}
|
||||
no
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="ph"
|
||||
value="yes"
|
||||
checked={protocolHandler !== null}
|
||||
onChange={handleChangeProtocolHandler}
|
||||
/>
|
||||
yes
|
||||
</label>
|
||||
</div>
|
||||
{protocolHandler !== null && (
|
||||
<div>
|
||||
<input
|
||||
placeholder="url template"
|
||||
value={protocolHandler}
|
||||
onChange={handleChangeProtocolHandler}
|
||||
style={{width: '680px', maxWidth: '90%'}}
|
||||
/>
|
||||
<pre>{`
|
||||
{hex} = hex pubkey for npub or nprofile, hex event id for note or nevent
|
||||
{p_or_e} = "p" for npub or nprofile, "e" for note or nevent
|
||||
{u_or_n} = "u" for npub or nprofile, "n" for note or nevent
|
||||
{relay0} = first relay in a nprofile or nevent
|
||||
{relay1} = second relay in a nprofile or nevent
|
||||
{relay2} = third relay in a nprofile or nevent
|
||||
{raw} = anything after the colon, i.e. the full nip19 bech32 string
|
||||
{hrp} = human-readable prefix of the nip19 string
|
||||
|
||||
examples:
|
||||
- https://nostr.guru/{p_or_e}/{hex}
|
||||
- https://brb.io/{u_or_n}/{hex}
|
||||
- https://notes.blockcore.net/{p_or_e}/{hex}
|
||||
`}</pre>
|
||||
</div>
|
||||
)}
|
||||
<button
|
||||
style={{marginTop: '10px'}}
|
||||
onClick={saveNostrProtocolHandlerSettings}
|
||||
>
|
||||
save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{marginTop: '12px', fontSize: '120%'}}>{message}</div>
|
||||
</>
|
||||
)
|
||||
|
||||
async function handleKeyChange(e) {
|
||||
let key = e.target.value.toLowerCase().trim()
|
||||
setPrivKey(key)
|
||||
addUnsavedChanges('private_key')
|
||||
}
|
||||
|
||||
async function generate() {
|
||||
setPrivKey(nip19.nsecEncode(generatePrivateKey()))
|
||||
addUnsavedChanges('private_key')
|
||||
}
|
||||
|
||||
async function saveKey() {
|
||||
if (!isKeyValid()) return
|
||||
if (!isKeyValid()) {
|
||||
showMessage('PRIVATE KEY IS INVALID! did not save private key.')
|
||||
return
|
||||
}
|
||||
|
||||
let hexOrEmptyKey = privKey
|
||||
|
||||
@@ -341,6 +326,7 @@ function Options() {
|
||||
{url: ev.target.value, policy: relays[i].policy},
|
||||
...relays.slice(i + 1)
|
||||
])
|
||||
addUnsavedChanges('relays')
|
||||
}
|
||||
|
||||
function toggleRelayPolicy(i, cat) {
|
||||
@@ -352,6 +338,7 @@ function Options() {
|
||||
},
|
||||
...relays.slice(i + 1)
|
||||
])
|
||||
addUnsavedChanges('relays')
|
||||
}
|
||||
|
||||
function removeRelay(i) {
|
||||
@@ -359,6 +346,7 @@ function Options() {
|
||||
...relays.slice(0, i),
|
||||
...relays.slice(i + 1)
|
||||
])
|
||||
addUnsavedChanges('relays')
|
||||
}
|
||||
|
||||
function addNewRelay() {
|
||||
@@ -368,6 +356,7 @@ function Options() {
|
||||
policy: {read: true, write: true}
|
||||
})
|
||||
setRelays(relays)
|
||||
addUnsavedChanges('relays')
|
||||
setNewRelayURL('')
|
||||
}
|
||||
|
||||
@@ -386,19 +375,22 @@ function Options() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleNotifications() {
|
||||
if (showNotifications) {
|
||||
await browser.storage.local.set({notifications: false})
|
||||
setNotifications(false)
|
||||
} else {
|
||||
function handleNotifications() {
|
||||
setNotifications(!showNotifications)
|
||||
addUnsavedChanges('notifications')
|
||||
if (!showNotifications) requestBrowserNotificationPermissions()
|
||||
}
|
||||
|
||||
async function requestBrowserNotificationPermissions() {
|
||||
let granted = await browser.permissions.request({
|
||||
permissions: ['notifications']
|
||||
})
|
||||
if (granted) {
|
||||
await browser.storage.local.set({notifications: true})
|
||||
setNotifications(true)
|
||||
}
|
||||
if (!granted) setNotifications(false)
|
||||
}
|
||||
|
||||
async function saveNotifications() {
|
||||
await browser.storage.local.set({notifications: showNotifications})
|
||||
showMessage('saved notifications!')
|
||||
}
|
||||
|
||||
async function saveRelays() {
|
||||
@@ -412,23 +404,54 @@ function Options() {
|
||||
showMessage('saved relays!')
|
||||
}
|
||||
|
||||
function handleChangeProtocolHandler(e) {
|
||||
if (e.target.type === 'text') setProtocolHandler(e.target.value)
|
||||
else
|
||||
switch (e.target.value) {
|
||||
case 'no':
|
||||
setProtocolHandler(null)
|
||||
break
|
||||
case 'yes':
|
||||
setProtocolHandler('')
|
||||
break
|
||||
function changeShowProtocolHandlerHelp() {
|
||||
setShowProtocolHandlerHelp(true)
|
||||
}
|
||||
|
||||
function changeHandleNostrLinks() {
|
||||
if (handleNostrLinks) {
|
||||
setProtocolHandler('')
|
||||
addUnsavedChanges('protocol_handler')
|
||||
} else setShowProtocolHandlerHelp(true)
|
||||
setHandleNostrLinks(!handleNostrLinks)
|
||||
}
|
||||
|
||||
function handleChangeProtocolHandler(e) {
|
||||
setProtocolHandler(e.target.value)
|
||||
addUnsavedChanges('protocol_handler')
|
||||
}
|
||||
|
||||
async function saveNostrProtocolHandlerSettings() {
|
||||
await browser.storage.local.set({protocol_handler: protocolHandler})
|
||||
showMessage('saved protocol handler!')
|
||||
}
|
||||
|
||||
function addUnsavedChanges(section) {
|
||||
if (!unsavedChanges.find(s => s === section)) {
|
||||
unsavedChanges.push(section)
|
||||
setUnsavedChanges(unsavedChanges)
|
||||
}
|
||||
}
|
||||
|
||||
async function saveChanges() {
|
||||
for (let section of unsavedChanges) {
|
||||
switch (section) {
|
||||
case 'private_key':
|
||||
await saveKey()
|
||||
break
|
||||
case 'relays':
|
||||
await saveRelays()
|
||||
break
|
||||
case 'protocol_handler':
|
||||
await saveNostrProtocolHandlerSettings()
|
||||
break
|
||||
case 'notifications':
|
||||
await saveNotifications()
|
||||
break
|
||||
}
|
||||
}
|
||||
setUnsavedChanges([])
|
||||
}
|
||||
}
|
||||
|
||||
render(<Options />, document.getElementById('main'))
|
||||
|
||||
Reference in New Issue
Block a user