File size: 11,942 Bytes
86572fe 5b4aadb ae84176 5b4aadb 86572fe ae84176 86572fe ae84176 86572fe ae84176 86572fe ae84176 5b4aadb ae84176 86572fe 5b4aadb 86572fe 5b4aadb 86572fe 5b4aadb 86572fe 5b4aadb 86572fe 5b4aadb 86572fe 5b4aadb 86572fe 5b4aadb ea93290 d7fe134 ea93290 d7fe134 ea93290 d7fe134 ea93290 d7fe134 ea93290 d7fe134 ea93290 d7fe134 5b4aadb d7fe134 5b4aadb d7fe134 86572fe |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
document.addEventListener('DOMContentLoaded', () => {
// Initialize app
createSnowflakes();
initializeStory();
setupNavigation();
// Event listeners
document.getElementById('continue-story')?.addEventListener('click', continueStory);
document.getElementById('ask-question')?.addEventListener('click', askQuestion);
// Location buttons
document.querySelectorAll('.location-btn').forEach(btn => {
btn.addEventListener('click', () => {
const location = btn.dataset.location;
showLocation(location);
});
});
// Back buttons
document.querySelectorAll('[data-back]').forEach(btn => {
btn.addEventListener('click', showHomeView);
});
});
function setupNavigation() {
// Handle bottom nav clicks
document.querySelectorAll('.nav-btn').forEach(btn => {
btn.addEventListener('click', () => {
const view = btn.dataset.view;
showView(view);
// Update active state
document.querySelectorAll('.nav-btn').forEach(navBtn => {
navBtn.classList.remove('active');
});
btn.classList.add('active');
});
});
}
function showView(viewName) {
// Hide all views
document.querySelectorAll('.view').forEach(view => {
view.classList.add('hidden');
view.classList.remove('active');
});
// Show selected view
const view = document.getElementById(`${viewName}-view`);
if (view) {
view.classList.remove('hidden');
view.classList.add('active');
}
}
function showHomeView() {
showView('home');
document.querySelector('[data-view="home"]').classList.add('active');
}
function showLocation(location) {
showView(location);
}
function initializeStory() {
const currentDay = 1;
document.getElementById('current-day').textContent = currentDay;
const chapterTitles = [
"Chapter 1: The Arrival",
"Chapter 2: The Baker's Secret",
"Chapter 3: Market Mystery",
"Chapter 4: Getting Around",
"Chapter 5: Hotel Check-in",
"Chapter 6: Café Culture",
"Chapter 7: Weekly Review",
"Chapter 8: Grocery Shopping",
"Chapter 9: Post Office Visit",
"Chapter 10: Doctor's Visit",
"Chapter 11: Public Transport",
"Chapter 12: Restaurant Night",
"Chapter 13: Shopping Spree",
"Chapter 14: Weekly Review",
"Chapter 15: Carol Singing",
"Chapter 16: Tree Decorating",
"Chapter 17: Gift Wrapping",
"Chapter 18: Winter Sports",
"Chapter 19: Holiday Cooking",
"Chapter 20: Town Celebration",
"Chapter 21: Weekly Review",
"Chapter 22: Storytelling",
"Chapter 23: Local Legends",
"Chapter 24: Christmas Eve",
"Chapter 25: Farewell"
];
if (document.getElementById('chapter-title')) {
document.getElementById('chapter-title').textContent = chapterTitles[currentDay - 1] || "Chapter 1: The Arrival";
}
}
function generateCalendar() {
const calendarDays = document.getElementById('calendar-days');
if (!calendarDays) return;
calendarDays.innerHTML = '';
for (let day = 1; day <= 25; day++) {
const dayElement = document.createElement('div');
dayElement.className = `text-center p-3 rounded-lg cursor-pointer transition ${day === 1 ? 'bg-primary text-white' : day <= 1 ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-400'}`;
dayElement.innerHTML = `
<div class="font-bold text-lg">${day}</div>
<div class="text-xs">${day === 1 ? 'Today' : 'Day ' + day}</div>
`;
if (day <= 1) {
dayElement.addEventListener('click', () => {
alert(`You're on Day ${day}! ${day === 1 ? 'Continue your adventure.' : 'This day will unlock soon.'}`);
});
}
calendarDays.appendChild(dayElement);
}
}
function loadCharacters() {
const characterContainer = document.getElementById('character-profiles');
if (!characterContainer) return;
const characters = [
{
name: "Pierre",
role: "The Baker",
description: "Friendly local who loves teaching phrases about food.",
img: "http://static.photos/people/200x200/10"
},
{
name: "Claire",
role: "Market Vendor",
description: "Sells Christmas ornaments and knows all the holiday vocabulary.",
img: "http://static.photos/people/200x200/11"
},
{
name: "Luc",
role: "Town Musician",
description: "Teaches French through Christmas carols.",
img: "http://static.photos/people/200x200/12"
},
{
name: "Monsieur Lefevre",
role: "Mayor",
description: "Speaks formal French - great for learning polite expressions.",
img: "http://static.photos/people/200x200/13"
}
];
characterContainer.innerHTML = '';
characters.forEach(char => {
const charElement = document.createElement('div');
charElement.className = 'text-center';
charElement.innerHTML = `
<img src="${char.img}" alt="${char.name}" class="w-20 h-20 rounded-full mx-auto mb-3 border-4 border-white shadow">
<h4 class="font-bold text-primary">${char.name}</h4>
<p class="text-sm text-secondary font-medium">${char.role}</p>
<p class="text-xs text-gray-600 mt-1">${char.description}</p>
`;
characterContainer.appendChild(charElement);
});
}
function continueStory() {
const storyChat = document.getElementById('story-chat');
if (!storyChat) return;
const storySteps = [
{ speaker: "ai", text: "You walk toward the town square and see a beautiful Christmas market. A vendor calls out: 'Venez voir nos décorations!' (Come see our decorations!)", character: "Market Vendor" },
{ speaker: "user", text: "Je voudrais acheter une décoration. (I would like to buy a decoration.)", character: "You" },
{ speaker: "ai", text: "'Très bien! Celle-ci coûte cinq euros,' she says with a smile. You've just completed your first transaction in French!", character: "Claire" }
];
storySteps.forEach((step, index) => {
setTimeout(() => {
const messageDiv = document.createElement('div');
messageDiv.className = 'flex items-start space-x-3 mb-4';
if (step.speaker === 'user') {
messageDiv.innerHTML = `
<div class="bg-primary rounded-full p-2">
<i data-feather="user" class="text-white"></i>
</div>
<div class="bg-gray-100 rounded-2xl px-4 py-2 max-w-xs">
<p class="font-medium">${step.text}</p>
<p class="text-xs text-gray-500 mt-1">${step.character}</p>
</div>
`;
} else {
messageDiv.innerHTML = `
<div class="bg-secondary rounded-full p-2">
<i data-feather="user-check" class="text-white"></i>
</div>
<div class="bg-blue-50 rounded-2xl px-4 py-2 max-w-xs">
<p class="font-medium">${step.text}</p>
<p class="text-xs text-gray-500 mt-1">${step.character}</p>
</div>
`;
}
storyChat.appendChild(messageDiv);
storyChat.scrollTop = storyChat.scrollHeight;
feather.replace();
}, (index + 1) * 1500);
});
// Update mission text after story progresses
setTimeout(() => {
const missionElement = document.getElementById('daily-mission');
if (missionElement) {
missionElement.textContent = "Visit the Christmas market and buy a decoration using French.";
}
}, 5000);
}
function askQuestion() {
const storyChat = document.getElementById('story-chat');
if (!storyChat) return;
const questionDiv = document.createElement('div');
questionDiv.className = 'flex items-start space-x-3 mb-4';
questionDiv.innerHTML = `
<div class="bg-accent rounded-full p-2">
<i data-feather="help-circle" class="text-white"></i>
</div>
<div class="bg-yellow-50 rounded-2xl px-4 py-2 max-w-xs">
<p class="font-medium">How do I say 'How much does this cost?' in French?</p>
<p class="text-xs text-gray-500 mt-1">You asked</p>
</div>
`;
storyChat.appendChild(questionDiv);
setTimeout(() => {
const answerDiv = document.createElement('div');
answerDiv.className = 'flex items-start space-x-3 mb-4';
answerDiv.innerHTML = `
<div class="bg-secondary rounded-full p-2">
<i data-feather="user-check" class="text-white"></i>
</div>
<div class="bg-green-50 rounded-2xl px-4 py-2 max-w-xs">
<p class="font-medium">You say: 'Combien ça coûte?' (kɔm.bjɛ̃ sa kut). Try repeating it!</p>
<p class="text-xs text-gray-500 mt-1">Pierre helps</p>
</div>
`;
storyChat.appendChild(answerDiv);
storyChat.scrollTop = storyChat.scrollHeight;
feather.replace();
}, 1000);
}
function createSnowflakes() {
const snowContainer = document.getElementById('snow-overlay');
if (!snowContainer) return;
for (let i = 0; i < 100; i++) {
const snowflake = document.createElement('div');
snowflake.className = 'snowflake';
snowflake.innerHTML = '❄';
snowflake.style.left = Math.random() * 100 + 'vw';
snowflake.style.top = -20 + 'px';
snowflake.style.fontSize = (Math.random() * 10 + 8) + 'px';
snowflake.style.opacity = Math.random();
snowflake.style.animationDuration = `${Math.random() * 5 + 5}s, ${Math.random() * 5 + 5}s`;
snowflake.style.animationDelay = `${Math.random() * 5}s`;
snowContainer.appendChild(snowflake);
}
}
function visitLocation(location) {
const locations = {
bakery: {
title: "Pierre's Bakery",
description: "The sweet smell of fresh pastries fills the air as you enter the cozy bakery. Pierre greets you warmly."
},
market: {
title: "Christmas Market",
description: "Colorful stalls line the square, selling handmade ornaments and holiday treats. Claire waves as you approach."
},
hotel: {
title: "Town Hotel",
description: "The grand hotel entrance welcomes you with twinkling lights. The concierge stands ready to assist."
}
};
const storyPanel = document.querySelector('.story-panel');
if (storyPanel) {
storyPanel.querySelector('#chapter-title').textContent = locations[location].title;
storyPanel.querySelector('#story-text').textContent = locations[location].description;
}
}
});
|