Spaces:
Running
Running
| <html lang="ko"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>HUIUCL Database Final</title> | |
| <style> | |
| :root { --bg: #f4f1ea; --card: #ffffff; --accent: #8b7355; --text: #333; } | |
| body { font-family: sans-serif; background: var(--bg); color: var(--text); padding: 20px; } | |
| .container { max-width: 1200px; margin: 0 auto; } | |
| .search-box { width: 100%; padding: 15px; margin-bottom: 20px; border: 2px solid #ddd; border-radius: 8px; font-size: 1.1rem; } | |
| .table-wrapper { background: #fff; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.1); overflow: hidden; } | |
| table { width: 100%; border-collapse: collapse; table-layout: fixed; } | |
| th, td { padding: 15px; text-align: left; border-bottom: 1px solid #eee; word-break: break-all; } | |
| th { background: #f8f8f8; font-weight: bold; border-bottom: 2px solid #ddd; } | |
| .word-cell { font-weight: bold; color: var(--accent); width: 20%; font-size: 1.1rem; } | |
| .path-cell { font-size: 0.8rem; color: #999; width: 20%; } | |
| .usage-tag { background: #f0f0f0; padding: 4px 8px; border-radius: 4px; font-size: 0.8rem; color: #666; display: block; margin-top: 5px; } | |
| .meaning-item { margin-bottom: 4px; } | |
| .sub-row { background: #fafafa; font-size: 0.9rem; } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <input type="text" id="searchInput" class="search-box" placeholder="๋จ์ด, ๋ป, ๋ถ๋ฅ ๊ฒ์..." oninput="render()"> | |
| <div class="table-wrapper"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th style="width:20%">๋จ์ด (Word)</th> | |
| <th style="width:60%">์๋ฏธ ๋ฐ ์ฉ๋ฒ</th> | |
| <th style="width:20%">๋ถ๋ฅ</th> | |
| </tr> | |
| </thead> | |
| <tbody id="dictBody"></tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <script> | |
| let rawData = {}; | |
| window.onload = () => { | |
| fetch('Huiucl.json') | |
| .then(res => res.json()) | |
| .then(data => { | |
| rawData = data; | |
| render(); | |
| }); | |
| }; | |
| function render() { | |
| const query = document.getElementById('searchInput').value.toLowerCase(); | |
| const body = document.getElementById('dictBody'); | |
| body.innerHTML = ''; | |
| // ๋ชจ๋ ์นดํ ๊ณ ๋ฆฌ ์ํ (Settings ์ ์ธ) | |
| for (const cat in rawData) { | |
| if (cat === "Settings") continue; | |
| extract(rawData[cat], cat, query); | |
| } | |
| } | |
| function extract(obj, path, query) { | |
| if (path.includes("Grammar_Rules")) return; | |
| for (const key in obj) { | |
| const val = obj[key]; | |
| if (!val) continue; | |
| // 1. ๋ฌธ์์ด์ธ ๊ฒฝ์ฐ (๋จ์ ๋๋ช ์ฌ, ์ธ์ฌ๋ง ๋ฑ) | |
| if (typeof val === 'string') { | |
| if (isMatch(key, val, path, query)) { | |
| appendRow(key, val, "", "", path); | |
| } | |
| } | |
| // 2. ๊ฐ์ฒด์ธ ๊ฒฝ์ฐ (๋จ์ด ์ ๋ณด ํฌํจ) | |
| else if (typeof val === 'object') { | |
| // ์ด ๊ฐ์ฒด๊ฐ '๋จ์ด ์ ๋ณด'๋ฅผ ๋ด๊ณ ์๋์ง ํ์ธ | |
| const info = getWordInfo(val); | |
| if (info.hasData) { | |
| if (isMatch(key, info.ko + info.en + info.usage, path, query)) { | |
| appendRow(key, info.ko, info.en, info.usage, path); | |
| } | |
| // ํ์์ด ์ฒ๋ฆฌ | |
| if (val.derivations) { | |
| for (const dKey in val.derivations) { | |
| appendRow(dKey, val.derivations[dKey], "", "", path, true); | |
| } | |
| } | |
| // ์์ ๋ณํ ๋ฑ ํ์ ๋ฐ์ดํฐ๊ฐ ๋ ์๋ค๋ฉด ํ์ (๋จ, ๋ฐ์ดํฐ ํค๋ ์ ์ธ) | |
| for (const subKey in val) { | |
| if (!["meaning_ko", "meaning_en", "ko", "en", "definition", "usage", "note", "derivations"].includes(subKey)) { | |
| extract({ [subKey]: val[subKey] }, path + " > " + key, query); | |
| } | |
| } | |
| } else { | |
| // ๋จ์ด ๋ฐ์ดํฐ๊ฐ ์๋๋ฉด ๋ ๊น๊ฒ ํ์ | |
| extract(val, path + " > " + key, query); | |
| } | |
| } | |
| } | |
| } | |
| // ๊ฐ์ฒด ์์์ ํ๊ธ ๋ป, ์์ด ๋ป, ์ฌ์ฉ๋ฒ์ ๊ธ์ด๋ชจ์ผ๋ ํจ์ | |
| function getWordInfo(obj) { | |
| let info = { | |
| ko: obj.meaning_ko || obj.ko || obj.๋ป || obj.definition || "", | |
| en: obj.meaning_en || obj.en || "", | |
| usage: obj.usage || obj.note || "", | |
| hasData: false | |
| }; | |
| // ko๋ definition์ด ๋ ๊ฐ์ฒด์ธ ๊ฒฝ์ฐ (์๋ฌ ๋ฐฉ์ง) | |
| if (typeof info.ko === 'object') info.ko = info.ko.ko || info.ko.meaning_ko || JSON.stringify(info.ko); | |
| if (typeof info.en === 'object') info.en = info.en.en || info.en.meaning_en || ""; | |
| if (info.ko || info.en || info.usage) info.hasData = true; | |
| return info; | |
| } | |
| function isMatch(word, content, path, query) { | |
| const target = (word + content + path).toLowerCase(); | |
| return target.includes(query); | |
| } | |
| function appendRow(word, ko, en, usage, path, isSub) { | |
| const body = document.getElementById('dictBody'); | |
| const row = body.insertRow(); | |
| if (isSub) row.className = 'sub-row'; | |
| let meaningHtml = `<div class="meaning-item"><strong>${ko}</strong></div>`; | |
| if (en) meaningHtml += `<div class="meaning-item" style="color: #666;">${en}</div>`; | |
| if (usage) { | |
| // usage๊ฐ ๊ฐ์ฒด์ธ ๊ฒฝ์ฐ ๋์ | |
| const usageText = typeof usage === 'object' ? JSON.stringify(usage) : usage; | |
| meaningHtml += `<div class="usage-tag">โป ${usageText}</div>`; | |
| } | |
| row.innerHTML = ` | |
| <td class="word-cell">${isSub ? 'โ ' : ''}${word}</td> | |
| <td>${meaningHtml}</td> | |
| <td class="path-cell">${path}</td> | |
| `; | |
| } | |
| </script> | |
| </body> | |
| </html> |