Spaces:
Running
Running
| <html lang="ko"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>HUIUCL Online Archive</title> | |
| <style> | |
| :root { | |
| --bg-color: #f9f7f2; | |
| --card-bg: #ffffff; | |
| --primary-color: #5d5b54; | |
| --accent-color: #d4a373; | |
| --border-color: #e0ddd5; | |
| --variation-bg: #faf9f6; | |
| } | |
| body { | |
| font-family: 'Pretendard', sans-serif; | |
| background-color: var(--bg-color); | |
| color: var(--primary-color); | |
| margin: 0; padding: 0; line-height: 1.6; | |
| } | |
| /* ๋ค๋น๊ฒ์ด์ : ARCHIVE๋ฅผ ๋งจ ๋ค๋ก ์ด๋ */ | |
| nav { | |
| position: sticky; top: 0; background: rgba(249, 247, 242, 0.9); | |
| backdrop-filter: blur(10px); padding: 20px; text-align: center; | |
| border-bottom: 1px solid var(--border-color); z-index: 100; | |
| } | |
| nav a { margin: 0 15px; text-decoration: none; color: var(--primary-color); font-weight: 500; font-size: 0.9rem; transition: 0.2s; } | |
| nav a:hover { color: var(--accent-color); } | |
| header { text-align: center; padding: 60px 20px; } | |
| h1 { font-weight: 300; letter-spacing: 8px; color: var(--accent-color); margin: 0; } | |
| .sub-title { font-size: 0.9rem; color: #999; margin-top: 10px; } | |
| .container { max-width: 900px; margin: 0 auto; padding: 0 20px 100px; } | |
| section { display: none; } | |
| section.active { display: block; animation: fadeIn 0.5s; } | |
| @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } | |
| /* ์ฌ์ (DICTIONARY) ์คํ์ผ */ | |
| .search-container { margin-bottom: 30px; display: flex; gap: 10px; } | |
| input[type="text"] { flex: 1; padding: 12px 24px; border: 1px solid var(--border-color); border-radius: 30px; outline: none; } | |
| .filter-container { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-bottom: 30px; } | |
| button { background: var(--card-bg); border: 1px solid var(--border-color); padding: 6px 16px; cursor: pointer; border-radius: 20px; font-size: 0.85rem; } | |
| button.active { background: var(--accent-color); color: white; border-color: var(--accent-color); } | |
| .table-wrapper { background: var(--card-bg); border-radius: 15px; overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,0.05); } | |
| table { width: 100%; border-collapse: collapse; } | |
| th, td { padding: 15px 20px; text-align: left; border-bottom: 1px solid var(--bg-color); } | |
| th { background: #f1eee6; font-size: 0.9rem; color: #777; } | |
| .word-cell { font-weight: bold; color: var(--accent-color); } | |
| /* ๋ฌธ๋ฒ(GRAMMAR) ์คํ์ผ */ | |
| .card { background: var(--card-bg); padding: 40px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.03); margin-bottom: 20px; } | |
| /* ์์นด์ด๋ธ(ARCHIVE) ์คํ์ผ: ๋ฆฌ์คํธ & ๋ทฐ์ด */ | |
| .archive-layout { display: flex; gap: 30px; } | |
| .story-list { width: 250px; flex-shrink: 0; } | |
| .story-item { | |
| padding: 15px; background: var(--card-bg); margin-bottom: 10px; | |
| border-radius: 10px; cursor: pointer; border: 1px solid var(--border-color); | |
| font-size: 0.9rem; transition: 0.2s; | |
| } | |
| .story-item:hover, .story-item.active { border-color: var(--accent-color); color: var(--accent-color); background: #fdfcf9; } | |
| .story-content { flex: 1; background: var(--card-bg); padding: 40px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.03); min-height: 400px; } | |
| .story-line { margin-bottom: 25px; } | |
| .huiucl-text { font-size: 1.2rem; color: var(--accent-color); font-weight: 600; margin-bottom: 5px; } | |
| .korean-text { font-size: 1rem; color: #777; border-left: 2px solid var(--border-color); padding-left: 15px; } | |
| </style> | |
| </head> | |
| <body> | |
| <nav> | |
| <a href="#" onclick="showSection('dictionary')">DICTIONARY</a> | |
| <a href="#" onclick="showSection('grammar')">GRAMMAR</a> | |
| <a href="#" onclick="showSection('archive')">ARCHIVE</a> | |
| </nav> | |
| <header> | |
| <h1>HUIUCL</h1> | |
| <div class="sub-title">v2.0 Revision - Artificial Language Project</div> | |
| </header> | |
| <div class="container"> | |
| <section id="dictionary" class="active"> | |
| <div class="search-container"> | |
| <input type="text" id="searchInput" placeholder="๋จ์ด ํน์ ์๋ฏธ ๊ฒ์..." onkeyup="renderTable()"> | |
| </div> | |
| <div class="filter-container" id="categoryButtons"> | |
| <button onclick="changeCategory('๋ชจ๋', this)" class="active">๋ชจ๋ ๋ณด๊ธฐ</button> | |
| </div> | |
| <div class="table-wrapper"> | |
| <table> | |
| <thead> | |
| <tr><th>๋จ์ด</th><th>์๋ฏธ</th><th>๋ถ๋ฅ</th></tr> | |
| </thead> | |
| <tbody id="dictBody"></tbody> | |
| </table> | |
| </div> | |
| </section> | |
| <section id="grammar"> | |
| <div class="card"> | |
| <h2 style="font-weight: 300;">Basic Grammar</h2> | |
| <p><strong>1. ์ด์:</strong> ์ฃผ์ด-๋์ฌ(SV) ๋๋ ์ฃผ์ด-๋์ฌ-๋ชฉ์ ์ด(SVO)</p> | |
| <p><strong>2. ๋ช ๋ น๋ฌธ:</strong> ๋์ฌ๋ฅผ ๋งจ ์์ ์์น</p> | |
| <p><strong>3. ์์ :</strong> ๊ณผ๊ฑฐํ <code>-m</code>, ๋ฏธ๋ํ <code>-n</code></p> | |
| <hr style="border: 0; border-top: 1px solid var(--border-color); margin: 20px 0;"> | |
| <h3>Phoneme (์์)</h3> | |
| <p><strong>Vowels:</strong> a, i, u</p> | |
| <p><strong>Consonants:</strong> m, n, s, h, l, c(ใฒ), t(ใธ)</p> | |
| </div> | |
| </section> | |
| <section id="archive"> | |
| <div class="archive-layout"> | |
| <div class="story-list"> | |
| <div class="story-item active" onclick="loadStory(0, this)">01. ํ์</div> | |
| <div class="story-item" onclick="loadStory(1, this)">02. ์ค๋น ์ค...</div> | |
| </div> | |
| <div class="story-content" id="storyViewer"> | |
| </div> | |
| </div> | |
| </section> | |
| </div> | |
| <script> | |
| let conlangData = {}; | |
| let currentCategory = '๋ชจ๋'; | |
| // ์น์ ์ ํ | |
| function showSection(id) { | |
| document.querySelectorAll('section').forEach(s => s.classList.remove('active')); | |
| document.getElementById(id).classList.add('active'); | |
| } | |
| // ์์ค ๋ฐ์ดํฐ ๋ก๋ ๋ฐ ์ ํ | |
| const stories = [ | |
| { | |
| title: "๊ธฐ๋ก 01: ํ์", | |
| lines: [ | |
| { h: "unal cinicl si hamolhilasna clamam..", k: "์ฐ์ฃผ์ ํ๋ชฐํ๋ผ์ค๋๊ฐ ํ์ด๋ฌ๋ค." }, | |
| { h: "su u clum hoct.", k: "๊ทธ๋ ์ ์ด์๋ค." } | |
| ] | |
| }, | |
| { | |
| title: "๊ธฐ๋ก 02: (๋ด์ฉ์ ์ถ๊ฐํ์ธ์)", | |
| lines: [ | |
| { h: "...", k: "๋ค์ ์ด์ผ๊ธฐ๋ฅผ ์ค๋น ์ค์ ๋๋ค." } | |
| ] | |
| } | |
| ]; | |
| function loadStory(index, el) { | |
| if(el) { | |
| document.querySelectorAll('.story-item').forEach(item => item.classList.remove('active')); | |
| el.classList.add('active'); | |
| } | |
| const story = stories[index]; | |
| let html = `<h2 style="font-weight:300; margin-bottom:40px; text-align:center;">${story.title}</h2>`; | |
| story.lines.forEach(line => { | |
| html += ` | |
| <div class="story-line"> | |
| <div class="huiucl-text">${line.h}</div> | |
| <div class="korean-text">${line.k}</div> | |
| </div>`; | |
| }); | |
| document.getElementById('storyViewer').innerHTML = html; | |
| } | |
| // ์ด๊ธฐ ์คํ | |
| window.onload = () => { | |
| loadStory(0); | |
| fetch('Huiucl.json') | |
| .then(res => res.json()) | |
| .then(data => { | |
| conlangData = data; | |
| initButtons(); | |
| renderTable(); | |
| }); | |
| }; | |
| // --- ์ฌ์ ๋ก์ง (๊ธฐ์กด๊ณผ ๋์ผ) --- | |
| function initButtons() { | |
| const container = document.getElementById('categoryButtons'); | |
| Object.keys(conlangData).forEach(key => { | |
| if (key === "์ค์ ") return; | |
| const btn = document.createElement('button'); | |
| btn.innerText = key; | |
| btn.onclick = (e) => { | |
| document.querySelectorAll('#categoryButtons button').forEach(b => b.classList.remove('active')); | |
| e.target.classList.add('active'); | |
| currentCategory = key; | |
| renderTable(); | |
| }; | |
| container.appendChild(btn); | |
| }); | |
| } | |
| function renderTable() { | |
| const body = document.getElementById('dictBody'); | |
| const search = document.getElementById('searchInput').value.toLowerCase(); | |
| body.innerHTML = ''; | |
| const targets = currentCategory === '๋ชจ๋' ? Object.keys(conlangData).filter(k => k !== "์ค์ ") : [currentCategory]; | |
| targets.forEach(cat => traverse(conlangData[cat], cat, search)); | |
| } | |
| function traverse(obj, path, search) { | |
| for (const key in obj) { | |
| if (key === "์ค์ " || key === "๋ณํ") continue; | |
| const item = obj[key]; | |
| if (item && typeof item === 'object' && item.hasOwnProperty('๋ป')) { | |
| if (key.toLowerCase().includes(search) || item.๋ป.toLowerCase().includes(search)) addRow(key, item.๋ป, path, false); | |
| if (item[key] && typeof item[key] === 'object') processVariations(item[key], `${path} > ${key}`, search); | |
| } else if (typeof item === 'string') { | |
| if (key.toLowerCase().includes(search) || item.toLowerCase().includes(search)) addRow(key, item, path, false); | |
| } else if (typeof item === 'object') { | |
| traverse(item, `${path} > ${key}`, search); | |
| } | |
| } | |
| } | |
| function processVariations(vObj, path, search) { | |
| for (const vKey in vObj) { | |
| const vVal = vObj[vKey]; | |
| const meaning = typeof vVal === 'string' ? vVal : (vVal.๋ป || ""); | |
| if (vKey.toLowerCase().includes(search) || meaning.toLowerCase().includes(search)) addRow(vKey, meaning, path, true); | |
| if (typeof vVal === 'object' && vVal[vKey]) processVariations(vVal[vKey], `${path} > ${vKey}`, search); | |
| } | |
| } | |
| function addRow(word, meaning, path, isVar) { | |
| const row = document.getElementById('dictBody').insertRow(); | |
| row.innerHTML = `<td class="word-cell">${isVar ? 'โณ ' : ''}${word}</td><td>${meaning}</td><td style="font-size:0.7rem; color:#ccc;">${path}</td>`; | |
| } | |
| </script> | |
| </body> | |
| </html> | |