openvibers/openvibe.network Commits

Wallet: Opening soon instead of a primary button that leads nowhere (#565)

OP OpenVibers committed 8 days ago · 688db097ea · 5 files, +36 −12

* Wallet: a closed currency's button says Opening soon, not a primary that opens a dead end

While Balance is closed, Add money was the page's loudest button and opened a dialog that said it was not open.
Now a closed currency's action is a quiet, unpressable Opening soon (Move to a project is off too), the Vibes card
says why when Vibes are closed, and a button label never breaks inside the button on a phone.

* Phone text is at least 12 px on the wallet, /my and the sign-in and admin forms

Measured signed in at 390 px: the wallet's tags and small headings were 11.84 px, /my's continue rows 11.5 px and its
hints 10 px, and the form labels on /my, admin and the sign-in page 11 px.

Changes

ddiff --git a/public/css/admin.css b/public/css/admin.css
iindex e564e253..f9b16512 100644
---- a/public/css/admin.css
++++ b/public/css/admin.css
@@@ -79,7 +79,7 @@ a.btn{text-decoration:none}
/* Form fields */
.form-field{margin-bottom:14px}
--.form-field label{display:block;font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:5px}
++.form-field label{display:block;font-size:12px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:5px}
.form-field input,.form-field select,.form-field textarea{
width:100%;padding:10px 12px;background:var(--bg-input);border:1px solid var(--border);
border-radius:8px;color:var(--text);font-size:13px;outline:none;transition:border-color var(--ov-dur-2, .2s);
ddiff --git a/public/css/login.css b/public/css/login.css
iindex 466c3831..1c5a782c 100644
---- a/public/css/login.css
++++ b/public/css/login.css
@@@ -93,7 +93,7 @@ body{min-height:100dvh;background:var(--bg);color:var(--text);font-family:'Inter
@keyframes panel-in{from{transform:translateX(10px);opacity:0}to{transform:translateX(0);opacity:1}}
.field{margin-bottom:16px;position:relative}
--.field label{display:block;font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}
++.field label{display:block;font-size:12px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}
.field input{
width:100%;padding:12px 14px;background:var(--bg-input);border:1px solid var(--border);
border-radius:10px;color:var(--text);font-size:14px;outline:none;
ddiff --git a/public/css/my.css b/public/css/my.css
iindex b21fd13e..6ba26d9c 100644
---- a/public/css/my.css
++++ b/public/css/my.css
@@@ -90,7 +90,7 @@ body{min-height:100%;color:var(--text);font-family:'Inter',-apple-system,BlinkMa
:where(input,select,textarea):user-invalid{border-color:var(--danger,#ef4444)}
.form-field input,.form-field select,.form-field textarea{width:100%}
.form-field textarea{resize:vertical;min-height:60px}
--.form-field .hint{font-size:10px;color:var(--text-muted);margin-top:3px}
++.form-field .hint{font-size:12px;color:var(--text-muted);margin-top:3px}
.theme-submit{display:grid;grid-template-columns:repeat(2,minmax(0,1fr)) auto;gap:12px;align-items:start;margin-top:16px}
.theme-submit .form-field{margin:0}
.theme-submit .btn{margin-top:21px;min-height:40px}
@@@ -273,7 +273,7 @@ a.linked-item:hover{background:var(--bg-hover,var(--bg-card));transform:translat
.td-cont:hover, .td-site:hover, .td-try:hover { border-color: var(--accent); }
.td-cont-ic, .td-site-ic { display: grid; place-items: center; width: 32px; height: 32px; border-radius: 10px; background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent-light); font-size: 14px; flex: none; }
.td-cont-t { font-size: 13.5px; font-weight: 650; line-height: 1.35; }
--.td-cont-m { font-size: 11.5px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
++.td-cont-m { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.td-grid { display: grid; align-items: start; gap: 16px; }
.td-box { display: grid; align-content: start; gap: 12px; padding: 16px; min-width: 0; }
.td-sites { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
ddiff --git a/public/css/wallet.css b/public/css/wallet.css
iindex 4f545af5..211f0047 100644
---- a/public/css/wallet.css
++++ b/public/css/wallet.css
@@@ -64,7 +64,8 @@ a { color: var(--accent, #3b82f6); }
}
.w-line { margin: 4px 0 0; color: var(--text-secondary, #a8b3c4); font-size: .88rem; line-height: 1.45; }
.w-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: auto; padding-top: 18px; }
--.w-actions .ovk-btn { flex: 1 1 140px; }
++/* A label never breaks inside its button: on a phone the second button takes its own row. */
++.w-actions .ovk-btn { flex: 1 1 140px; white-space: nowrap; }
.w-note { margin: 10px 0 0; font-size: .78rem; line-height: 1.45; color: var(--text-muted, #7d8aa0); }
.w-note.is-warn { color: var(--warning-text, var(--warning, #b45309)); }
@@@ -89,8 +90,8 @@ a { color: var(--accent, #3b82f6); }
.w-project-link { display: flex; align-items: center; gap: 4px; color: inherit; text-decoration: none; min-width: 0; }
.w-project-link:hover b { color: var(--accent-light, var(--accent, #60a5fa)); }
.w-project-link b { font-size: .93rem; font-weight: 650; overflow-wrap: anywhere; }
--.w-project-ext { color: var(--text-muted, #7d8aa0); font-size: .74rem; line-height: 1; }
--.w-project-sub { margin-top: 2px; color: var(--text-muted, #7d8aa0); font-size: .74rem; font-variant-numeric: tabular-nums; }
++.w-project-ext { color: var(--text-muted, #7d8aa0); font-size: .78rem; line-height: 1; }
++.w-project-sub { margin-top: 2px; color: var(--text-muted, #7d8aa0); font-size: .78rem; font-variant-numeric: tabular-nums; }
.w-project-side { flex: none; display: flex; align-items: center; gap: 10px; }
.w-project-bal { font-variant-numeric: tabular-nums; font-weight: 750; font-size: .95rem; white-space: nowrap; }
@media (max-width: 359px) {
@@@ -138,14 +139,14 @@ a { color: var(--accent, #3b82f6); }
/* Where each works: one quiet line of chips per currency */
.w-where { margin-top: 34px; padding-top: 20px; border-top: 1px solid var(--border, rgba(255, 255, 255, .12)); }
--.w-where h2 { margin: 0 0 12px; color: var(--text-muted, #7d8aa0); font-size: .74rem; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; }
++.w-where h2 { margin: 0 0 12px; color: var(--text-muted, #7d8aa0); font-size: .78rem; font-weight: 800; letter-spacing: .09em; text-transform: uppercase; }
.w-where-list { display: grid; gap: 9px; margin: 0; }
.w-where-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.w-where-row dt { min-width: 76px; color: var(--text-secondary, #a8b3c4); font-size: .8rem; font-weight: 700; }
.w-where-row dd { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.w-tag {
padding: 3px 10px; border: 1px solid var(--border, rgba(255, 255, 255, .12)); border-radius: 999px;
-- background: var(--bg-secondary, #101828); color: var(--text-secondary, #a8b3c4); font-size: .74rem; line-height: 1.5;
++ background: var(--bg-secondary, #101828); color: var(--text-secondary, #a8b3c4); font-size: .78rem; line-height: 1.5;
}
/* ── Sheets (Move to a project, Add money, Get Vibes) ── */
@@@ -172,7 +173,7 @@ a { color: var(--accent, #3b82f6); }
.w-tab[aria-selected="true"] { background: var(--bg-card, #121826); color: var(--text-primary, #e8ecf3); }
.w-field { display: grid; gap: 5px; min-width: 0; }
--.w-field > span { color: var(--text-muted, #7d8aa0); font-size: .72rem; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; }
++.w-field > span { color: var(--text-muted, #7d8aa0); font-size: .75rem; font-weight: 800; letter-spacing: .05em; text-transform: uppercase; }
.w-field input, .w-field select {
width: 100%; min-height: 46px; padding: 10px 12px; border-radius: 11px;
border: 1px solid var(--border, rgba(255, 255, 255, .12)); background: var(--bg-input, #0f1522);
ddiff --git a/public/js/wallet/page.js b/public/js/wallet/page.js
iindex 08f321e0..3c677919 100644
---- a/public/js/wallet/page.js
++++ b/public/js/wallet/page.js
@@@ -75,11 +75,34 @@
$('w-vibes-amount').textContent = DATA && DATA.state.vibes === 'open' ? M.vibes(vibesCount()) : (DATA && DATA.state.vibes === 'closed' ? M.vibes(0) : '—');
note('w-vibes-note', DATA && DATA.state.vibes === 'not_authoritative' ? "Vibes aren't in this wallet until Billing takes them over." :
-- DATA && DATA.state.vibes === 'unavailable' ? "Your Vibes couldn't load." : '', 'quiet');
++ DATA && DATA.state.vibes === 'unavailable' ? "Your Vibes couldn't load." :
++ DATA && !vibesOpen() ? "Vibes aren't open yet. When they are, Get Vibes buys them, or moves dollars from your Balance." : '', 'quiet');
$('w-coins-amount').textContent = DATA ? M.vibes(DATA.opencoins) : '—';
}
++ /** Vibes can be had when they are open (buy) or when Balance is (move dollars into Vibes). */
++ function vibesOpen() { return !!(DATA && DATA.state && (DATA.state.vibes === 'open' || balanceOpen())); }
++
++ // A primary button promises the action works. While a currency is not open, its button is a quiet "Opening soon"
++ // that cannot be pressed, and the card's note says why; once it opens, the button is the primary action again.
++ function setAction(id, open, label, closedTitle) {
++ const btn = $(id);
++ const closed = DATA && DATA.state && !open;
++ btn.disabled = !open;
++ btn.textContent = closed ? 'Opening soon' : label;
++ btn.classList.toggle('ovk-btn--primary', !closed);
++ btn.classList.toggle('ovk-btn--quiet', closed);
++ btn.title = closed ? closedTitle : '';
++ }
++ function renderActions() {
++ setAction('w-add-money', balanceOpen(), 'Add money', "Balance isn't open yet");
++ const move = $('w-move');
++ move.disabled = !balanceOpen();
++ move.title = balanceOpen() ? '' : "Balance isn't open yet";
++ setAction('w-get-vibes', vibesOpen(), 'Get Vibes', "Vibes aren't open yet");
++ }
++
function renderProjects() {
const list = $('w-projects');
list.replaceChildren();
@@@ -329,7 +352,7 @@
try {
DATA = await W.api('/api/wallet');
render();
-- for (const id of ['w-add-money', 'w-move', 'w-get-vibes']) $(id).disabled = false;
++ renderActions();
} catch (e) {
banner("The wallet couldn't load right now.", true);
$('w-balance-amount').textContent = '—';