forked from nostr/nostrweb
ui: update settings and feed
- changed private-key input to type password - added toggle to show private-key - added key-generated, key-saved success messages - changed global font size - upadted colors (especially light mode) - unsubscribe after a few messages for testing
parent
be13ecf73f
commit
f9fcb1131e
|
@ -23,8 +23,9 @@
|
|||
}
|
||||
|
||||
.mbox .mbox-body {
|
||||
color: var(--fgcolor-accent);
|
||||
color: var(--color-accent);
|
||||
flex-basis: calc(100% - 64px - 1rem);
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
max-width: 84ch;
|
||||
}
|
||||
|
|
66
src/form.css
66
src/form.css
|
@ -1,32 +1,52 @@
|
|||
form {
|
||||
max-width: 64ch;
|
||||
max-width: 72ch;
|
||||
}
|
||||
|
||||
input,
|
||||
textarea {
|
||||
color: var(--bgcolor-accent);
|
||||
font-family: monospace;
|
||||
font-size: 1.6rem;
|
||||
margin-bottom: 1.2rem;
|
||||
padding: 1.3rem 1.8rem;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
textarea {
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
label {
|
||||
color: var(--bgcolor-accent);
|
||||
display: block;
|
||||
margin-bottom: .5rem;
|
||||
padding-left: 0;
|
||||
font-size: 1.6rem;
|
||||
margin-bottom: 0;
|
||||
padding: 1.3rem 1.8rem;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
input[type="password"],
|
||||
input[type="text"] {
|
||||
border: .2rem solid #b7b7b7;
|
||||
border-radius: .2rem;
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
padding: .5rem;
|
||||
outline-color: rgb(102, 102, 102);
|
||||
width: 100%;
|
||||
}
|
||||
input[type="password"]:focus,
|
||||
input[type="text"]:focus {
|
||||
border-color: #d4d4d4;
|
||||
outline-offset: 1px;
|
||||
}
|
||||
|
||||
input[type="password"] {
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
padding: .5rem;
|
||||
width: 100%;
|
||||
.buttons {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
min-height: 3.2rem;
|
||||
}
|
||||
|
||||
.button-inline {
|
||||
background: transparent;
|
||||
color: var(--color);
|
||||
display: inline;
|
||||
padding: .3rem;
|
||||
}
|
||||
|
||||
button {
|
||||
|
@ -34,7 +54,6 @@ button {
|
|||
border: none;
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
padding: .5rem 1rem;
|
||||
}
|
||||
|
||||
button:disabled {
|
||||
|
@ -42,19 +61,12 @@ button:disabled {
|
|||
cursor: default;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
height: 2rem;
|
||||
}
|
||||
|
||||
.inline-text,
|
||||
.inline-error {
|
||||
.inline-text {
|
||||
display: inline-block;
|
||||
padding: 0 1ch;
|
||||
}
|
||||
|
||||
.inline-error {
|
||||
color: var(--color-danger);
|
||||
.form-status {
|
||||
flex-grow: 1;
|
||||
padding: 1rem 1.8rem;
|
||||
}
|
||||
|
|
|
@ -44,15 +44,20 @@
|
|||
<input type="radio" name="maintabs" id="settings">
|
||||
<label for="settings">settings</label>
|
||||
<form name="settings" method="post" class="content">
|
||||
<label for="pubkey">public key</label>
|
||||
<label for="pubkey">public-key</label>
|
||||
<input type="text" name="pubkey" id="pubkey">
|
||||
<label for="privatekey">private key</label>
|
||||
<input type="text" name="privatekey" id="privatekey">
|
||||
<label for="privatekey">
|
||||
private-key
|
||||
<button type="button" name="privatekey-toggle" class="button-inline" >
|
||||
<small>show</small>
|
||||
</button>
|
||||
</label>
|
||||
<input type="password" name="privatekey" id="privatekey">
|
||||
<div class="buttons">
|
||||
<span id="keyError" class="inline-error" hidden></span>
|
||||
<button name="generate">generate</button>
|
||||
<span class="inline-text"> or </span>
|
||||
<button name="import" disabled>import</button>
|
||||
<div id="keystatus" class="form-status" hidden></div>
|
||||
<button type="button" name="generate" tabindex="0">new</button>
|
||||
<span class="inline-text"></span>
|
||||
<button type="button" name="import" tabindex="0" disabled>save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
46
src/main.css
46
src/main.css
|
@ -2,17 +2,24 @@
|
|||
@import "cards.css";
|
||||
@import "form.css";
|
||||
|
||||
:root {
|
||||
--color-danger: #e00;
|
||||
|
||||
::selection {
|
||||
background: #ff79f9;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
:where([hidden]) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
html {
|
||||
--bgcolor: #fff7e9;
|
||||
--bgcolor: #fff;
|
||||
--bgcolor-accent: #ff731d;
|
||||
--bgcolor-inactive: #737373;
|
||||
--fgcolor: #1746a2;
|
||||
--fgcolor-accent: #5f9df7;
|
||||
--bgcolor-inactive: #bababa;
|
||||
--color: rgb(68 68 68);
|
||||
--color-accent: rgb(0 0 0);
|
||||
--bgcolor-danger: rgb(255 0 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,8 +28,9 @@
|
|||
--bgcolor: #191919;
|
||||
--bgcolor-accent: #2d4263;
|
||||
--bgcolor-inactive: #535353;
|
||||
--fgcolor: #c84b31;
|
||||
--fgcolor-accent: #ecdbba;
|
||||
--color: #c84b31;
|
||||
--color-accent: #ecdbba;
|
||||
--bgcolor-danger: rgb(255 0 0);
|
||||
}
|
||||
|
||||
img {
|
||||
|
@ -34,13 +42,27 @@
|
|||
}
|
||||
}
|
||||
|
||||
*, ::after, ::before {
|
||||
box-sizing: border-box;
|
||||
html {
|
||||
font-size: 62.5%;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--bgcolor);
|
||||
color: var(--fgcolor);
|
||||
color: var(--color);
|
||||
font-family: monospace;
|
||||
font-size: 120%;
|
||||
font-size: 1.6rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
*, ::after, ::before {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.danger {
|
||||
background-color: var(--bgcolor-danger);
|
||||
}
|
||||
|
|
51
src/main.js
51
src/main.js
|
@ -2,9 +2,12 @@ import {relayPool, generatePrivateKey, getPublicKey} from 'nostr-tools';
|
|||
import {elem} from './domutil.js';
|
||||
|
||||
const pool = relayPool();
|
||||
pool.addRelay('wss://nostr.x1ddos.ch', {read: true, write: true});
|
||||
// pool.addRelay('wss://nostr.x1ddos.ch', {read: true, write: true});
|
||||
pool.addRelay('wss://nostr.bitcoiner.social/', {read: true, write: true});
|
||||
pool.addRelay('wss://relay.nostr.info', {read: true, write: true});
|
||||
pool.addRelay('wss://nostr.openchain.fr', {read: true, write: true});
|
||||
pool.addRelay('wss://relay.damus.io', {read: true, write: true});
|
||||
|
||||
|
||||
const feedlist = document.querySelector('#feedlist');
|
||||
|
||||
|
@ -14,8 +17,11 @@ const dateTime = new Intl.DateTimeFormat(navigator.language, {
|
|||
});
|
||||
|
||||
const userList = [];
|
||||
|
||||
let max = 0;
|
||||
function onEvent(evt, relay) {
|
||||
if (max++ >= 7) {
|
||||
return subscription.unsub();
|
||||
}
|
||||
switch (evt.kind) {
|
||||
case 0:
|
||||
try {
|
||||
|
@ -36,7 +42,7 @@ function onEvent(evt, relay) {
|
|||
}
|
||||
}
|
||||
|
||||
pool.sub({
|
||||
const subscription = pool.sub({
|
||||
cb: onEvent,
|
||||
filter: {
|
||||
authors: [
|
||||
|
@ -53,7 +59,7 @@ function renderTextNote(evt, relay) {
|
|||
const body = elem('div', {className: 'mbox-body', title: dateTime.format(time)}, [
|
||||
elem('header', {className: 'mbox-header'}, [
|
||||
elem('strong', {}, userName),
|
||||
` on ${host}:`
|
||||
elem('small', {},` on ${host}`),
|
||||
]),
|
||||
evt.content // text
|
||||
]);
|
||||
|
@ -65,7 +71,7 @@ function renderRecommendServer(evt, relay) {
|
|||
const body = elem('div', {className: 'mbox-body', title: dateTime.format(time)}, [
|
||||
elem('header', {className: 'mbox-header'}, [
|
||||
elem('strong', {}, userName),
|
||||
` on ${host}`
|
||||
elem('small', {},` on ${host}`),
|
||||
]),
|
||||
`recommends server: ${evt.content}`
|
||||
]);
|
||||
|
@ -116,32 +122,30 @@ function setMetadata(userList, relay, evt, content) {
|
|||
const form = document.querySelector('form[name="settings"]');
|
||||
const privateKeyInput = form.querySelector('#privatekey');
|
||||
const pubKeyInput = form.querySelector('#pubkey');
|
||||
const keyError = form.querySelector('#keyError');
|
||||
const statusMessage = form.querySelector('#keystatus');
|
||||
const generateBtn = form.querySelector('button[name="generate"]');
|
||||
const importBtn = form.querySelector('button[name="import"]');
|
||||
const privateTgl = form.querySelector('button[name="privatekey-toggle"]')
|
||||
|
||||
generateBtn.addEventListener('click', (evt) => {
|
||||
evt.preventDefault();
|
||||
generateBtn.addEventListener('click', () => {
|
||||
const privateKey = generatePrivateKey();
|
||||
const pubKey = getPublicKey(privateKey);
|
||||
if (validKeys(privateKey, pubKey)) {
|
||||
localStorage.setItem('privateKey', privateKey);
|
||||
localStorage.setItem('pubKey', pubKey);
|
||||
privateKeyInput.value = privateKey;
|
||||
pubKeyInput.value = pubKey;
|
||||
statusMessage.textContent = 'private-key created!';
|
||||
statusMessage.hidden = false;
|
||||
}
|
||||
});
|
||||
|
||||
privateKeyInput.value = localStorage.getItem('privateKey');
|
||||
pubKeyInput.value = localStorage.getItem('pubKey');
|
||||
|
||||
importBtn.addEventListener('click', (evt) => {
|
||||
evt.preventDefault();
|
||||
importBtn.addEventListener('click', () => {
|
||||
const privateKey = privateKeyInput.value;
|
||||
const pubKey = pubKeyInput.value;
|
||||
if (validKeys(privateKey, pubKey)) {
|
||||
localStorage.setItem('privateKey', privateKey);
|
||||
localStorage.setItem('pubKey', pubKey);
|
||||
statusMessage.textContent = 'private-key saved in local storage!';
|
||||
statusMessage.hidden = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -151,22 +155,25 @@ function validKeys(privateKey, pubKey) {
|
|||
if (pubKey && privateKey) {
|
||||
try {
|
||||
if (getPublicKey(privateKey) === pubKey) {
|
||||
keyError.hidden = true;
|
||||
keyError.textContent = '';
|
||||
statusMessage.hidden = true;
|
||||
statusMessage.textContent = 'public-key corresponds to private-key';
|
||||
importBtn.removeAttribute('disabled');
|
||||
return true;
|
||||
} else {
|
||||
keyError.textContent = 'private key does not correspond to public key!'
|
||||
statusMessage.textContent = 'private-key does not correspond to public-key!'
|
||||
}
|
||||
} catch (e) {
|
||||
keyError.textContent = `not a valid private key: ${e.message || e}`;
|
||||
statusMessage.textContent = `not a valid private-key: ${e.message || e}`;
|
||||
}
|
||||
}
|
||||
keyError.hidden = false;
|
||||
statusMessage.hidden = false;
|
||||
importBtn.setAttribute('disabled', true);
|
||||
return false;
|
||||
}
|
||||
|
||||
document.body.addEventListener('keyup', () => {
|
||||
console.log(document.activeElemen)
|
||||
privateTgl.addEventListener('click', () => {
|
||||
privateKeyInput.type = privateKeyInput.type === 'text' ? 'password' : 'text';
|
||||
});
|
||||
|
||||
privateKeyInput.value = localStorage.getItem('privateKey');
|
||||
pubKeyInput.value = localStorage.getItem('pubKey');
|
||||
|
|
29
src/tabs.css
29
src/tabs.css
|
@ -9,20 +9,20 @@
|
|||
|
||||
.tab > label {
|
||||
cursor: pointer;
|
||||
font-size: 1.1em;
|
||||
padding: .5em 1em;
|
||||
padding: 1rem 1.5em;
|
||||
}
|
||||
|
||||
.tab [type=radio] {
|
||||
position: absolute;
|
||||
height: 0;
|
||||
width: 0;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
width: 0;
|
||||
}
|
||||
|
||||
.tab [type=radio] + label {
|
||||
outline: 1px solid var(--bgcolor-accent);
|
||||
outline: 2px solid var(--bgcolor-accent);
|
||||
outline-offset: -1px;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -32,22 +32,21 @@
|
|||
*/
|
||||
|
||||
.tab [type=radio]:checked ~ label {
|
||||
z-index: 2;
|
||||
background-color: var(--bgcolor-accent);
|
||||
color: var(--fgcolor-accent);
|
||||
color: var(--color-accent);
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.tab [type=radio]:checked ~ label ~ .content {
|
||||
z-index: 1;
|
||||
opacity: 1;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.tab .content {
|
||||
position: absolute;
|
||||
top: 2.5em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 1rem 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 5em;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue