Add a settings page for profit display and default stack
- Per-device toggle to hide your own net and the net ranking at tables - Default starting stack set in settings; creating a table saves the stack, SB and BB used as the next defaults - Number fields on create and settings select all on focus Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ed3d1e437e
commit
22ee28ba03
9 files changed
+160
-8
No files matched your search
+39
-1
@@ -28,8 +28,46 @@
|
||||
}
|
||||
return t;
|
||||
},
|
||||
// テーブルで自分の収支を表示するか(設定画面で切り替える。既定は表示)
|
||||
get showNet() { return lsGet('poker.showNet') !== '0'; },
|
||||
set showNet(v) { lsSet('poker.showNet', v ? '1' : '0'); },
|
||||
// テーブル作成画面の開始スタックの初期値(設定画面で変えられ、テーブルを作るたびに前回値で上書きする)
|
||||
get defaultStack() {
|
||||
const n = Number(lsGet('poker.defaultStack'));
|
||||
return Number.isInteger(n) && n >= 10 && n <= 100000000 ? n : 1000;
|
||||
},
|
||||
set defaultStack(v) { lsSet('poker.defaultStack', String(v)); },
|
||||
// 前回テーブルを作ったときの SB/BB と、そのときの開始スタック { stack, sb, bb }
|
||||
get lastBlinds() {
|
||||
try {
|
||||
const b = JSON.parse(lsGet('poker.lastBlinds'));
|
||||
return b && [b.stack, b.sb, b.bb].every(Number.isInteger) && b.sb >= 1 && b.bb > b.sb && b.bb <= b.stack ? b : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
set lastBlinds(v) { lsSet('poker.lastBlinds', JSON.stringify(v)); },
|
||||
};
|
||||
|
||||
// 数値の入力欄: フォーカスしたら全体を選択して、そのまま打ち替えられるようにする
|
||||
function selectOnFocus(el) {
|
||||
let skipMouseUp = false;
|
||||
el.addEventListener('focus', () => {
|
||||
el.select();
|
||||
skipMouseUp = true;
|
||||
// iOS Safari はタップの処理の後で選択が外れるので、もう一度選ぶ
|
||||
setTimeout(() => {
|
||||
if (document.activeElement === el) el.select();
|
||||
}, 0);
|
||||
});
|
||||
// クリックで入ったときは、離した位置にカーソルが置かれて選択が外れるのを防ぐ
|
||||
el.addEventListener('mouseup', (e) => {
|
||||
if (skipMouseUp) e.preventDefault();
|
||||
skipMouseUp = false;
|
||||
});
|
||||
el.addEventListener('keydown', () => { skipMouseUp = false; });
|
||||
}
|
||||
|
||||
function esc(s) {
|
||||
return String(s).replace(/[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c]));
|
||||
}
|
||||
@@ -233,5 +271,5 @@
|
||||
FINISHING: 'FINISHING',
|
||||
};
|
||||
|
||||
window.App = { Store, esc, chips, toast, confirm: confirmDialog, api, copyText, connectSocket, safeNext, PHASE_LABELS };
|
||||
window.App = { Store, esc, chips, toast, selectOnFocus, confirm: confirmDialog, api, copyText, connectSocket, safeNext, PHASE_LABELS };
|
||||
})();
|
||||
+13
-1
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const { Store, api, chips } = App;
|
||||
const { Store, api, chips, selectOnFocus } = App;
|
||||
if (!Store.name) {
|
||||
location.replace('/');
|
||||
return;
|
||||
@@ -109,6 +109,7 @@
|
||||
timerInput.addEventListener('change', refresh);
|
||||
intervalInput.addEventListener('input', refresh);
|
||||
form.querySelectorAll('input[type="radio"]').forEach((el) => el.addEventListener('change', refresh));
|
||||
[stackInput, sbInput, bbInput, intervalInput].forEach(selectOnFocus);
|
||||
$('reroll').addEventListener('click', suggestName);
|
||||
Fluid.Segmented(form.querySelector('.segmented.numbers'));
|
||||
Fluid.navBar($('nav'), $('large-title'));
|
||||
@@ -152,6 +153,9 @@
|
||||
cpuCount: Number(radioValue('cpu-count')),
|
||||
token: Store.token,
|
||||
});
|
||||
// 次にテーブルを作るときの初期値にする
|
||||
Store.defaultStack = int(stackInput);
|
||||
Store.lastBlinds = { stack: int(stackInput), sb: int(sbInput), bb: int(bbInput) };
|
||||
location.href = '/table/' + encodeURIComponent(id);
|
||||
} catch (err) {
|
||||
errorEl.textContent = err.message;
|
||||
@@ -164,7 +168,15 @@
|
||||
.then((me) => { $('review-mode').hidden = !me.admin; })
|
||||
.catch(() => {});
|
||||
|
||||
// 開始スタックは設定(=前回値)。SB/BB は前回と同じ開始スタックなら前回値を引き継ぐ
|
||||
stackInput.value = Store.defaultStack;
|
||||
applyDefaultBlinds();
|
||||
const last = Store.lastBlinds;
|
||||
if (last && last.stack === Store.defaultStack && (last.sb !== int(sbInput) || last.bb !== int(bbInput))) {
|
||||
sbInput.value = last.sb;
|
||||
bbInput.value = last.bb;
|
||||
blindsTouched = true;
|
||||
}
|
||||
refresh();
|
||||
suggestName();
|
||||
})();
|
||||
@@ -0,0 +1,34 @@
|
||||
// 設定: この端末だけに保存する(localStorage)
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const { Store, selectOnFocus } = App;
|
||||
const $ = (id) => document.getElementById(id);
|
||||
|
||||
Fluid.navBar($('nav'), $('large-title'));
|
||||
|
||||
const showNet = $('show-net');
|
||||
showNet.checked = Store.showNet;
|
||||
showNet.addEventListener('change', () => {
|
||||
Store.showNet = showNet.checked;
|
||||
Fluid.haptic(6);
|
||||
});
|
||||
|
||||
const stack = $('default-stack');
|
||||
stack.value = Store.defaultStack;
|
||||
selectOnFocus(stack);
|
||||
// 正しい値のときだけ保存する。外したときに不正なら保存済みの値に戻す
|
||||
stack.addEventListener('input', () => {
|
||||
const n = Number(stack.value);
|
||||
const ok = Number.isInteger(n) && n >= 10 && n <= 100000000;
|
||||
stack.classList.toggle('invalid', stack.value !== '' && !ok);
|
||||
if (ok) Store.defaultStack = n;
|
||||
});
|
||||
stack.addEventListener('blur', () => {
|
||||
stack.classList.remove('invalid');
|
||||
stack.value = Store.defaultStack;
|
||||
});
|
||||
stack.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') stack.blur();
|
||||
});
|
||||
})();
|
||||
@@ -468,6 +468,9 @@ a {
|
||||
.tone-purple {
|
||||
background: linear-gradient(180deg, #c86ff0, #9440c2);
|
||||
}
|
||||
.tone-gray {
|
||||
background: linear-gradient(180deg, #a1a1a8, #75757c);
|
||||
}
|
||||
|
||||
/* セルの中の入力(ラベルが左、値が右) */
|
||||
.field-cell {
|
||||
|
||||
+10
-5
@@ -437,8 +437,9 @@
|
||||
const o = m.options;
|
||||
|
||||
Fluid.countTo($('my-stack'), m.stack, chips);
|
||||
const net = m.net;
|
||||
$('my-net').textContent = `収支 ${net > 0 ? '+' : net < 0 ? '−' : '±'}${chips(Math.abs(net))}`;
|
||||
// 収支は設定で消せる(この端末だけ)
|
||||
const net = Store.showNet ? m.net : null;
|
||||
$('my-net').textContent = net == null ? '' : `収支 ${net > 0 ? '+' : net < 0 ? '−' : '±'}${chips(Math.abs(net))}`;
|
||||
$('my-net').className = net > 0 ? 'plus' : net < 0 ? 'minus' : '';
|
||||
$('my-bet').textContent = seat.inHand && seat.bet > 0 ? `ベット中 ${chips(seat.bet)}` : '';
|
||||
$('my-hand').textContent = (seat.inHand && seat.handName) || '';
|
||||
@@ -642,8 +643,11 @@
|
||||
net: '収支 = 持っているチップ − バイインの合計(リバイを含む)',
|
||||
};
|
||||
|
||||
// 収支を表示しない設定のときはスタック順だけ
|
||||
const rankMode = () => (Store.showNet ? rankBy : 'stack');
|
||||
|
||||
function rankingEntries(s) {
|
||||
const key = rankBy === 'net' ? 'net' : 'held';
|
||||
const key = rankMode() === 'net' ? 'net' : 'held';
|
||||
const list = s.seats.filter(Boolean).sort((a, b) => b[key] - a[key] || a.seat - b.seat);
|
||||
let rank = 0;
|
||||
return list.map((p, i) => {
|
||||
@@ -694,7 +698,7 @@
|
||||
const sub = [p.seat === s.mySeat && 'あなた', p.bot && 'CPU', p.sittingOut && '離席中', !p.connected && 'オフライン']
|
||||
.filter(Boolean)
|
||||
.join(' ・ ');
|
||||
const net = rankBy === 'net';
|
||||
const net = rankMode() === 'net';
|
||||
patch(
|
||||
el,
|
||||
`<span class="rank-no${rank <= 3 ? ` top-${rank}` : ''}">${rank}</span>` +
|
||||
@@ -712,7 +716,8 @@
|
||||
rankRows.delete(seat);
|
||||
}
|
||||
slideFrom(before); // 順位が変わった行は元の位置から滑らせる
|
||||
$('ranking-note').textContent = RANK_NOTE[rankBy];
|
||||
$('ranking-tabs').hidden = !Store.showNet;
|
||||
$('ranking-note').textContent = RANK_NOTE[rankMode()];
|
||||
if (!s.seats.some(Boolean)) listEl.innerHTML = '<li class="empty">まだ誰も座っていません</li>';
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user