| | |
| | |
| | const hskDatabase = { |
| | "你好": { level: 1, style: "Neutral", usage: "Common", meaning: "hello", pinyin: "nǐ hǎo" }, |
| | "学习": { level: 1, style: "Neutral", usage: "Common", meaning: "study, learn", pinyin: "xué xí" }, |
| | "谢谢": { level: 1, style: "Neutral", usage: "Common", meaning: "thank you", pinyin: "xiè xiè" }, |
| | "再见": { level: 1, style: "Neutral", usage: "Common", meaning: "goodbye", pinyin: "zài jiàn" }, |
| | "是": { level: 1, style: "Neutral", usage: "Common", meaning: "to be", pinyin: "shì" }, |
| | "不": { level: 1, style: "Neutral", usage: "Common", meaning: "no, not", pinyin: "bù" }, |
| | "我": { level: 1, style: "Neutral", usage: "Common", meaning: "I, me", pinyin: "wǒ" }, |
| | "你": { level: 1, style: "Neutral", usage: "Common", meaning: "you", pinyin: "nǐ" }, |
| | "好": { level: 1, style: "Neutral", usage: "Common", meaning: "good", pinyin: "hǎo" }, |
| | "人": { level: 1, style: "Neutral", usage: "Common", meaning: "person", pinyin: "rén" }, |
| | "冒险": { level: 4, style: "Neutral", usage: "Common", meaning: "adventure, take risks", pinyin: "mào xiǎn" }, |
| | "尴尬": { level: 5, style: "Neutral", usage: "Common", meaning: "embarrassed, awkward", pinyin: "gān gà" }, |
| | "牛逼": { level: "Not in HSK", style: "Informal", usage: "Common", meaning: "awesome, amazing", pinyin: "niú bī" }, |
| | "囧": { level: "Not in HSK", style: "Informal", usage: "Rare", meaning: "embarrassed, awkward", pinyin: "jiǒng" }, |
| | "饕餮": { level: "Not in HSK", style: "Formal", usage: "Rare", meaning: "gluttonous monster", pinyin: "tāo tiè" }, |
| | "耄耋": { level: "Not in HSK", style: "Formal", usage: "Rare", meaning: "very old age", pinyin: "mào dié" } |
| | }; |
| |
|
| | |
| | const API_ENDPOINTS = { |
| | analyze: '/api/analyze', |
| | batchAnalyze: '/api/batch-analyze', |
| | hskLevel: '/api/hsk/' |
| | }; |
| |
|
| | |
| | async function apiCall(endpoint, method = 'GET', data = null) { |
| | const options = { |
| | method: method, |
| | headers: { |
| | 'Content-Type': 'application/json', |
| | }, |
| | }; |
| | |
| | if (data) { |
| | options.body = JSON.stringify(data); |
| | } |
| | |
| | try { |
| | const response = await fetch(endpoint, options); |
| | if (!response.ok) { |
| | throw new Error(`HTTP error! status: ${response.status}`); |
| | } |
| | return await response.json(); |
| | } catch (error) { |
| | console.error('API call failed:', error); |
| | |
| | return fallbackAnalysis(data); |
| | } |
| | } |
| |
|
| | |
| | function fallbackAnalysis(data) { |
| | if (data.word) { |
| | return { |
| | word: data.word, |
| | ...(hskDatabase[data.word] || { |
| | level: "Not in HSK", |
| | style: "Neutral", |
| | usage: "Rare", |
| | meaning: "unknown meaning", |
| | pinyin: "unknown" |
| | } |
| | }; |
| | } else if (data.words) { |
| | return { |
| | results: data.words.map(word => ({ |
| | word: word, |
| | ...(hskDatabase[word] || { |
| | level: "Not in HSK", |
| | style: "Neutral", |
| | usage: "Rare", |
| | meaning: "unknown meaning", |
| | pinyin: "unknown" |
| | })) |
| | }; |
| | } |
| | return null; |
| | } |
| |
|
| | |
| | async function analyzeWord(word) { |
| | |
| | if (!isChinese(word)) { |
| | showError("Please enter a valid Chinese word."); |
| | return; |
| | } |
| | |
| | |
| | try { |
| | const response = await apiCall(API_ENDPOINTS.analyze, 'POST', { word: word }); |
| | displayResults(word, response); |
| | saveResults(word, response); |
| | } catch (error) { |
| | |
| | const wordData = hskDatabase[word] || { |
| | level: "Not in HSK", |
| | style: "Neutral", |
| | usage: "Rare", |
| | meaning: "unknown meaning", |
| | pinyin: "unknown" |
| | }; |
| | |
| | displayResults(word, wordData); |
| | saveResults(word, wordData); |
| | } |
| | } |
| | |
| | const wordForm = document.getElementById('wordForm'); |
| | const chineseWordInput = document.getElementById('chineseWord'); |
| | const resultsSection = document.getElementById('resultsSection'); |
| | const resultsDiv = document.getElementById('results'); |
| | const clearResultsBtn = document.getElementById('clearResults'); |
| |
|
| | |
| | document.addEventListener('DOMContentLoaded', function() { |
| | console.log('Hanzi Hunter initialized'); |
| | |
| | |
| | wordForm.addEventListener('submit', function(e) { |
| | e.preventDefault(); |
| | const word = chineseWordInput.value.trim(); |
| | |
| | if (word) { |
| | analyzeWord(word); |
| | } |
| | }); |
| | |
| | |
| | clearResultsBtn.addEventListener('click', function() { |
| | clearResults(); |
| | }); |
| | |
| | |
| | loadSavedResults(); |
| | }); |
| |
|
| | |
| | function analyzeWord(word) { |
| | |
| | if (!isChinese(word)) { |
| | showError("Please enter a valid Chinese word."); |
| | return; |
| | } |
| | |
| | |
| | const wordData = hskDatabase[word] || { |
| | level: "Not in HSK", |
| | style: "Neutral", |
| | usage: "Rare", |
| | meaning: "unknown meaning" |
| | }; |
| | |
| | |
| | displayResults(word, wordData); |
| | |
| | |
| | saveResults(word, wordData); |
| | } |
| |
|
| | |
| | function isChinese(str) { |
| | return /[\u4e00-\u9fff]/.test(str); |
| | } |
| |
|
| | |
| | function displayResults(word, data) { |
| | resultsSection.classList.remove('hidden'); |
| | resultsSection.classList.add('fade-in-up'); |
| | |
| | let warningText = ''; |
| | if (data.style === "Informal") { |
| | warningText = '<p class="text-yellow-400 text-sm mt-2"><i data-feather="alert-triangle" class="w-4 h-4 inline mr-1"></i>This is casual spoken Chinese.</p>'; |
| | } else if (data.style === "Formal" || data.usage === "Rare") { |
| | warningText = '<p class="text-orange-400 text-sm mt-2"><i data-feather="info" class="w-4 h-4 inline mr-1"></i>This word is mostly used in formal writing.</p>'; |
| | } |
| | |
| | resultsDiv.innerHTML = ` |
| | <div class="bg-gray-800 rounded-lg p-4 border-l-4 border-red-500"> |
| | <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
| | <div> |
| | <p class="text-gray-400 text-sm">Word</p> |
| | <p class="text-2xl font-bold">${word}</p> |
| | </div> |
| | <div> |
| | <p class="text-gray-400 text-sm">HSK Level</p> |
| | <p class="text-xl font-semibold">${data.level}</p> |
| | </div> |
| | <div> |
| | <p class="text-gray-400 text-sm">Style</p> |
| | <p class="text-xl font-semibold">${data.style}</p> |
| | </div> |
| | <div> |
| | <p class="text-gray-400 text-sm">Usage</p> |
| | <p class="text-xl font-semibold">${data.usage}</p> |
| | </div> |
| | <div> |
| | <p class="text-gray-400 text-sm">Meaning</p> |
| | <p class="text-xl font-semibold">${data.meaning}</p> |
| | </div> |
| | </div> |
| | ${warningText} |
| | </div> |
| | `; |
| | |
| | |
| | feather.replace(); |
| | |
| | |
| | resultsSection.scrollIntoView({ behavior: 'smooth', block: 'start' }); |
| | } |
| |
|
| | |
| | function showError(message) { |
| | resultsSection.classList.remove('hidden'); |
| | resultsDiv.innerHTML = ` |
| | <div class="bg-red-900 rounded-lg p-4 border-l-4 border-red-500"> |
| | <div class="flex items-center"> |
| | <i data-feather="alert-circle" class="w-6 h-6 text-red-300 mr-3"></i> |
| | <p class="text-red-300">${message}</p> |
| | </div> |
| | </div> |
| | `; |
| | feather.replace(); |
| | } |
| |
|
| | |
| | function clearResults() { |
| | resultsSection.classList.add('hidden'); |
| | chineseWordInput.value = ''; |
| | chineseWordInput.focus(); |
| | localStorage.removeItem('lastWordAnalysis'); |
| | } |
| |
|
| | |
| | function saveResults(word, data) { |
| | const analysis = { |
| | word: word, |
| | data: data, |
| | timestamp: new Date().toISOString() |
| | }; |
| | localStorage.setItem('lastWordAnalysis', JSON.stringify(analysis)); |
| | } |
| |
|
| | |
| | function loadSavedResults() { |
| | const saved = localStorage.getItem('lastWordAnalysis'); |
| | if (saved) { |
| | const analysis = JSON.parse(saved); |
| | displayResults(analysis.word, analysis.data); |
| | } |
| | } |
| |
|
| | |
| | function toggleTheme() { |
| | document.documentElement.classList.toggle('dark'); |
| | } |