dramaling-app/sop/archive/20250911035850_dialogue.html

1035 lines
34 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>對話練習 - Drama Ling</title>
<link rel="stylesheet" href="../assets/style.css">
<style>
.dialogue-layout {
min-height: 100vh;
background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);
display: flex;
}
/* 側邊欄 */
.sidebar {
width: 280px;
background: var(--bg-card);
border-right: 1px solid var(--divider);
display: flex;
flex-direction: column;
position: fixed;
height: 100vh;
z-index: 100;
}
.sidebar-header {
padding: var(--space-6);
border-bottom: 1px solid var(--divider);
}
.logo {
display: flex;
align-items: center;
gap: var(--space-3);
color: var(--text-primary);
text-decoration: none;
font-size: var(--text-xl);
font-weight: 700;
}
.sidebar-nav {
flex: 1;
padding: var(--space-6) 0;
overflow-y: auto;
}
.nav-section {
margin-bottom: var(--space-6);
}
.nav-section-title {
font-size: var(--text-xs);
font-weight: 600;
color: var(--text-tertiary);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: var(--space-3);
padding: 0 var(--space-6);
}
.nav-item {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3) var(--space-6);
color: var(--text-secondary);
text-decoration: none;
font-size: var(--text-sm);
font-weight: 500;
transition: all 0.2s ease;
border-left: 3px solid transparent;
}
.nav-item:hover {
background: rgba(0, 229, 204, 0.1);
color: var(--primary-teal);
}
.nav-item.active {
background: rgba(0, 229, 204, 0.15);
color: var(--primary-teal);
border-left-color: var(--primary-teal);
}
.nav-icon {
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
}
.sidebar-footer {
padding: var(--space-6);
border-top: 1px solid var(--divider);
}
.user-profile {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-3);
background: var(--bg-secondary);
border-radius: var(--radius-lg);
}
.user-avatar {
width: 40px;
height: 40px;
background: var(--primary-teal);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
color: white;
}
.user-info {
flex: 1;
}
.user-name {
font-size: var(--text-sm);
font-weight: 600;
color: var(--text-primary);
}
.user-level {
font-size: var(--text-xs);
color: var(--text-secondary);
}
/* 主內容區 */
.main-content {
flex: 1;
margin-left: 280px;
padding: var(--space-6);
overflow-y: auto;
}
.page-header {
margin-bottom: var(--space-8);
}
.header-section {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--space-6);
}
.header-text h1 {
font-size: var(--text-3xl);
font-weight: 700;
color: var(--text-primary);
margin-bottom: var(--space-2);
}
.header-text p {
font-size: var(--text-lg);
color: var(--text-secondary);
}
.start-dialogue-btn {
background: var(--primary-teal);
color: white;
border: none;
padding: var(--space-4) var(--space-6);
border-radius: var(--radius-lg);
font-size: var(--text-base);
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}
.start-dialogue-btn:hover {
background: #00b8a0;
transform: translateY(-2px);
}
/* 場景選擇器 */
.scenario-selector {
margin-bottom: var(--space-8);
}
.scenario-title {
font-size: var(--text-xl);
font-weight: 600;
color: var(--text-primary);
margin-bottom: var(--space-4);
}
.scenario-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: var(--space-4);
}
.scenario-card {
background: var(--bg-card);
border: 2px solid var(--divider);
border-radius: var(--radius-xl);
padding: var(--space-6);
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.scenario-card:hover {
border-color: var(--primary-teal);
transform: translateY(-2px);
box-shadow: var(--shadow-lg);
}
.scenario-card.active {
border-color: var(--primary-teal);
background: rgba(0, 229, 204, 0.1);
}
.scenario-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 4px;
background: linear-gradient(90deg, var(--primary-teal), var(--secondary-purple));
}
.scenario-icon {
font-size: var(--text-4xl);
margin-bottom: var(--space-3);
display: block;
}
.scenario-name {
font-size: var(--text-lg);
font-weight: 600;
color: var(--text-primary);
margin-bottom: var(--space-2);
}
.scenario-description {
font-size: var(--text-sm);
color: var(--text-secondary);
margin-bottom: var(--space-4);
line-height: 1.5;
}
.scenario-meta {
display: flex;
justify-content: space-between;
align-items: center;
font-size: var(--text-xs);
color: var(--text-tertiary);
}
.scenario-level {
background: var(--bg-secondary);
padding: var(--space-1) var(--space-2);
border-radius: var(--radius-sm);
}
/* 對話區域 */
.dialogue-section {
background: var(--bg-card);
border: 1px solid var(--divider);
border-radius: var(--radius-xl);
margin-bottom: var(--space-8);
display: flex;
flex-direction: column;
height: 600px;
}
.dialogue-header {
padding: var(--space-6);
border-bottom: 1px solid var(--divider);
display: flex;
justify-content: space-between;
align-items: center;
}
.dialogue-info {
display: flex;
align-items: center;
gap: var(--space-3);
}
.dialogue-avatar {
width: 48px;
height: 48px;
background: var(--primary-teal);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: var(--text-xl);
color: white;
}
.dialogue-meta h3 {
font-size: var(--text-lg);
font-weight: 600;
color: var(--text-primary);
margin-bottom: var(--space-1);
}
.dialogue-meta p {
font-size: var(--text-sm);
color: var(--text-secondary);
}
.dialogue-controls {
display: flex;
gap: var(--space-3);
}
.control-btn {
padding: var(--space-2) var(--space-4);
border: 1px solid var(--divider);
border-radius: var(--radius-md);
background: var(--bg-card);
color: var(--text-secondary);
font-size: var(--text-sm);
cursor: pointer;
transition: all 0.2s ease;
}
.control-btn:hover {
border-color: var(--primary-teal);
color: var(--primary-teal);
}
.control-btn.active {
background: var(--primary-teal);
border-color: var(--primary-teal);
color: white;
}
.dialogue-messages {
flex: 1;
padding: var(--space-6);
overflow-y: auto;
display: flex;
flex-direction: column;
gap: var(--space-4);
}
.message {
max-width: 70%;
display: flex;
align-items: flex-start;
gap: var(--space-3);
}
.message.user {
align-self: flex-end;
flex-direction: row-reverse;
}
.message-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: var(--text-sm);
font-weight: 600;
flex-shrink: 0;
}
.message-avatar.ai {
background: var(--primary-teal);
color: white;
}
.message-avatar.user {
background: var(--secondary-purple);
color: white;
}
.message-bubble {
padding: var(--space-4);
border-radius: var(--radius-lg);
position: relative;
}
.message.ai .message-bubble {
background: var(--bg-secondary);
color: var(--text-primary);
}
.message.user .message-bubble {
background: var(--primary-teal);
color: white;
}
.message-text {
margin-bottom: var(--space-2);
}
.message-translation {
font-size: var(--text-sm);
opacity: 0.8;
font-style: italic;
}
.message-actions {
display: flex;
gap: var(--space-2);
margin-top: var(--space-2);
}
.message-btn {
background: none;
border: none;
color: inherit;
font-size: var(--text-sm);
cursor: pointer;
opacity: 0.7;
transition: all 0.2s ease;
}
.message-btn:hover {
opacity: 1;
}
.dialogue-input {
padding: var(--space-6);
border-top: 1px solid var(--divider);
}
.input-section {
display: flex;
gap: var(--space-3);
align-items: flex-end;
}
.input-group {
flex: 1;
display: flex;
flex-direction: column;
gap: var(--space-2);
}
.input-controls {
display: flex;
gap: var(--space-2);
align-items: center;
}
.input-textarea {
width: 100%;
min-height: 60px;
padding: var(--space-3);
border: 2px solid var(--divider);
border-radius: var(--radius-lg);
background: var(--bg-secondary);
color: var(--text-primary);
font-size: var(--text-base);
font-family: inherit;
resize: vertical;
transition: all 0.2s ease;
}
.input-textarea:focus {
outline: none;
border-color: var(--primary-teal);
background: var(--bg-card);
}
.voice-btn, .send-btn {
padding: var(--space-3);
border: 2px solid var(--divider);
border-radius: var(--radius-lg);
background: var(--bg-card);
color: var(--text-primary);
font-size: var(--text-lg);
cursor: pointer;
transition: all 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
}
.voice-btn:hover, .send-btn:hover {
border-color: var(--primary-teal);
background: rgba(0, 229, 204, 0.1);
}
.send-btn {
background: var(--primary-teal);
border-color: var(--primary-teal);
color: white;
}
.send-btn:hover {
background: #00b8a0;
}
.input-hint {
font-size: var(--text-xs);
color: var(--text-tertiary);
display: flex;
justify-content: space-between;
align-items: center;
}
.suggested-responses {
display: flex;
gap: var(--space-2);
flex-wrap: wrap;
margin-top: var(--space-3);
}
.suggestion-btn {
background: var(--bg-secondary);
border: 1px solid var(--divider);
border-radius: var(--radius-md);
padding: var(--space-2) var(--space-3);
font-size: var(--text-sm);
color: var(--text-secondary);
cursor: pointer;
transition: all 0.2s ease;
}
.suggestion-btn:hover {
background: var(--primary-teal);
border-color: var(--primary-teal);
color: white;
}
/* 響應式設計 */
@media (max-width: 1024px) {
.sidebar {
transform: translateX(-100%);
transition: transform 0.3s ease;
}
.sidebar.open {
transform: translateX(0);
}
.main-content {
margin-left: 0;
}
.scenario-grid {
grid-template-columns: 1fr;
}
}
@media (max-width: 768px) {
.main-content {
padding: var(--space-4);
}
.header-section {
flex-direction: column;
align-items: flex-start;
gap: var(--space-4);
}
.dialogue-section {
height: 500px;
}
.message {
max-width: 85%;
}
.input-section {
flex-direction: column;
gap: var(--space-3);
}
.input-controls {
align-self: stretch;
justify-content: space-between;
}
}
.prototype-note {
position: fixed;
top: var(--space-4);
right: var(--space-4);
background: var(--success-green);
color: var(--bg-dark);
padding: var(--space-2) var(--space-4);
border-radius: var(--radius-md);
font-size: var(--text-xs);
font-weight: 600;
z-index: 1000;
box-shadow: var(--shadow-md);
}
.mobile-menu-btn {
display: none;
position: fixed;
top: var(--space-4);
left: var(--space-4);
width: 48px;
height: 48px;
background: var(--primary-teal);
border: none;
border-radius: var(--radius-lg);
color: white;
font-size: var(--text-lg);
z-index: 101;
cursor: pointer;
}
@media (max-width: 1024px) {
.mobile-menu-btn {
display: flex;
align-items: center;
justify-content: center;
}
}
</style>
</head>
<body>
<div class="prototype-note">
💬 HTML 原型 - 對話練習
</div>
<button class="mobile-menu-btn" id="mobileMenuBtn"></button>
<div class="dialogue-layout">
<!-- 側邊欄 -->
<aside class="sidebar" id="sidebar">
<div class="sidebar-header">
<a href="dashboard.html" class="logo">
🎭 Drama Ling
</a>
</div>
<nav class="sidebar-nav">
<div class="nav-section">
<div class="nav-section-title">主要功能</div>
<a href="dashboard.html" class="nav-item">
<span class="nav-icon">📊</span>
學習儀表板
</a>
<a href="vocabulary.html" class="nav-item">
<span class="nav-icon">📚</span>
詞彙學習
</a>
<a href="#" class="nav-item active">
<span class="nav-icon">💬</span>
對話練習
</a>
<a href="roleplay.html" class="nav-item">
<span class="nav-icon">🎭</span>
角色扮演
</a>
<a href="pronunciation.html" class="nav-item">
<span class="nav-icon">🎵</span>
發音練習
</a>
</div>
<div class="nav-section">
<div class="nav-section-title">個人管理</div>
<a href="profile.html" class="nav-item">
<span class="nav-icon">👤</span>
個人檔案
</a>
<a href="progress.html" class="nav-item">
<span class="nav-icon">📈</span>
學習進度
</a>
<a href="settings.html" class="nav-item">
<span class="nav-icon">⚙️</span>
設定
</a>
</div>
<div class="nav-section">
<div class="nav-section-title">訂閱服務</div>
<a href="subscription.html" class="nav-item">
<span class="nav-icon">💎</span>
訂閱管理
</a>
</div>
</nav>
<div class="sidebar-footer">
<div class="user-profile">
<div class="user-avatar"></div>
<div class="user-info">
<div class="user-name">張小明</div>
<div class="user-level">Level 12</div>
</div>
</div>
</div>
</aside>
<!-- 主內容區 -->
<main class="main-content">
<div class="page-header">
<div class="header-section">
<div class="header-text">
<h1>AI 對話練習</h1>
<p>與 AI 導師進行真實情境對話,提升口語表達能力</p>
</div>
<button class="start-dialogue-btn" id="startDialogueBtn">
🚀 開始新對話
</button>
</div>
<!-- 場景選擇器 -->
<div class="scenario-selector">
<h2 class="scenario-title">選擇對話場景</h2>
<div class="scenario-grid">
<div class="scenario-card active" data-scenario="coffee">
<span class="scenario-icon"></span>
<h3 class="scenario-name">咖啡廳點餐</h3>
<p class="scenario-description">學習在咖啡廳點餐、詢問價格、選擇座位等日常對話</p>
<div class="scenario-meta">
<span class="scenario-level">Level 2</span>
<span>15-20分鐘</span>
</div>
</div>
<div class="scenario-card" data-scenario="office">
<span class="scenario-icon">🏢</span>
<h3 class="scenario-name">職場會議</h3>
<p class="scenario-description">練習商務會議中的表達、提案、討論和決策對話</p>
<div class="scenario-meta">
<span class="scenario-level">Level 4</span>
<span>25-30分鐘</span>
</div>
</div>
<div class="scenario-card" data-scenario="shopping">
<span class="scenario-icon">🛍️</span>
<h3 class="scenario-name">購物中心</h3>
<p class="scenario-description">掌握購物時的詢價、比較、討價還價等實用對話</p>
<div class="scenario-meta">
<span class="scenario-level">Level 3</span>
<span>20-25分鐘</span>
</div>
</div>
<div class="scenario-card" data-scenario="travel">
<span class="scenario-icon">✈️</span>
<h3 class="scenario-name">機場旅行</h3>
<p class="scenario-description">學習機場check-in、安檢、登機等旅遊必備對話</p>
<div class="scenario-meta">
<span class="scenario-level">Level 3</span>
<span>20-25分鐘</span>
</div>
</div>
</div>
</div>
</div>
<!-- 對話區域 -->
<div class="dialogue-section">
<div class="dialogue-header">
<div class="dialogue-info">
<div class="dialogue-avatar"></div>
<div class="dialogue-meta">
<h3>咖啡廳點餐對話</h3>
<p>與 AI 咖啡師練習點餐對話</p>
</div>
</div>
<div class="dialogue-controls">
<button class="control-btn active" id="translationBtn">翻譯</button>
<button class="control-btn" id="hintBtn">提示</button>
<button class="control-btn" id="settingsBtn">設定</button>
</div>
</div>
<div class="dialogue-messages" id="messagesContainer">
<div class="message ai">
<div class="message-avatar ai">AI</div>
<div class="message-bubble">
<div class="message-text">
Hello! Welcome to our coffee shop. What can I get for you today?
</div>
<div class="message-translation">
您好!歡迎光臨我們的咖啡店。請問您今天想要什麼?
</div>
<div class="message-actions">
<button class="message-btn">🔊</button>
<button class="message-btn">📋</button>
</div>
</div>
</div>
<div class="message user">
<div class="message-avatar user"></div>
<div class="message-bubble">
<div class="message-text">
I'd like a cappuccino, please.
</div>
<div class="message-translation">
我想要一杯卡布奇諾,謝謝。
</div>
</div>
</div>
<div class="message ai">
<div class="message-avatar ai">AI</div>
<div class="message-bubble">
<div class="message-text">
Great choice! Would you like that in regular or large size?
</div>
<div class="message-translation">
很好的選擇!您要中杯還是大杯的?
</div>
<div class="message-actions">
<button class="message-btn">🔊</button>
<button class="message-btn">📋</button>
</div>
</div>
</div>
</div>
<div class="dialogue-input">
<div class="input-section">
<div class="input-group">
<textarea
class="input-textarea"
id="messageInput"
placeholder="輸入您的回答..."
rows="2"
></textarea>
<div class="input-hint">
<span>按 Shift+Enter 換行Enter 發送</span>
<span id="charCount">0/500</span>
</div>
</div>
<div class="input-controls">
<button class="voice-btn" id="voiceBtn" title="語音輸入">🎙️</button>
<button class="send-btn" id="sendBtn" title="發送訊息">📤</button>
</div>
</div>
<div class="suggested-responses">
<button class="suggestion-btn">Regular size, please</button>
<button class="suggestion-btn">I'll take a large</button>
<button class="suggestion-btn">What's the price difference?</button>
<button class="suggestion-btn">Do you have soy milk?</button>
</div>
</div>
</div>
</main>
</div>
<script>
// 原型互動功能
document.addEventListener('DOMContentLoaded', function() {
// 行動版選單切換
const mobileMenuBtn = document.getElementById('mobileMenuBtn');
const sidebar = document.getElementById('sidebar');
mobileMenuBtn.addEventListener('click', function() {
sidebar.classList.toggle('open');
});
// 點擊外部關閉側邊欄
document.addEventListener('click', function(e) {
if (window.innerWidth <= 1024 &&
!sidebar.contains(e.target) &&
!mobileMenuBtn.contains(e.target)) {
sidebar.classList.remove('open');
}
});
// 場景選擇
document.querySelectorAll('.scenario-card').forEach(card => {
card.addEventListener('click', function() {
document.querySelectorAll('.scenario-card').forEach(c => c.classList.remove('active'));
this.classList.add('active');
const scenario = this.dataset.scenario;
const scenarioName = this.querySelector('.scenario-name').textContent;
// 更新對話標題
document.querySelector('.dialogue-meta h3').textContent = scenarioName + '對話';
document.querySelector('.dialogue-avatar').textContent = this.querySelector('.scenario-icon').textContent;
alert(`切換到場景:${scenarioName}`);
});
});
// 開始對話按鈕
document.getElementById('startDialogueBtn').addEventListener('click', function() {
const activeScenario = document.querySelector('.scenario-card.active .scenario-name').textContent;
alert(`🚀 開始 ${activeScenario} 對話練習!`);
});
// 對話控制按鈕
document.getElementById('translationBtn').addEventListener('click', function() {
this.classList.toggle('active');
const translations = document.querySelectorAll('.message-translation');
translations.forEach(t => {
t.style.display = this.classList.contains('active') ? 'block' : 'none';
});
});
document.getElementById('hintBtn').addEventListener('click', function() {
alert('💡 提示:您可以說 "Regular size, please" 或 "I\'ll take a large"');
});
document.getElementById('settingsBtn').addEventListener('click', function() {
alert('⚙️ 對話設定\n- 語音速度:正常\n- 難度等級:中等\n- 自動翻譯:開啟');
});
// 訊息輸入
const messageInput = document.getElementById('messageInput');
const sendBtn = document.getElementById('sendBtn');
const charCount = document.getElementById('charCount');
messageInput.addEventListener('input', function() {
const length = this.value.length;
charCount.textContent = `${length}/500`;
if (length > 500) {
this.value = this.value.substring(0, 500);
charCount.textContent = '500/500';
}
});
messageInput.addEventListener('keydown', function(e) {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
sendBtn.addEventListener('click', sendMessage);
function sendMessage() {
const message = messageInput.value.trim();
if (!message) return;
// 添加用戶訊息到對話
const messagesContainer = document.getElementById('messagesContainer');
const userMessage = document.createElement('div');
userMessage.className = 'message user';
userMessage.innerHTML = `
<div class="message-avatar user">我</div>
<div class="message-bubble">
<div class="message-text">${message}</div>
<div class="message-translation">正在翻譯...</div>
</div>
`;
messagesContainer.appendChild(userMessage);
// 清空輸入框
messageInput.value = '';
charCount.textContent = '0/500';
// 模擬 AI 回應
setTimeout(() => {
const aiMessage = document.createElement('div');
aiMessage.className = 'message ai';
aiMessage.innerHTML = `
<div class="message-avatar ai">AI</div>
<div class="message-bubble">
<div class="message-text">That sounds perfect! Anything else you'd like to add to your order?</div>
<div class="message-translation">聽起來很棒!您還需要其他東西嗎?</div>
<div class="message-actions">
<button class="message-btn">🔊</button>
<button class="message-btn">📋</button>
</div>
</div>
`;
messagesContainer.appendChild(aiMessage);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}, 1500);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
// 語音輸入按鈕
document.getElementById('voiceBtn').addEventListener('click', function() {
alert('🎙️ 語音輸入功能(原型中模擬)');
messageInput.value = 'I\'d like to add a blueberry muffin, please.';
messageInput.dispatchEvent(new Event('input'));
});
// 建議回答按鈕
document.querySelectorAll('.suggestion-btn').forEach(btn => {
btn.addEventListener('click', function() {
messageInput.value = this.textContent;
messageInput.dispatchEvent(new Event('input'));
messageInput.focus();
});
});
// 訊息動作按鈕
document.addEventListener('click', function(e) {
if (e.target.classList.contains('message-btn')) {
const text = e.target.textContent;
if (text === '🔊') {
alert('播放語音');
} else if (text === '📋') {
alert('複製到剪貼板');
}
}
});
// 導航項目點擊
document.querySelectorAll('.nav-item').forEach(item => {
item.addEventListener('click', function(e) {
if (this.getAttribute('href') === '#') {
e.preventDefault();
}
});
});
console.log('💬 對話練習原型已載入完成');
});
// 響應式處理
window.addEventListener('resize', function() {
const sidebar = document.getElementById('sidebar');
if (window.innerWidth > 1024) {
sidebar.classList.remove('open');
}
});
</script>
</body>
</html>