New mobile nav. Removed old cruft.

This commit is contained in:
Thomas Mathews 2023-03-22 15:56:53 -07:00
parent 20907bede6
commit 6c9f5f12fe
9 changed files with 106 additions and 253 deletions

View file

@ -1,59 +1,15 @@
# Yo, Sup?
Yo Sup? or simply "Yo" for short is a web client for the Nostr protocol. Its
aim is to be as good of an experience (if not better than) as Twitter. Note Yo
will not be the same as Twitter and will not implement all of it's features.
Nor will Yo try to implement all of Nostr's features as there are many.
The true purpose of Yo is to provide a great experience on any platform for
anyone. It should be easy to use and understand making it a great option for
people coming from other social networks to engage in their community.
Yo comes from the legacy Damus Web app an holds all of its history. It has been
rewritten to accomodate for the scale issues that we have seen so that it can
continue to be used. The main reason for branching off is due to the lack of
parity between Damus iOS (and new codebase improvements) and that of what the
web version would support.
New minor features will continue to be added, but nothing substancial without
full time maintainers. Security will always be a top concern.
# Yo Sup
[Issue Tracker](https://todo.sr.ht/~tomtom/damus-web-issues)
## Contribution Guide
"Yo Sup" is a minimal Nostr client that grew out of the original Damus Web
code. It's goal is to view your feed and access your direct messages very fast.
So fast it works over 3G with a fresh page load. It has no goals to fulfill any
other NIPs, please use other clients such as Snort, Coracle, or Iris.
There are rules to contributing to this client. Please ensure you read them
before making changes and supplying patch notes.
It's written in plain JavaScript, HTML, and CSS for ease of development and
building, see the example Dockerfile. Small features and optimizations will be
added as needed, but the application is considered "complete".
- No transpilers. All source code should work out of the box.
- Keep source code organised. Refer to the folder structure. If you have a
question, ask it.
- Do not include your personal tools in the source code. Use your own scripts
outside of the project. This does not include build tools such as Make.
- Use tabs & write JS with snake_case. End of discussion.
- Do not include binary files.
- No NPM (and kin) environments. If you need a file from an external resource
mark the location in the "sources" file and add it to the repo.
- No frameworks. Learn the browser tools and write good code.
- No experimental browser APIs.
- Do not write animations in JavaScript, CSS only. Keep them short and snappy.
Animations should not be a forefront, but an enjoyable addition.
- All new & modified code should be properly documented.
- Source code should be readable in the browser.
- Search for the TODOs.
These rules are subject to discussion.
## Terminology
* Sign Out - Not "log out", "logout", "log off", etc.
* Sign In - Not "login", "log in", "signin", "sign-in", etc.
* Share - Not "boosted", "retweeted", "repost", etc.
* Send - Not "tweet", "toot", "post", etc.
* Link - Not "share".
## Known Issues
* You cannot send events when running from an IP address that is not secure.
Work arounds are not known at this time.
Patches are welcomed via email.

View file

@ -1,32 +1,29 @@
@media (max-width: 800px){
:root {
/* TODO font size should not be controlled by CSS:
* Instead I would prefer user settings. The main reason is the font is
* too small on my desktop when I use the app in column mode.
*/
--fsSmall: 10px;
--fsNormal: 14px;
--fsReduced: 12px;
--fsEnlarged: 16px;
}
@media (max-width: 840px){
/* Utility */
.vertical-hide {
display: none !important;
}
/* Application Framework */
#gnav {
display: initial;
}
#view {
flex: 1;
width: initial;
border-right: none;
}
.nav.mobile {
display: flex;
}
#content header > label {
padding: 12px;
}
.nav.mobile .new-note {
position: fixed;
height: initial;
bottom: 88px;
right: 20px;
z-index: var(--zGlobal);
padding: 24px;
}
/* Event */
.pfp { /* TODO sync up with userpic */

View file

@ -45,13 +45,6 @@ th, td {
text-align: right;
}
#gsticker {
position: absolute;
top: 0;
left: 0;
padding: 15px;
}
/* Welcome */
#container-busy .loader {
@ -83,98 +76,53 @@ th, td {
}
/* Navigation */
#nav {
.nav.full {
border-right: 1px solid var(--clrBorder);
padding: 10px;
}
#nav > div {
.nav.full > div {
position: sticky;
top: 16px;
display: flex;
flex-flow: column;
}
#nav > div > * {
.nav.full > div > * {
margin-bottom: 20px;
padding: 10px;
position: relative;
}
#nav > div[data-active] img.active {
.nav.mobile {
display: none;
background: var(--clrBg);
position: sticky;
bottom: 0;
z-index: var(--zHeader);
flex-direction: row;
border-top: var(--clrBorder) 1px solid;
}
.nav.mobile button {
padding: 18px;
flex: 1;
}
.nav [data-view].active img.inactive,
.nav [data-view] img.active {
display: none;
}
#nav > div[data-active="home"] [data-view="friends"] img.inactive,
#nav > div[data-active="explore"] [data-view="explore"] img.inactive,
#nav > div[data-active="notifications"] [data-view="notifications"] img.inactive,
#nav > div[data-active="settings"] [data-view="settings"] img.inactive,
#nav > div[data-active="messages"] [data-view="dm"] img.inactive {
display: none;
}
#nav > div[data-active="home"] [data-view="friends"] img.active,
#nav > div[data-active="explore"] [data-view="explore"] img.active,
#nav > div[data-active="notifications"] [data-view="notifications"] img.active,
#nav > div[data-active="settings"] [data-view="settings"] img.active,
#nav > div[data-active="messages"] [data-view="dm"] img.active {
.nav [data-view].active img.active {
display: block;
}
#new-note {
background: white;
height: 56px;
border-radius: 38px;
}
#app-icon-logo > img {
width: 36px;
height: 36px;
}
button.nav > img.icon {
width: 28px;
height: 28px;
}
#gnav {
display: none;
position: fixed;
bottom: 55px;
right: 55px;
z-index: var(--zGlobal);
.nav button.new-note {
background: white;
height: 56px;
border-radius: 38px;
}
#gnav button {
position: absolute;
top: 0;
left: 0;
font-size: 24px;
border-radius: 50%;
background: var(--clrText);
color: var(--clrBg);
padding: 10px;
border: transparent 5px solid;
transition: top 0.05s linear;
transform: translateX(-50%) translateY(-50%);
z-index: calc(var(--zGlobal) - 1);
}
#gnav button > .icon {
width: 28px;
height: 28px;
}
#gnav button[action="toggle-gnav"] {
z-index: var(--zGlobal);
padding: 15px;
}
#gnav.open button[data-view="friends"] {
top: -375px;
}
#gnav.open button[data-view="explore"] {
top: -300px;
}
#gnav.open button[data-view="dm"] {
top: -225px;
}
#gnav.open button[data-view="notifications"] {
top: -150px;
}
#gnav.open button[data-view="notifications"] .new-notifications {
right: 9px;
}
#gnav.open button[data-view="settings"] {
top: -75px;
#app-icon-logo > img {
width: 36px;
height: 36px;
}
.new-notifications {
@ -195,24 +143,29 @@ button.nav > img.icon {
flex-flow: row;
}
#view {
display: flex;
flex-direction: column;
flex-shrink: 0;
border-right: 1px solid var(--clrBorder);
width: 750px;
min-height: 100vh;
}
#view > div > header {
#view > header {
position: sticky;
top: 0;
z-index: var(--zHeader);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
}
#view > div > header > label {
#view > header > label {
padding: 15px;
font-size: 22px;
font-weight: 800;
display: block;
}
#timeline, #settings, #dms {
flex: 1;
}
#header-tools {
display: flex;
position: absolute;
@ -551,7 +504,7 @@ code {
}
#settings header > label {
font-weight: bold;
font-size: var(--fsEnlarged);
font-size: var(--fsLarge);
}
/* Messaging */

View file

@ -27,6 +27,7 @@
--fsReduced: 14px;
--fsNormal: 16px;
--fsEnlarged: 18px;
--fsLarge: 22px;
/* Font Families */
--ffDefault: "Noto Sans", sans-serif;

View file

@ -44,39 +44,18 @@
Yo, Sup?
<img class="icon svg" src="/icon/logo-inverted.svg"/>
</h1>
<p>The blue bird experience for Nostr.</p>
<button class="action" action="sign-in">
Sign In with Key
<img src="/icon/key.svg" class="icon svg small invert"/>
</button>
<p>A minimal experience for Nostr.</p>
<p>Please access with a nos2x compatible browser.</p>
</div>
</div>
</div>
<div id="container-app" class="hide">
<nav id="gnav">
<button class="icon" action="toggle-gnav" title="Open Menu">
<img class="icon svg invert" src="/icon/logo.svg"/>
</button>
<button class="icon" action="open-view" data-view="friends" title="Home">
<img class="icon svg invert" src="/icon/home.svg"/>
</button>
<button class="icon" action="open-view" data-view="dm" title="Direct Messages">
<img class="icon svg invert" src="/icon/messages.svg"/>
<div class="new-notifications hide" role="dm"></div>
</button>
<button class="icon" action="open-view" data-view="notifications" title="Notifications">
<img class="icon svg invert" src="/icon/notifications.svg"/>
<div class="new-notifications hide" role="activity"></div>
</button>
<button class="icon" action="open-view" data-view="settings" title="Settings">
<img class="icon svg invert" src="/icon/settings.svg"/>
</button>
</nav>
<div id="container">
<div class="flex-fill vertical-hide"></div>
<div id="nav" class="flex-noshrink vertical-hide">
<div data-active="home">
<nav id="nav" class="nav full flex-noshrink vertical-hide">
<div>
<div id="app-icon-logo">
<img class="icon svg" title="Damus" src="/icon/logo-inverted.svg"/>
</div>
@ -102,18 +81,17 @@
<img class="icon svg inactive" src="/icon/settings.svg"/>
<img class="icon svg active" src="/icon/settings-active.svg"/>
</button>
<button id="new-note" action="new-note" title="New Note" class="nav icon">
<button action="new-note" title="New Note" class="nav icon new-note">
<img class="icon svg invert" src="/icon/new-note.svg"/>
</button>
</div>
</div>
</nav>
<div id="view">
<div>
<header>
<label>Home</label>
<div id="header-tools">
<button class="action small bordered hide"
<button class="action small hide"
disabled action="mark-all-read">
Mark All Read
</button>
@ -167,11 +145,6 @@
<button action="show-timeline-new">
Show New (<span role="count">0</span>)</button>
</div>
<div id="dms-not-available" class="hide">
DMs could not be decrypted due to lack of nip04
integration. Please use an extension such as nos2x or
Alby.
</div>
<div id="dms" class="hide">
</div>
<div id="timeline" class="events"></div>
@ -198,35 +171,41 @@
</table>
</section>
<section>
<header><label>About</label></header>
<header><label>Info</label></header>
<p>
Yo, Sup? was originally Damus Web
written by <span action="open-profile" class="username clickable"
data-pubkey="32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245">
jb55</span>. It was rewritten by in order to bring
it up to date.
<a href="https://git.sr.ht/~tomtom/damus">Source Code</a>
<a href="https://todo.sr.ht/~tomtom/damus-web-issues">Bug Tracker</a>
<a href="mailto:thomas.c.mathews@gmail.com">Email Me</a>
</p>
<p>
Yo is open source under the AGPL-3 license. You can
find the source code <a
href="https://git.sr.ht/~tomtom/damus">here</a>.
</p>
<p>
Bugs and feature requests can be emailed to <a
href="mailto:thomas.c.mathews@gmail.com">thomas.c.mathews@gmail.com</a>
or submitted to the <a
href="https://todo.sr.ht/~tomtom/damus-web-issues">
tracker</a>.
</p>
</section>
<section>
<button class="action" role="sign-out">
Sign Out
<img class="icon svg small invert" src="/icon/sign-out.svg"/>
</button>
</section>
</div>
</div>
<nav class="nav mobile">
<button action="open-view" data-view="friends" class="icon"
title="Home">
<img class="icon svg inactive" src="/icon/home.svg"/>
<img class="icon svg active" src="/icon/home-active.svg"/>
</button>
<button action="open-view" data-view="dm" class="icon"
title="Direct Messages">
<img class="icon svg inactive" src="/icon/messages.svg"/>
<img class="icon svg active" src="/icon/messages-active.svg"/>
<div class="new-notifications hide" role="dm"></div>
</button>
<button action="open-view" data-view="notifications"
class="icon" title="Notifications">
<img class="icon svg inactive" src="/icon/notifications.svg"/>
<img class="icon svg active" src="/icon/notifications-active.svg"/>
<div class="new-notifications hide" role="activity"></div>
</button>
<button action="open-view" data-view="settings"
title="Settings" class="icon">
<img class="icon svg inactive" src="/icon/settings.svg"/>
<img class="icon svg active" src="/icon/settings-active.svg"/>
</button>
<button action="new-note" title="New Note" class="nav icon new-note">
<img class="icon svg invert" src="/icon/new-note.svg"/>
</button>
</nav>
</div>
<div class="flex-fill vertical-hide"></div>
</div>

View file

@ -81,10 +81,6 @@ async function webapp_init() {
// Load data from storage
await model_load_settings(model);
/*err = await contacts_load(model);
if (err) {
window.alert("Unable to load contacts.");
}*/
init_settings(model);
// Create our pool so that event processing functions can work
@ -96,14 +92,6 @@ async function webapp_init() {
pool.on("eose", on_pool_eose);
pool.on("ok", on_pool_ok);
// Load all events from storage and re-process them so that apply correct
// effects.
/*await model_load_events(model, (ev)=> {
model_process_event(model, undefined, ev);
});
log_debug("loaded events", Object.keys(model.all_events).length);
*/
var { mode, opts, valid } = parse_url_mode();
view_timeline_apply_mode(model, mode, opts, !valid);
on_timer_timestamps();
@ -171,7 +159,7 @@ function on_timer_save() {
setTimeout(() => {
const model = DAMUS;
//model_save_events(model);
model_save_settings(model);
//model_save_settings(model);
on_timer_save();
}, 1 * 1000);
}
@ -300,6 +288,7 @@ function fetch_profile(pubkey, pool, relay) {
}
function fetch_thread_history(evid, pool) {
// TODO look up referenced relays for thread history
const sid = `${SID_THREAD}:${evid}`
pool.subscribe(sid, [{
kinds: PUBLIC_KINDS,
@ -309,8 +298,7 @@ function fetch_thread_history(evid, pool) {
}
function fetch_friends_history(friends, pool, relay) {
// TODO only fetch friends history from their desired relay instead of
// pinging all of the relays
// TODO fetch history of each friend by their desired relay
pool.subscribe(SID_FRIENDS, [{
kinds: PUBLIC_KINDS,
authors: friends,

View file

@ -1,21 +1,12 @@
function init_settings(model) {
const el = find_node("#settings");
find_node("#add-relay", el).addEventListener("click", on_click_add_relay);
find_node("[role='sign-out']", el).addEventListener("click", on_click_sign_out);
const rlist = find_node("#relay-list tbody", el);
model.relays.forEach((str) => {
rlist.appendChild(new_relay_item(str));
});
}
async function on_click_sign_out(ev) {
if (confirm("Are you sure you want to sign out?")) {
localStorage.clear();
await dbclear();
window.location.reload();
}
}
function new_relay_item(str) {
const tr = document.createElement('tr');
tr.innerHTML = `<td>${str}</td>

View file

@ -115,17 +115,14 @@ function view_timeline_apply_mode(model, mode, opts={}, push_state=true) {
// Do some visual updates
find_node("#show-more").classList.add("hide");
find_node("#view header > label").innerText = name;
find_node("#nav > div[data-active]").dataset.active = names[mode].toLowerCase();
find_node("#view header > label").innerText = name;
view_update_navs(mode);
find_node("#view [role='profile-info']").classList.toggle("hide", mode != VM_USER);
const timeline_el = find_node("#timeline");
timeline_el.classList.toggle("reverse", mode == VM_THREAD);
timeline_el.classList.toggle("hide", mode == VM_SETTINGS || mode == VM_DM);
find_node("#settings").classList.toggle("hide", mode != VM_SETTINGS);
find_node("#dms").classList.toggle("hide", mode != VM_DM);
find_node("#dms-not-available")
.classList.toggle("hide", mode == VM_DM_THREAD || mode == VM_DM ?
dms_available() : true);
find_node("#header-tools button[action='mark-all-read']")
.classList.toggle("hide", mode != VM_DM);
@ -220,6 +217,12 @@ function view_timeline_refresh(model, mode, opts={}) {
}
}
function view_update_navs(mode) {
find_nodes("nav.nav button[data-view]").forEach((el)=> {
el.classList.toggle("active", el.dataset.view == mode)
});
}
function view_show_spinner(show=true) {
find_node("#view .loading-events").classList.toggle("hide", !show);
}
@ -546,7 +549,6 @@ function get_thread_root_id(damus, id) {
function switch_view(mode, opts) {
view_timeline_apply_mode(DAMUS, mode, opts);
close_gnav();
}
function toggle_hide_replys(el) {
@ -668,9 +670,6 @@ function onclick_any(ev) {
const el = ev.target;
const action = el.getAttribute("action");
switch (action) {
case "toggle-gnav":
toggle_gnav(el);
break;
case "sign-in":
signin();
break;

View file

@ -3,17 +3,6 @@
* this file grows specific UI area code should be migrated to its own file.
*/
/* toggle_gnav hides or shows the global navigation's additional buttons based
* on its opened state.
*/
function toggle_gnav(el) {
el.parentElement.classList.toggle("open");
}
function close_gnav() {
find_node("#gnav").classList.remove("open");
}
/* init_message_textareas finds all message textareas and updates their initial
* height based on their content (0). This is so there is no jaring affect when
* the page loads.