feat(posimai-dev): voice input, bigger Claude icon, aurora bg, session in settings
- Web Speech API mic button (ja-JP, pulses red while listening, hidden if unsupported) - Claude bot icon 15px → 20px, button 32px → 36px - Aurora gradient opacity 7% → 14% (visible through transparent xterm canvas) - Session ID moved to settings panel (hidden in chat bar) - Removed chat input placeholder Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
170dfaa7e0
commit
d7f38faa59
|
|
@ -74,23 +74,38 @@
|
||||||
}
|
}
|
||||||
.status-badge.disconnected { background: rgba(239,68,68,0.12); color: #F87171; }
|
.status-badge.disconnected { background: rgba(239,68,68,0.12); color: #F87171; }
|
||||||
|
|
||||||
/* セッションバッジ(チャットバー内) */
|
|
||||||
.session-badge {
|
|
||||||
font-size: 10px; font-weight: 400; color: rgba(255,255,255,0.25);
|
|
||||||
font-family: monospace; display: none; white-space: nowrap;
|
|
||||||
overflow: hidden; text-overflow: ellipsis; max-width: 180px;
|
|
||||||
}
|
|
||||||
.session-badge.visible { display: block; }
|
|
||||||
|
|
||||||
/* Claude開始ボタン — アイコンのみ */
|
/* Claude開始ボタン — アイコンのみ */
|
||||||
.claude-btn {
|
.claude-btn {
|
||||||
width: 32px; height: 32px; border-radius: 8px; border: none; cursor: pointer;
|
width: 36px; height: 36px; border-radius: 8px; border: none; cursor: pointer;
|
||||||
background: var(--accent-dim); color: var(--accent);
|
background: var(--accent-dim); color: var(--accent);
|
||||||
display: flex; align-items: center; justify-content: center;
|
display: flex; align-items: center; justify-content: center;
|
||||||
flex-shrink: 0; transition: background 0.15s;
|
flex-shrink: 0; transition: background 0.15s;
|
||||||
}
|
}
|
||||||
.claude-btn:hover { background: rgba(167,139,250,0.25); }
|
.claude-btn:hover { background: rgba(167,139,250,0.25); }
|
||||||
|
|
||||||
|
/* マイクボタン */
|
||||||
|
.mic-btn {
|
||||||
|
width: 38px; height: 38px; border-radius: 10px; border: none;
|
||||||
|
background: rgba(255,255,255,0.05); color: rgba(255,255,255,0.35); cursor: pointer;
|
||||||
|
display: none; align-items: center; justify-content: center;
|
||||||
|
flex-shrink: 0; transition: background 0.15s, color 0.15s;
|
||||||
|
}
|
||||||
|
.mic-btn.available { display: flex; }
|
||||||
|
.mic-btn:hover { background: rgba(255,255,255,0.1); color: #F3F4F6; }
|
||||||
|
.mic-btn.listening {
|
||||||
|
background: rgba(239,68,68,0.15); color: #F87171;
|
||||||
|
animation: mic-pulse 1s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
@keyframes mic-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.55; } }
|
||||||
|
|
||||||
|
/* 設定パネル内セッション表示 */
|
||||||
|
.session-info-row {
|
||||||
|
display: flex; align-items: center; gap: 8px; margin-top: 8px;
|
||||||
|
font-size: 11px; color: rgba(255,255,255,0.35); font-family: monospace;
|
||||||
|
background: rgba(255,255,255,0.04); border-radius: 8px; padding: 8px 10px;
|
||||||
|
}
|
||||||
|
.session-info-row.hidden { display: none; }
|
||||||
|
|
||||||
/* ── Terminal ── */
|
/* ── Terminal ── */
|
||||||
#terminal-container {
|
#terminal-container {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
@ -98,8 +113,8 @@
|
||||||
padding: 12px 12px 0;
|
padding: 12px 12px 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
background:
|
background:
|
||||||
radial-gradient(ellipse at 15% 60%, rgba(34,211,238,0.07) 0%, transparent 55%),
|
radial-gradient(ellipse at 15% 60%, rgba(34,211,238,0.14) 0%, transparent 55%),
|
||||||
radial-gradient(ellipse at 85% 25%, rgba(167,139,250,0.07) 0%, transparent 55%),
|
radial-gradient(ellipse at 85% 25%, rgba(167,139,250,0.14) 0%, transparent 55%),
|
||||||
var(--dev-bg);
|
var(--dev-bg);
|
||||||
}
|
}
|
||||||
#terminal-container .xterm { height: 100%; }
|
#terminal-container .xterm { height: 100%; }
|
||||||
|
|
@ -173,7 +188,11 @@
|
||||||
</div>
|
</div>
|
||||||
<div style="margin-top:20px">
|
<div style="margin-top:20px">
|
||||||
<div class="settings-group-label">セッション</div>
|
<div class="settings-group-label">セッション</div>
|
||||||
<a href="/sessions.html" style="font-size:13px;color:var(--accent);text-decoration:none;display:flex;align-items:center;gap:6px;margin-top:8px">
|
<div class="session-info-row hidden" id="settingsSessionBadge">
|
||||||
|
<i data-lucide="terminal" style="width:12px;height:12px;stroke-width:1.75;color:var(--accent);flex-shrink:0"></i>
|
||||||
|
<span id="settingsSessionId">—</span>
|
||||||
|
</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">
|
||||||
<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>
|
||||||
|
|
@ -190,7 +209,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="header-right">
|
<div class="header-right">
|
||||||
<button class="claude-btn" id="claudeBtn" aria-label="Claude 開始">
|
<button class="claude-btn" id="claudeBtn" aria-label="Claude 開始">
|
||||||
<i data-lucide="bot" style="width:15px;height:15px;stroke-width:1.75"></i>
|
<i data-lucide="bot" style="width:20px;height:20px;stroke-width:1.75"></i>
|
||||||
</button>
|
</button>
|
||||||
<button class="icon-btn" id="settingsBtn" aria-label="設定" aria-expanded="false">
|
<button class="icon-btn" id="settingsBtn" aria-label="設定" aria-expanded="false">
|
||||||
<i data-lucide="settings" style="width:18px;height:18px;stroke-width:1.5"></i>
|
<i data-lucide="settings" style="width:18px;height:18px;stroke-width:1.5"></i>
|
||||||
|
|
@ -201,17 +220,18 @@
|
||||||
<div id="terminal-container"></div>
|
<div id="terminal-container"></div>
|
||||||
|
|
||||||
<div class="chat-bar">
|
<div class="chat-bar">
|
||||||
<span class="session-badge" id="sessionBadge"></span>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
class="chat-input"
|
class="chat-input"
|
||||||
id="chatInput"
|
id="chatInput"
|
||||||
placeholder="Claude に話しかける、またはコマンドを入力..."
|
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
autocorrect="off"
|
autocorrect="off"
|
||||||
autocapitalize="off"
|
autocapitalize="off"
|
||||||
spellcheck="false"
|
spellcheck="false"
|
||||||
>
|
>
|
||||||
|
<button class="mic-btn" id="micBtn" aria-label="音声入力">
|
||||||
|
<i data-lucide="mic" style="width:16px;height:16px;stroke-width:1.75"></i>
|
||||||
|
</button>
|
||||||
<button class="send-btn" id="sendBtn" disabled aria-label="送信">
|
<button class="send-btn" id="sendBtn" disabled aria-label="送信">
|
||||||
<i data-lucide="arrow-up" style="width:16px;height:16px;stroke-width:2.5"></i>
|
<i data-lucide="arrow-up" style="width:16px;height:16px;stroke-width:2.5"></i>
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -221,11 +241,13 @@
|
||||||
<script>
|
<script>
|
||||||
(function () {
|
(function () {
|
||||||
const statusBadge = document.getElementById('statusBadge');
|
const statusBadge = document.getElementById('statusBadge');
|
||||||
const sessionBadge = document.getElementById('sessionBadge');
|
const settingsSessionRow = document.getElementById('settingsSessionBadge');
|
||||||
|
const settingsSessionId = document.getElementById('settingsSessionId');
|
||||||
const container = document.getElementById('terminal-container');
|
const container = document.getElementById('terminal-container');
|
||||||
const chatInput = document.getElementById('chatInput');
|
const chatInput = document.getElementById('chatInput');
|
||||||
const sendBtn = document.getElementById('sendBtn');
|
const sendBtn = document.getElementById('sendBtn');
|
||||||
const claudeBtn = document.getElementById('claudeBtn');
|
const claudeBtn = document.getElementById('claudeBtn');
|
||||||
|
const micBtn = document.getElementById('micBtn');
|
||||||
|
|
||||||
// xterm.js
|
// xterm.js
|
||||||
const term = new Terminal({
|
const term = new Terminal({
|
||||||
|
|
@ -277,8 +299,8 @@
|
||||||
const msg = JSON.parse(e.data);
|
const msg = JSON.parse(e.data);
|
||||||
if (msg.type === 'output') term.write(msg.data);
|
if (msg.type === 'output') term.write(msg.data);
|
||||||
if (msg.type === 'session') {
|
if (msg.type === 'session') {
|
||||||
sessionBadge.textContent = msg.id;
|
settingsSessionId.textContent = msg.id;
|
||||||
sessionBadge.classList.add('visible');
|
settingsSessionRow.classList.remove('hidden');
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
};
|
};
|
||||||
|
|
@ -319,6 +341,40 @@
|
||||||
term.focus();
|
term.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 音声入力
|
||||||
|
const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
|
||||||
|
if (SR) {
|
||||||
|
micBtn.classList.add('available');
|
||||||
|
const recognition = new SR();
|
||||||
|
recognition.lang = 'ja-JP';
|
||||||
|
recognition.continuous = false;
|
||||||
|
recognition.interimResults = false;
|
||||||
|
let listening = false;
|
||||||
|
|
||||||
|
micBtn.addEventListener('click', () => {
|
||||||
|
if (listening) { recognition.stop(); return; }
|
||||||
|
recognition.start();
|
||||||
|
});
|
||||||
|
|
||||||
|
recognition.onstart = () => {
|
||||||
|
listening = true;
|
||||||
|
micBtn.classList.add('listening');
|
||||||
|
};
|
||||||
|
recognition.onend = () => {
|
||||||
|
listening = false;
|
||||||
|
micBtn.classList.remove('listening');
|
||||||
|
};
|
||||||
|
recognition.onresult = (e) => {
|
||||||
|
const transcript = e.results[0][0].transcript;
|
||||||
|
chatInput.value = transcript;
|
||||||
|
chatInput.focus();
|
||||||
|
};
|
||||||
|
recognition.onerror = () => {
|
||||||
|
listening = false;
|
||||||
|
micBtn.classList.remove('listening');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Resize
|
// Resize
|
||||||
const ro = new ResizeObserver(() => {
|
const ro = new ResizeObserver(() => {
|
||||||
fitAddon.fit();
|
fitAddon.fit();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue