Compare commits
2 Commits
f3cc672051
...
b5b721cd60
| Author | SHA1 | Date |
|---|---|---|
|
|
b5b721cd60 | |
|
|
147d85abf6 |
|
|
@ -26,10 +26,10 @@
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="https://posimai-ui.vercel.app/v1/base.css">
|
<link rel="stylesheet" href="https://posimai-ui.vercel.app/v1/base.css">
|
||||||
<link rel="stylesheet" href="https://unpkg.com/@xterm/xterm@6.0.0/css/xterm.css">
|
<link rel="stylesheet" href="https://unpkg.com/@xterm/xterm@6.0.0/css/xterm.css" integrity="sha384-n2n7twoohnW+d3myBKaUgl7DSiwidw6MkQy9oesGzkPpMjejKRR3XlnD+5yCdtBD" crossorigin="anonymous">
|
||||||
<script src="https://unpkg.com/lucide@0.344.0/dist/umd/lucide.min.js" integrity="sha384-tTkFttkBclaU1cloKwOi9xk3pbao3VZxTjLNBt8iFABWDBQibbAbWpVmO28zMuxq" crossorigin="anonymous"></script>
|
<script src="https://unpkg.com/lucide@0.344.0/dist/umd/lucide.min.js" integrity="sha384-tTkFttkBclaU1cloKwOi9xk3pbao3VZxTjLNBt8iFABWDBQibbAbWpVmO28zMuxq" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/@xterm/xterm@6.0.0/lib/xterm.js"></script>
|
<script src="https://unpkg.com/@xterm/xterm@6.0.0/lib/xterm.js" integrity="sha384-f/1U6Z9wM4D71a5eRXEZnyOTMOvjqxr2XLwh+Go1OvIl3L3tOcvUrzudnhbECwl4" crossorigin="anonymous"></script>
|
||||||
<script src="https://unpkg.com/@xterm/addon-fit@0.11.0/lib/addon-fit.js"></script>
|
<script src="https://unpkg.com/@xterm/addon-fit@0.11.0/lib/addon-fit.js" integrity="sha384-txoiwu4RR2GD3qySbaj+BbzibkLbSJRcfqGYMu6z1EqHil4A2dyBiBW5dlacG6OR" crossorigin="anonymous"></script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
|
|
@ -294,7 +294,7 @@
|
||||||
<i data-lucide="terminal" style="width:12px;height:12px;stroke-width:1.75;color:var(--accent);flex-shrink:0"></i>
|
<i data-lucide="terminal" style="width:12px;height:12px;stroke-width:1.75;color:var(--accent);flex-shrink:0"></i>
|
||||||
<span id="settingsSessionId">—</span>
|
<span id="settingsSessionId">—</span>
|
||||||
</div>
|
</div>
|
||||||
<a href="/sessions.html" style="font-size:13px;color:var(--accent);text-decoration:none;display:flex;align-items:center;gap:6px;margin-top:10px" rel="noopener">
|
<a href="/sessions.html" style="font-size:13px;color:var(--accent);text-decoration:none;display:flex;align-items:center;gap:6px;margin-top:10px" rel="noopener noreferrer">
|
||||||
<i data-lucide="history" style="width:14px;height:14px;stroke-width:1.75"></i>
|
<i data-lucide="history" style="width:14px;height:14px;stroke-width:1.75"></i>
|
||||||
過去のセッションを見る
|
過去のセッションを見る
|
||||||
</a>
|
</a>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"id": "/posimai-dev/",
|
||||||
"name": "posimai-dev",
|
"name": "posimai-dev",
|
||||||
"short_name": "dev",
|
"short_name": "dev",
|
||||||
"description": "posimai development portal",
|
"description": "posimai development portal",
|
||||||
|
|
|
||||||
|
|
@ -227,7 +227,7 @@
|
||||||
<div class="stat-card"><div class="stat-label">Node.js</div><div class="stat-val" id="node-val">—</div></div>
|
<div class="stat-card"><div class="stat-label">Node.js</div><div class="stat-val" id="node-val">—</div></div>
|
||||||
<div class="stat-card"><div class="stat-label">Platform</div><div class="stat-val" id="platform-val">—</div></div>
|
<div class="stat-card"><div class="stat-label">Platform</div><div class="stat-val" id="platform-val">—</div></div>
|
||||||
</div>
|
</div>
|
||||||
<a class="open-btn" href="/" target="_blank" rel="noopener"><i data-lucide="terminal"></i>posimai-dev を開く</a>
|
<a class="open-btn" href="/" target="_blank" rel="noopener noreferrer"><i data-lucide="terminal"></i>posimai-dev を開く</a>
|
||||||
<!-- Divider -->
|
<!-- Divider -->
|
||||||
<div class="machines-divider"></div>
|
<div class="machines-divider"></div>
|
||||||
<!-- VPS section -->
|
<!-- VPS section -->
|
||||||
|
|
@ -333,10 +333,10 @@
|
||||||
<div id="bottom-row">
|
<div id="bottom-row">
|
||||||
<div class="bottom-brand">posimai<span>-station</span> <span style="font-size:10px;color:var(--violet);margin-left:4px">B</span></div>
|
<div class="bottom-brand">posimai<span>-station</span> <span style="font-size:10px;color:var(--violet);margin-left:4px">B</span></div>
|
||||||
<div class="bottom-links">
|
<div class="bottom-links">
|
||||||
<a class="bottom-link" href="/station" rel="noopener"><i data-lucide="monitor"></i>Design A</a>
|
<a class="bottom-link" href="/station" rel="noopener noreferrer"><i data-lucide="monitor"></i>Design A</a>
|
||||||
<a class="bottom-link" href="/" target="_blank" rel="noopener"><i data-lucide="terminal"></i>dev</a>
|
<a class="bottom-link" href="/" target="_blank" rel="noopener noreferrer"><i data-lucide="terminal"></i>dev</a>
|
||||||
<a class="bottom-link" href="https://posimai-atlas.vercel.app" target="_blank" rel="noopener"><i data-lucide="network"></i>atlas</a>
|
<a class="bottom-link" href="https://posimai-atlas.vercel.app" target="_blank" rel="noopener noreferrer"><i data-lucide="network"></i>atlas</a>
|
||||||
<a class="bottom-link" href="https://posimai.soar-enrich.com" target="_blank" rel="noopener"><i data-lucide="layout-dashboard"></i>dashboard</a>
|
<a class="bottom-link" href="https://posimai.soar-enrich.com" target="_blank" rel="noopener noreferrer"><i data-lucide="layout-dashboard"></i>dashboard</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="refresh-countdown">次の更新まで <span id="countdown">30</span>s</div>
|
<div id="refresh-countdown">次の更新まで <span id="countdown">30</span>s</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,7 @@
|
||||||
<div class="stat-card"><div class="stat-label">Platform</div><div class="stat-val" id="platform-val">—</div></div>
|
<div class="stat-card"><div class="stat-label">Platform</div><div class="stat-val" id="platform-val">—</div></div>
|
||||||
<div class="stat-card" id="temp-card" style="display:none"><div class="stat-label">CPU Temp</div><div class="stat-val" id="temp-val">—</div></div>
|
<div class="stat-card" id="temp-card" style="display:none"><div class="stat-label">CPU Temp</div><div class="stat-val" id="temp-val">—</div></div>
|
||||||
</div>
|
</div>
|
||||||
<a class="open-btn" href="/" target="_blank" rel="noopener"><i data-lucide="terminal"></i>posimai-dev を開く</a>
|
<a class="open-btn" href="/" target="_blank" rel="noopener noreferrer"><i data-lucide="terminal"></i>posimai-dev を開く</a>
|
||||||
</div>
|
</div>
|
||||||
<!-- Col 2: rings + sparkline -->
|
<!-- Col 2: rings + sparkline -->
|
||||||
<div class="panel rings-panel">
|
<div class="panel rings-panel">
|
||||||
|
|
@ -317,10 +317,10 @@
|
||||||
<div id="bottom-row">
|
<div id="bottom-row">
|
||||||
<div class="bottom-brand">posimai<span>-station</span></div>
|
<div class="bottom-brand">posimai<span>-station</span></div>
|
||||||
<div class="bottom-links">
|
<div class="bottom-links">
|
||||||
<a class="bottom-link" href="/station-b" rel="noopener"><i data-lucide="monitor"></i>Design B</a>
|
<a class="bottom-link" href="/station-b" rel="noopener noreferrer"><i data-lucide="monitor"></i>Design B</a>
|
||||||
<a class="bottom-link" href="/" target="_blank" rel="noopener"><i data-lucide="terminal"></i>dev</a>
|
<a class="bottom-link" href="/" target="_blank" rel="noopener noreferrer"><i data-lucide="terminal"></i>dev</a>
|
||||||
<a class="bottom-link" href="https://posimai-atlas.vercel.app" target="_blank" rel="noopener"><i data-lucide="network"></i>atlas</a>
|
<a class="bottom-link" href="https://posimai-atlas.vercel.app" target="_blank" rel="noopener noreferrer"><i data-lucide="network"></i>atlas</a>
|
||||||
<a class="bottom-link" href="https://posimai.soar-enrich.com" target="_blank" rel="noopener"><i data-lucide="layout-dashboard"></i>dashboard</a>
|
<a class="bottom-link" href="https://posimai.soar-enrich.com" target="_blank" rel="noopener noreferrer"><i data-lucide="layout-dashboard"></i>dashboard</a>
|
||||||
</div>
|
</div>
|
||||||
<div id="refresh-countdown">次の更新まで <span id="countdown">30</span>s</div>
|
<div id="refresh-countdown">次の更新まで <span id="countdown">30</span>s</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
21
server.js
21
server.js
|
|
@ -2547,8 +2547,17 @@ ${excerpt}
|
||||||
});
|
});
|
||||||
|
|
||||||
// GET /together/feed/:groupId — フィード(リアクション・コメント数付き)
|
// GET /together/feed/:groupId — フィード(リアクション・コメント数付き)
|
||||||
|
// ?limit=N&cursor=<ISO timestamp> でカーソルページネーション対応
|
||||||
r.get('/together/feed/:groupId', async (req, res) => {
|
r.get('/together/feed/:groupId', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
|
const limit = Math.min(parseInt(req.query.limit) || 20, 50);
|
||||||
|
const cursor = req.query.cursor; // shared_at の ISO タイムスタンプ
|
||||||
|
const params = [req.params.groupId];
|
||||||
|
let cursorClause = '';
|
||||||
|
if (cursor) {
|
||||||
|
params.push(cursor);
|
||||||
|
cursorClause = 'AND s.shared_at < $2';
|
||||||
|
}
|
||||||
const result = await pool.query(`
|
const result = await pool.query(`
|
||||||
SELECT
|
SELECT
|
||||||
s.*,
|
s.*,
|
||||||
|
|
@ -2560,12 +2569,16 @@ ${excerpt}
|
||||||
FROM together_shares s
|
FROM together_shares s
|
||||||
LEFT JOIN together_reactions r ON r.share_id = s.id
|
LEFT JOIN together_reactions r ON r.share_id = s.id
|
||||||
LEFT JOIN together_comments c ON c.share_id = s.id
|
LEFT JOIN together_comments c ON c.share_id = s.id
|
||||||
WHERE s.group_id = $1
|
WHERE s.group_id = $1 ${cursorClause}
|
||||||
GROUP BY s.id
|
GROUP BY s.id
|
||||||
ORDER BY s.shared_at DESC
|
ORDER BY s.shared_at DESC
|
||||||
LIMIT 50
|
LIMIT ${limit + 1}
|
||||||
`, [req.params.groupId]);
|
`, params);
|
||||||
res.json(result.rows);
|
const rows = result.rows;
|
||||||
|
const hasMore = rows.length > limit;
|
||||||
|
const items = hasMore ? rows.slice(0, limit) : rows;
|
||||||
|
const nextCursor = items.length > 0 ? items[items.length - 1].shared_at : null;
|
||||||
|
res.json({ items, next_cursor: nextCursor, has_more: hasMore });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[together/feed]', e.message);
|
console.error('[together/feed]', e.message);
|
||||||
res.status(500).json({ error: 'Internal server error' });
|
res.status(500).json({ error: 'Internal server error' });
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue