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
OFF0 2 years ago
parent be13ecf73f
commit f9fcb1131e
Signed by: offbyn
GPG Key ID: 94A2F643C51F37FA

@ -23,8 +23,9 @@
} }
.mbox .mbox-body { .mbox .mbox-body {
color: var(--fgcolor-accent); color: var(--color-accent);
flex-basis: calc(100% - 64px - 1rem); flex-basis: calc(100% - 64px - 1rem);
flex-grow: 0; flex-grow: 0;
flex-shrink: 1; flex-shrink: 1;
max-width: 84ch;
} }

@ -1,32 +1,52 @@
form { form {
max-width: 64ch; max-width: 72ch;
} }
button,
input, input,
textarea { textarea {
color: var(--bgcolor-accent);
font-family: monospace; font-family: monospace;
font-size: 1.6rem;
margin-bottom: 1.2rem;
padding: 1.3rem 1.8rem;
} }
button,
label { label {
color: var(--bgcolor-accent);
display: block; display: block;
margin-bottom: .5rem; font-size: 1.6rem;
padding-left: 0; margin-bottom: 0;
padding: 1.3rem 1.8rem;
text-indent: 0; text-indent: 0;
} }
input[type="password"],
input[type="text"] { input[type="text"] {
border: .2rem solid #b7b7b7;
border-radius: .2rem;
display: block; display: block;
margin-bottom: 1rem; outline-color: rgb(102, 102, 102);
padding: .5rem;
width: 100%; width: 100%;
} }
input[type="password"]:focus,
input[type="text"]:focus {
border-color: #d4d4d4;
outline-offset: 1px;
}
input[type="password"] { .buttons {
display: block; align-items: center;
margin-bottom: 1rem; display: flex;
padding: .5rem; justify-content: flex-end;
width: 100%; min-height: 3.2rem;
}
.button-inline {
background: transparent;
color: var(--color);
display: inline;
padding: .3rem;
} }
button { button {
@ -34,7 +54,6 @@ button {
border: none; border: none;
color: white; color: white;
cursor: pointer; cursor: pointer;
padding: .5rem 1rem;
} }
button:disabled { button:disabled {
@ -42,19 +61,12 @@ button:disabled {
cursor: default; cursor: default;
} }
.buttons { .inline-text {
align-items: center;
display: flex;
justify-content: flex-end;
height: 2rem;
}
.inline-text,
.inline-error {
display: inline-block; display: inline-block;
padding: 0 1ch; padding: 0 1ch;
} }
.inline-error { .form-status {
color: var(--color-danger); flex-grow: 1;
padding: 1rem 1.8rem;
} }

@ -44,15 +44,20 @@
<input type="radio" name="maintabs" id="settings"> <input type="radio" name="maintabs" id="settings">
<label for="settings">settings</label> <label for="settings">settings</label>
<form name="settings" method="post" class="content"> <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"> <input type="text" name="pubkey" id="pubkey">
<label for="privatekey">private key</label> <label for="privatekey">
<input type="text" name="privatekey" id="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"> <div class="buttons">
<span id="keyError" class="inline-error" hidden></span> <div id="keystatus" class="form-status" hidden></div>
<button name="generate">generate</button> <button type="button" name="generate" tabindex="0">new</button>
<span class="inline-text"> or </span> <span class="inline-text"></span>
<button name="import" disabled>import</button> <button type="button" name="import" tabindex="0" disabled>save</button>
</div> </div>
</form> </form>
</div> </div>

@ -2,17 +2,24 @@
@import "cards.css"; @import "cards.css";
@import "form.css"; @import "form.css";
:root {
--color-danger: #e00; ::selection {
background: #ff79f9;
color: #fff;
}
:where([hidden]) {
display: none !important;
} }
@media (prefers-color-scheme: light) { @media (prefers-color-scheme: light) {
html { html {
--bgcolor: #fff7e9; --bgcolor: #fff;
--bgcolor-accent: #ff731d; --bgcolor-accent: #ff731d;
--bgcolor-inactive: #737373; --bgcolor-inactive: #bababa;
--fgcolor: #1746a2; --color: rgb(68 68 68);
--fgcolor-accent: #5f9df7; --color-accent: rgb(0 0 0);
--bgcolor-danger: rgb(255 0 0);
} }
} }
@ -21,8 +28,9 @@
--bgcolor: #191919; --bgcolor: #191919;
--bgcolor-accent: #2d4263; --bgcolor-accent: #2d4263;
--bgcolor-inactive: #535353; --bgcolor-inactive: #535353;
--fgcolor: #c84b31; --color: #c84b31;
--fgcolor-accent: #ecdbba; --color-accent: #ecdbba;
--bgcolor-danger: rgb(255 0 0);
} }
img { img {
@ -34,13 +42,27 @@
} }
} }
*, ::after, ::before { html {
box-sizing: border-box; font-size: 62.5%;
line-height: 1;
} }
body { body {
background-color: var(--bgcolor); background-color: var(--bgcolor);
color: var(--fgcolor); color: var(--color);
font-family: monospace; 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);
} }

@ -2,9 +2,12 @@ import {relayPool, generatePrivateKey, getPublicKey} from 'nostr-tools';
import {elem} from './domutil.js'; import {elem} from './domutil.js';
const pool = relayPool(); 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://nostr.bitcoiner.social/', {read: true, write: true});
pool.addRelay('wss://relay.nostr.info', {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'); const feedlist = document.querySelector('#feedlist');
@ -14,8 +17,11 @@ const dateTime = new Intl.DateTimeFormat(navigator.language, {
}); });
const userList = []; const userList = [];
let max = 0;
function onEvent(evt, relay) { function onEvent(evt, relay) {
if (max++ >= 7) {
return subscription.unsub();
}
switch (evt.kind) { switch (evt.kind) {
case 0: case 0:
try { try {
@ -36,7 +42,7 @@ function onEvent(evt, relay) {
} }
} }
pool.sub({ const subscription = pool.sub({
cb: onEvent, cb: onEvent,
filter: { filter: {
authors: [ authors: [
@ -53,7 +59,7 @@ function renderTextNote(evt, relay) {
const body = elem('div', {className: 'mbox-body', title: dateTime.format(time)}, [ const body = elem('div', {className: 'mbox-body', title: dateTime.format(time)}, [
elem('header', {className: 'mbox-header'}, [ elem('header', {className: 'mbox-header'}, [
elem('strong', {}, userName), elem('strong', {}, userName),
` on ${host}:` elem('small', {},` on ${host}`),
]), ]),
evt.content // text evt.content // text
]); ]);
@ -65,7 +71,7 @@ function renderRecommendServer(evt, relay) {
const body = elem('div', {className: 'mbox-body', title: dateTime.format(time)}, [ const body = elem('div', {className: 'mbox-body', title: dateTime.format(time)}, [
elem('header', {className: 'mbox-header'}, [ elem('header', {className: 'mbox-header'}, [
elem('strong', {}, userName), elem('strong', {}, userName),
` on ${host}` elem('small', {},` on ${host}`),
]), ]),
`recommends server: ${evt.content}` `recommends server: ${evt.content}`
]); ]);
@ -116,32 +122,30 @@ function setMetadata(userList, relay, evt, content) {
const form = document.querySelector('form[name="settings"]'); const form = document.querySelector('form[name="settings"]');
const privateKeyInput = form.querySelector('#privatekey'); const privateKeyInput = form.querySelector('#privatekey');
const pubKeyInput = form.querySelector('#pubkey'); const pubKeyInput = form.querySelector('#pubkey');
const keyError = form.querySelector('#keyError'); const statusMessage = form.querySelector('#keystatus');
const generateBtn = form.querySelector('button[name="generate"]'); const generateBtn = form.querySelector('button[name="generate"]');
const importBtn = form.querySelector('button[name="import"]'); const importBtn = form.querySelector('button[name="import"]');
const privateTgl = form.querySelector('button[name="privatekey-toggle"]')
generateBtn.addEventListener('click', (evt) => { generateBtn.addEventListener('click', () => {
evt.preventDefault();
const privateKey = generatePrivateKey(); const privateKey = generatePrivateKey();
const pubKey = getPublicKey(privateKey); const pubKey = getPublicKey(privateKey);
if (validKeys(privateKey, pubKey)) { if (validKeys(privateKey, pubKey)) {
localStorage.setItem('privateKey', privateKey);
localStorage.setItem('pubKey', pubKey);
privateKeyInput.value = privateKey; privateKeyInput.value = privateKey;
pubKeyInput.value = pubKey; pubKeyInput.value = pubKey;
statusMessage.textContent = 'private-key created!';
statusMessage.hidden = false;
} }
}); });
privateKeyInput.value = localStorage.getItem('privateKey'); importBtn.addEventListener('click', () => {
pubKeyInput.value = localStorage.getItem('pubKey');
importBtn.addEventListener('click', (evt) => {
evt.preventDefault();
const privateKey = privateKeyInput.value; const privateKey = privateKeyInput.value;
const pubKey = pubKeyInput.value; const pubKey = pubKeyInput.value;
if (validKeys(privateKey, pubKey)) { if (validKeys(privateKey, pubKey)) {
localStorage.setItem('privateKey', privateKey); localStorage.setItem('privateKey', privateKey);
localStorage.setItem('pubKey', pubKey); 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) { if (pubKey && privateKey) {
try { try {
if (getPublicKey(privateKey) === pubKey) { if (getPublicKey(privateKey) === pubKey) {
keyError.hidden = true; statusMessage.hidden = true;
keyError.textContent = ''; statusMessage.textContent = 'public-key corresponds to private-key';
importBtn.removeAttribute('disabled'); importBtn.removeAttribute('disabled');
return true; return true;
} else { } else {
keyError.textContent = 'private key does not correspond to public key!' statusMessage.textContent = 'private-key does not correspond to public-key!'
} }
} catch (e) { } 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); importBtn.setAttribute('disabled', true);
return false; return false;
} }
document.body.addEventListener('keyup', () => { privateTgl.addEventListener('click', () => {
console.log(document.activeElemen) privateKeyInput.type = privateKeyInput.type === 'text' ? 'password' : 'text';
}); });
privateKeyInput.value = localStorage.getItem('privateKey');
pubKeyInput.value = localStorage.getItem('pubKey');

@ -9,20 +9,20 @@
.tab > label { .tab > label {
cursor: pointer; cursor: pointer;
font-size: 1.1em; padding: 1rem 1.5em;
padding: .5em 1em;
} }
.tab [type=radio] { .tab [type=radio] {
position: absolute; clip: rect(0, 0, 0, 0);
height: 0; height: 0;
width: 0;
overflow: hidden; overflow: hidden;
clip: rect(0, 0, 0, 0); position: absolute;
width: 0;
} }
.tab [type=radio] + label { .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 { .tab [type=radio]:checked ~ label {
z-index: 2;
background-color: var(--bgcolor-accent); background-color: var(--bgcolor-accent);
color: var(--fgcolor-accent); color: var(--color-accent);
z-index: 2;
} }
.tab [type=radio]:checked ~ label ~ .content { .tab [type=radio]:checked ~ label ~ .content {
z-index: 1;
opacity: 1; opacity: 1;
z-index: 1;
} }
.tab .content { .tab .content {
position: absolute;
top: 2.5em;
left: 0;
right: 0;
bottom: 0; bottom: 0;
padding: 1rem 0; left: 0;
opacity: 0; opacity: 0;
position: absolute;
right: 0;
top: 5em;
} }

Loading…
Cancel
Save