Kanji 777 Trainer
by Bret Lowrey
HTML
<body>
<div class="content" id="content-display">
<div class="kanji" id="kanji-display"></div>
<div class="caption" id="caption-display"></div>
</div>
<div class="search-container">
<input
type="text"
id="search-box"
class="search-box"
placeholder="Search Kanji"
/>
<button class="kanji-button" onclick="searchKanji()">Search</button>
<button class="kanji-button" onclick="displayRandomKanji()">Random</button>
</div>
<div class="history" id="history-display"></div>
</body>
CSS
body {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 90vh;
margin: 5px;
font-family: Arial, sans-serif;
background-color: #f0f0f0;
}
.kanji {
font-size: 15vw;
text-align: center;
}
.caption {
font-size: 1rem;
text-align: center;
margin-top: 5px;
max-width: 90vw;
}
.content {
border: 10px solid black;
border-radius: 20px; /* Rounded corners */
padding: 5vh;
background-color: white; /* Background color for better contrast */
min-width: 40vw;
min-height: 20vh;
max-width: 95vw;
max-height: fit-content;
}
.history {
/* color: #f0f0f0; */
color: #a9a9a9;
font-size: 0.5em;
margin-top: 20px;
}
.search-container {
margin-top: 20px;
display: flex;
justify-content: center;
align-items: center;
}
.search-box {
padding: 10px;
font-size: 1rem;
width: 200px;
border: 2px solid #000;
border-radius: 5px;
}
.kanji-button {
padding: 10px;
font-size: 1rem;
margin-left: 10px;
cursor: pointer;
background-color: #000;
color: #fff;
border: none;
border-radius: 5px;
}
@keyframes jiggle {
0% {
transform: translateX(0);
}
25% {
transform: translateX(-5px);
}
50% {
transform: translateX(5px);
}
75% {
transform: translateX(-5px);
}
100% {
transform: translateX(0);
}
}
.jiggle {
animation: jiggle 0.3s ease;
}
JavaScript
const captionDisplay = document.getElementById("caption-display")
const kanjiDisplay = document.getElementById("kanji-display")
const historyDisplay = document.getElementById("history-display")
const contentDisplay = document.getElementById("content-display")
const searchBox = document.getElementById("search-box")
const kanji = kanjiDictionary()
const kanjiData = {}
for (const k of kanji) {
kanjiData[k.kanji] = k
}
const history = []
function displayKanji(kanjiInfo) {
const { kanji, meanings, hiragana, romanji } = kanjiInfo
captionDisplay.innerHTML = "<div>Click to display</div>"
kanjiDisplay.textContent = kanji
contentDisplay.addEventListener("click", function (event) {
event.stopPropagation()
captionDisplay.innerHTML = `
<div>
<span><b>Meanings</b>: <i>${meanings}</i> | </span>
<span><b>Hiragana:</b> <i>${hiragana}</i> | </span>
<span><b>Romanji:</b> <i>${romanji}</i></span>
</div>
`.trim()
})
history.push(kanjiInfo.kanji)
historyDisplay.innerHTML = `${history.join(", ")}`
}
function displayRandomKanji() {
const keys = Object.keys(kanjiData)
const randomKey = keys[Math.floor(Math.random() * keys.length)]
displayKanji(kanjiData[randomKey])
}
function findKanji(kanjiData, query) {
if (kanjiData[query]) {
return kanjiData[query]
}
for (const entry of Object.values(kanjiData)) {
for (const meaning of entry.meanings) {
if (meaning.startsWith(query.toLowerCase())) {
return entry
}
}
if (entry.hiragana === query) {
return entry
}
if (entry.romanji === query) {
return entry
}
}
return undefined
}
function searchKanji() {
const searchQuery = searchBox.value.trim()
const result = findKanji(kanjiData, searchQuery)
if (result) {
displayKanji(result)
} else {
// Add jiggle effect on not found
searchBox.classList.add("jiggle")
setTimeout(() =>...