OpenLab-NLP commited on
Commit
76441ae
·
verified ·
1 Parent(s): d069880

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +181 -208
index.html CHANGED
@@ -3,264 +3,237 @@
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Huiucl Dictionary</title>
7
  <style>
8
  :root {
9
- --bg-color: #f9f7f2; /* 메인 베이지 배경 */
10
- --card-bg: #ffffff; /* 화이트 카드 */
11
- --primary-color: #5d5b54; /* 진한 회갈색 (텍스트) */
12
- --accent-color: #d4a373; /* 포인트 컬러 (베이지 브라운) */
13
  --border-color: #e0ddd5;
14
- --variation-bg: #faf9f6; /* 변형 단어 배경색 */
15
  }
16
 
17
  body {
18
- font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, system-ui, Roboto, sans-serif;
19
  background-color: var(--bg-color);
20
  color: var(--primary-color);
21
- margin: 0;
22
- padding: 40px 20px;
23
- line-height: 1.6;
24
  }
25
 
26
- header { text-align: center; margin-bottom: 40px; }
27
- h1 { font-weight: 300; letter-spacing: 5px; color: var(--accent-color); margin-bottom: 10px; }
28
- .sub-title { font-size: 0.9rem; color: #999; }
29
-
30
- /* 검색창 섹션 */
31
- .search-container {
32
- max-width: 600px;
33
- margin: 0 auto 30px auto;
34
- display: flex;
35
- gap: 10px;
36
- }
37
- input[type="text"] {
38
- flex: 1;
39
- padding: 12px 24px;
40
- border: 1px solid var(--border-color);
41
- border-radius: 30px;
42
- outline: none;
43
- background-color: var(--card-bg);
44
- font-size: 1rem;
45
- box-shadow: 0 2px 5px rgba(0,0,0,0.02);
46
  }
47
- input[type="text"]:focus { border-color: var(--accent-color); box-shadow: 0 2px 10px rgba(212, 163, 115, 0.2); }
 
48
 
49
- /* 카테고리 버튼 */
50
- .filter-container {
51
- display: flex;
52
- flex-wrap: wrap;
53
- justify-content: center;
54
- gap: 8px;
55
- margin-bottom: 40px;
56
- max-width: 900px;
57
- margin-left: auto;
58
- margin-right: auto;
59
- }
60
- button {
61
- background: var(--card-bg);
62
- border: 1px solid var(--border-color);
63
- color: var(--primary-color);
64
- padding: 6px 16px;
65
- cursor: pointer;
66
- border-radius: 20px;
67
- font-size: 0.85rem;
68
- transition: all 0.2s;
69
- }
70
- button:hover, button.active {
71
- background: var(--accent-color);
72
- color: white;
73
- border-color: var(--accent-color);
74
- }
75
 
76
- /* 테이블 디자인 */
77
- .table-wrapper {
78
- max-width: 1000px;
79
- margin: 0 auto;
80
- background: var(--card-bg);
81
- border-radius: 15px;
82
- overflow: hidden;
83
- box-shadow: 0 10px 30px rgba(0,0,0,0.05);
84
- }
85
- table { width: 100%; border-collapse: collapse; table-layout: fixed; }
86
- th, td { padding: 15px 20px; text-align: left; border-bottom: 1px solid var(--bg-color); overflow: hidden; text-overflow: ellipsis; }
87
- th { background: #f1eee6; font-weight: 600; font-size: 0.9rem; color: #777; }
88
- tr:last-child td { border-bottom: none; }
89
 
90
- .word-cell { font-weight: bold; color: var(--accent-color); font-size: 1.1rem; }
91
- .path-cell { font-size: 0.75rem; color: #bbb; }
 
 
92
 
93
- /* 변형(Variation) 스타일 */
 
 
 
94
  .variation-row { background-color: var(--variation-bg); }
95
- .variation-icon { color: #ccc; margin-right: 8px; font-weight: normal; }
 
 
 
 
 
 
 
 
 
 
 
96
  </style>
97
  </head>
98
  <body>
99
 
 
 
 
 
 
 
100
  <header>
101
  <h1>HUIUCL</h1>
102
- <div class="sub-title">온라인 사전</div>
103
  </header>
104
 
105
- <div class="search-container">
106
- <input type="text" id="searchInput" placeholder="찾고 싶은 단어나 뜻을 입력하세요..." onkeyup="filterData()">
107
- </div>
108
-
109
- <div class="filter-container" id="categoryButtons">
110
- <button onclick="changeCategory('모두', this)" class="active">모두 보기</button>
111
- </div>
112
-
113
- <div class="table-wrapper">
114
- <table>
115
- <thead>
116
- <tr>
117
- <th style="width: 35%;">단어 (Huiucl)</th>
118
- <th style="width: 35%;">의미 (Korean)</th>
119
- <th style="width: 30%;">분류</th>
120
- </tr>
121
- </thead>
122
- <tbody id="dictBody">
123
- <tr><td colspan="3" style="text-align:center; padding:50px; color:#ccc;">데이터를 불러오는 중입니다...</td></tr>
124
- </tbody>
125
- </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  </div>
127
 
128
  <script>
129
  let conlangData = {};
130
- let currentCategory = '모두';
131
-
132
- // 1. JSON 로드
133
- fetch('Conlang_1.json')
134
- .then(res => res.json())
135
- .then(data => {
136
- conlangData = data;
137
- initButtons();
138
- renderTable();
139
- })
140
- .catch(err => {
141
- console.error("Error loading JSON:", err);
142
- document.getElementById('dictBody').innerHTML = '<tr><td colspan="3" style="text-align:center; color:red; padding:50px;">데이터 로드 실패 (CORS 정책 혹은 파일명을 확인하세요)</td></tr>';
143
- });
144
-
145
- function initButtons() {
146
- const container = document.getElementById('categoryButtons');
147
- // '설정'을 제외한 최상위 키들로 버튼 생성
148
- Object.keys(conlangData).forEach(key => {
149
- if (key === "설정") return;
150
- const btn = document.createElement('button');
151
- btn.innerText = key;
152
- btn.onclick = (e) => changeCategory(key, e.target);
153
- container.appendChild(btn);
154
- });
155
- }
156
-
157
- function changeCategory(key, target) {
158
- document.querySelectorAll('button').forEach(b => b.classList.remove('active'));
159
- target.classList.add('active');
160
- currentCategory = key;
161
- renderTable();
162
- }
163
 
164
- function filterData() {
165
- renderTable();
 
166
  }
167
 
168
- // 렌더링 함수
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  function renderTable() {
170
  const body = document.getElementById('dictBody');
171
- const searchTerm = document.getElementById('searchInput').value.toLowerCase();
172
  body.innerHTML = '';
173
 
174
- const targets = currentCategory === '모두'
175
- ? Object.keys(conlangData).filter(k => k !== "설정")
176
- : [currentCategory];
177
-
178
- targets.forEach(cat => {
179
- traverse(conlangData[cat], cat, searchTerm);
180
- });
181
-
182
- if (body.innerHTML === '') {
183
- body.innerHTML = '<tr><td colspan="3" style="text-align:center; padding:50px; color:#999;">검색 결과가 없습니다.</td></tr>';
184
- }
185
- }
186
-
187
- /**
188
- * 데이터를 재귀적으로 탐색하는 함수
189
- * @param {Object} obj - 탐색할 객체
190
- * @param {String} path - 현재 카테고리 경로
191
- * @param {String} search - 검색어
192
- */
193
- function traverse(obj, path, search) {
194
- for (const key in obj) {
195
- if (key === "설정" || key === "변형") continue;
196
 
197
- const item = obj[key];
198
-
199
- // Case A: 직접 ""을 가진 객체인 경우
200
- if (item && typeof item === 'object' && item.hasOwnProperty('뜻')) {
201
- const word = key;
202
- const meaning = item.뜻;
203
-
204
- if (word.toLowerCase().includes(search) || meaning.toLowerCase().includes(search)) {
205
- addRow(word, meaning, path, false);
206
- }
207
 
208
- // 단어 내부에 동일한 이름의 '변형 객체'가 있 확인 (예: sachi 안 sachi)
209
- if (item[key] && typeof item[key] === 'object') {
210
- processVariations(item[key], `${path} > ${key}`, search);
211
- }
212
- }
213
- // Case B: 값이 단순 문자열인 경우 (단어: 뜻)
214
- else if (typeof item === 'string') {
215
- if (key.toLowerCase().includes(search) || item.toLowerCase().includes(search)) {
216
- addRow(key, item, path, false);
217
- }
218
- }
219
- // Case C: 하위 카테고리 객체인 경우 (뜻이 없고 다른 객체들을 포함)
220
- else if (typeof item === 'object') {
221
- traverse(item, `${path} > ${key}`, search);
222
  }
223
- }
224
- }
225
 
226
- /**
227
- * 변형(Variation) 데이터를 처리하는 함수 (중첩된 li henna 등 대응)
228
- */
229
- function processVariations(vObj, path, search) {
230
- for (const vKey in vObj) {
231
- const vVal = vObj[vKey];
232
-
233
- if (typeof vVal === 'string') {
234
- if (vKey.toLowerCase().includes(search) || vVal.toLowerCase().includes(search)) {
235
- addRow(vKey, vVal, path, true);
236
- }
237
- } else if (vVal && typeof vVal === 'object') {
238
- // 변형 내부에 또 뜻과 객체가 있는 경우 (예: li henna)
239
- if (vVal.뜻) {
240
- if (vKey.toLowerCase().includes(search) || vVal.뜻.toLowerCase().includes(search)) {
241
- addRow(vKey, vVal.뜻, path, true);
242
  }
243
- // 더 깊은 변형이 있다면 재귀 호출
244
- if (vVal[vKey]) processVariations(vVal[vKey], `${path} > ${vKey}`, search);
245
- } else {
246
- processVariations(vVal, path, search);
247
  }
248
  }
249
  }
250
  }
251
 
252
- function addRow(word, meaning, path, isVariation) {
253
  const body = document.getElementById('dictBody');
254
  const row = body.insertRow();
255
- if (isVariation) row.className = 'variation-row';
256
 
257
  row.innerHTML = `
258
- <td class="word-cell" style="${isVariation ? 'padding-left: 40px; color: #999; font-size: 0.95rem;' : ''}">
259
- ${isVariation ? '<span class="variation-icon">↳</span>' : ''}${word}
260
- </td>
261
- <td style="${isVariation ? 'color: #777;' : ''}">${meaning}</td>
262
- <td class="path-cell">${path}</td>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
  `;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
264
  }
265
  </script>
266
 
 
3
  <head>
4
  <meta charset="UTF-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>HUIUCL Online Archive</title>
7
  <style>
8
  :root {
9
+ --bg-color: #f9f7f2;
10
+ --card-bg: #ffffff;
11
+ --primary-color: #5d5b54;
12
+ --accent-color: #d4a373;
13
  --border-color: #e0ddd5;
14
+ --variation-bg: #faf9f6;
15
  }
16
 
17
  body {
18
+ font-family: 'Pretendard', sans-serif;
19
  background-color: var(--bg-color);
20
  color: var(--primary-color);
21
+ margin: 0; padding: 0; line-height: 1.6;
 
 
22
  }
23
 
24
+ nav {
25
+ position: sticky; top: 0; background: rgba(249, 247, 242, 0.9);
26
+ backdrop-filter: blur(10px); padding: 20px; text-align: center;
27
+ border-bottom: 1px solid var(--border-color); z-index: 100;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  }
29
+ nav a { margin: 0 15px; text-decoration: none; color: var(--primary-color); font-weight: 500; font-size: 0.9rem; transition: 0.2s; cursor: pointer; }
30
+ nav a:hover { color: var(--accent-color); }
31
 
32
+ header { text-align: center; padding: 60px 20px; }
33
+ h1 { font-weight: 300; letter-spacing: 8px; color: var(--accent-color); margin: 0; }
34
+ .sub-title { font-size: 0.9rem; color: #999; margin-top: 10px; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
 
36
+ .container { max-width: 1000px; margin: 0 auto; padding: 0 20px 100px; }
37
+ section { display: none; }
38
+ section.active { display: block; animation: fadeIn 0.5s; }
39
+
40
+ @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
41
+
42
+ /* 사전(DICTIONARY) 스타일 */
43
+ .search-container { margin-bottom: 30px; display: flex; gap: 10px; }
44
+ input[type="text"] { flex: 1; padding: 12px 24px; border: 1px solid var(--border-color); border-radius: 30px; outline: none; font-size: 1rem; }
 
 
 
 
45
 
46
+ .table-wrapper { background: var(--card-bg); border-radius: 15px; overflow: hidden; box-shadow: 0 10px 30px rgba(0,0,0,0.05); }
47
+ table { width: 100%; border-collapse: collapse; table-layout: fixed; }
48
+ th, td { padding: 15px 20px; text-align: left; border-bottom: 1px solid #f1f1f1; }
49
+ th { background: #f1eee6; font-size: 0.9rem; color: #777; font-weight: 500; }
50
 
51
+ .word-cell { font-weight: bold; color: var(--accent-color); width: 25%; }
52
+ .meaning-cell { width: 45%; }
53
+ .eng-cell { width: 30%; font-size: 0.85rem; color: #999; font-style: italic; }
54
+
55
  .variation-row { background-color: var(--variation-bg); }
56
+ .variation-mark { color: #ccc; margin-right: 8px; }
57
+
58
+ /* 문법 & 아카이브 스타일 동일 */
59
+ .card { background: var(--card-bg); padding: 40px; border-radius: 15px; box-shadow: 0 10px 30px rgba(0,0,0,0.03); margin-bottom: 20px; }
60
+ .archive-layout { display: flex; gap: 30px; }
61
+ .story-list { width: 250px; flex-shrink: 0; }
62
+ .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; }
63
+ .story-item.active { border-color: var(--accent-color); color: var(--accent-color); background: #fdfcf9; }
64
+ .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; }
65
+ .story-line { margin-bottom: 25px; }
66
+ .huiucl-text { font-size: 1.2rem; color: var(--accent-color); font-weight: 600; margin-bottom: 5px; }
67
+ .korean-text { font-size: 1rem; color: #777; border-left: 2px solid var(--border-color); padding-left: 15px; }
68
  </style>
69
  </head>
70
  <body>
71
 
72
+ <nav>
73
+ <a onclick="showSection('dictionary')">DICTIONARY</a>
74
+ <a onclick="showSection('grammar')">GRAMMAR</a>
75
+ <a onclick="showSection('archive')">ARCHIVE</a>
76
+ </nav>
77
+
78
  <header>
79
  <h1>HUIUCL</h1>
80
+ <div class="sub-title">v2.0 Revision - Online Dictionary & Archive</div>
81
  </header>
82
 
83
+ <div class="container">
84
+ <section id="dictionary" class="active">
85
+ <div class="search-container">
86
+ <input type="text" id="searchInput" placeholder="HUIUCL 단어, 한국어 뜻, 또는 영문 의미 검색..." onkeyup="renderTable()">
87
+ </div>
88
+ <div class="table-wrapper">
89
+ <table>
90
+ <thead>
91
+ <tr>
92
+ <th style="width:25%">단어 (Word)</th>
93
+ <th style="width:45%">의미 (Meaning)</th>
94
+ <th style="width:30%">English</th>
95
+ </tr>
96
+ </thead>
97
+ <tbody id="dictBody">
98
+ </tbody>
99
+ </table>
100
+ </div>
101
+ </section>
102
+
103
+ <section id="grammar">
104
+ <div class="card">
105
+ <h2 style="font-weight: 300;">Grammar & Phonology</h2>
106
+ <div id="grammarContent">
107
+ </div>
108
+ </div>
109
+ </section>
110
+
111
+ <section id="archive">
112
+ <div class="archive-layout">
113
+ <div class="story-list">
114
+ <div class="story-item active" onclick="loadStory(0, this)">01. 탄생 (Clama)</div>
115
+ <div class="story-item" onclick="loadStory(1, this)">02. 준비 중...</div>
116
+ </div>
117
+ <div class="story-content" id="storyViewer"></div>
118
+ </div>
119
+ </section>
120
  </div>
121
 
122
  <script>
123
  let conlangData = {};
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
124
 
125
+ function showSection(id) {
126
+ document.querySelectorAll('section').forEach(s => s.classList.remove('active'));
127
+ document.getElementById(id).classList.add('active');
128
  }
129
 
130
+ // 초기 데 로드
131
+ window.onload = () => {
132
+ fetch('Huiucl.json')
133
+ .then(res => res.json())
134
+ .then(data => {
135
+ conlangData = data;
136
+ loadGrammar();
137
+ renderTable();
138
+ loadStory(0);
139
+ })
140
+ .catch(err => console.error("데이터를 불러오지 못했습니다. JSON 파일명을 확인하세요.", err));
141
+ };
142
+
143
+ // 사전 렌더링 로직
144
  function renderTable() {
145
  const body = document.getElementById('dictBody');
146
+ const search = document.getElementById('searchInput').value.toLowerCase();
147
  body.innerHTML = '';
148
 
149
+ // Settings, Pronouns 등을 제외한 실제 단어들 순회
150
+ const skipKeys = ["Settings", "Pronouns"];
151
+
152
+ for (const word in conlangData) {
153
+ if (skipKeys.includes(word)) continue;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
+ const entry = conlangData[word];
156
+ const kor = entry.meaning_ko || "";
157
+ const eng = entry.meaning_en || "";
 
 
 
 
 
 
 
158
 
159
+ // 검색 필터링 (표제어 는 의)
160
+ if (word.toLowerCase().includes(search) || kor.includes(search) || eng.toLowerCase().includes(search)) {
161
+ addRow(word, kor, eng, false);
 
 
 
 
 
 
 
 
 
 
 
162
  }
 
 
163
 
164
+ // 파생어(derivations) 처리
165
+ if (entry.derivations) {
166
+ for (const dWord in entry.derivations) {
167
+ const dMeaning = entry.derivations[dWord];
168
+ // 파생어도 검색 대상에 포함
169
+ if (dWord.toLowerCase().includes(search) || dMeaning.toLowerCase().includes(search)) {
170
+ addRow(dWord, dMeaning, "-", true);
 
 
 
 
 
 
 
 
 
171
  }
 
 
 
 
172
  }
173
  }
174
  }
175
  }
176
 
177
+ function addRow(word, meaning, eng, isVar) {
178
  const body = document.getElementById('dictBody');
179
  const row = body.insertRow();
180
+ if (isVar) row.className = "variation-row";
181
 
182
  row.innerHTML = `
183
+ <td class="word-cell">${isVar ? '<span class="variation-mark">↳</span>' : ''}${word}</td>
184
+ <td class="meaning-cell">${meaning}</td>
185
+ <td class="eng-cell">${eng}</td>
186
+ `;
187
+ }
188
+
189
+ // 문법 데이터 로드
190
+ function loadGrammar() {
191
+ const container = document.getElementById('grammarContent');
192
+ if (!conlangData.Settings) return;
193
+
194
+ const set = conlangData.Settings;
195
+ let html = `
196
+ <h3>Syntax (어순)</h3>
197
+ <p>기본 어순: ${set.Syntax.Word_Order.join(' / ')}</p>
198
+ <p>${set.Syntax.Imperative["2"]}</p>
199
+ <hr style="border:0; border-top:1px solid #eee; margin:20px 0;">
200
+ <h3>Phonology (음성)</h3>
201
+ <p><strong>Vowels:</strong> ${Object.keys(set.Phonology.Vowels).join(', ')}</p>
202
+ <p><strong>Consonants:</strong> ${Object.keys(set.Phonology.Consonants).join(', ')} (c=[k'], t=[t'])</p>
203
  `;
204
+ container.innerHTML = html;
205
+ }
206
+
207
+ // 아카이브 로직
208
+ const stories = [
209
+ {
210
+ title: "기록 01: 탄생",
211
+ lines: [
212
+ { h: "unal cinicl si hamolhilasna clamam..", k: "우주와 하몰히라스나가 태어났다." },
213
+ { h: "su u clum hoct.", k: "그는 신이었다." }
214
+ ]
215
+ },
216
+ {
217
+ title: "기록 02: 준비 중",
218
+ lines: [{ h: "...", k: "다음 데이터 업데이트를 기다려주세요." }]
219
+ }
220
+ ];
221
+
222
+ function loadStory(index, el) {
223
+ if(el) {
224
+ document.querySelectorAll('.story-item').forEach(item => item.classList.remove('active'));
225
+ el.classList.add('active');
226
+ }
227
+ const story = stories[index];
228
+ let html = `<h2 style="font-weight:300; margin-bottom:40px; text-align:center; color:var(--accent-color);">${story.title}</h2>`;
229
+ story.lines.forEach(line => {
230
+ html += `
231
+ <div class="story-line">
232
+ <div class="huiucl-text">${line.h}</div>
233
+ <div class="korean-text">${line.k}</div>
234
+ </div>`;
235
+ });
236
+ document.getElementById('storyViewer').innerHTML = html;
237
  }
238
  </script>
239