psugam commited on
Commit
b6e41f9
·
verified ·
1 Parent(s): 1ab6fa0

Delete frontend

Browse files
frontend/html/about.html DELETED
@@ -1,166 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="UTF-8" />
5
- <title>About - Sanskrit Smart Reader</title>
6
- <style>
7
- :root {
8
- --primary: #1e4d6b;
9
- --secondary: #8b6914;
10
- --accent: #8b3a1a;
11
- --bg: #faf8f3;
12
- --card-bg: #ffffff;
13
- --text: #1a1a1a;
14
- --muted: #5a5a5a;
15
- --border-soft: #d4d4d4;
16
- --border-medium: #b8b8b8;
17
- }
18
-
19
- /* ===== PAGE ===== */
20
- body {
21
- font-family: "Crimson Pro", "Georgia", "Times New Roman", serif;
22
- background: linear-gradient(to bottom, #f5f2eb 0%, #faf8f3 100%);
23
- color: var(--text);
24
- margin: 0;
25
- padding: 0;
26
- -webkit-font-smoothing: antialiased;
27
- min-height: 100vh;
28
- }
29
-
30
- .container {
31
- max-width: 960px;
32
- margin: auto;
33
- padding: 32px 24px;
34
- }
35
-
36
- /* ===== NAVBAR ===== */
37
- nav {
38
- background: var(--card-bg);
39
- border-bottom: 1px solid var(--border-medium);
40
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
41
- position: sticky;
42
- top: 0;
43
- z-index: 100;
44
- }
45
-
46
- .nav-container {
47
- max-width: 960px;
48
- margin: 0 auto;
49
- padding: 0 24px;
50
- display: flex;
51
- justify-content: space-between;
52
- align-items: center;
53
- height: 64px;
54
- }
55
-
56
- .nav-brand {
57
- font-family: "Crimson Pro", Georgia, serif;
58
- font-size: 1.35rem;
59
- font-weight: 700;
60
- color: var(--primary);
61
- text-decoration: none;
62
- letter-spacing: -0.02em;
63
- }
64
-
65
- .nav-links {
66
- display: flex;
67
- gap: 8px;
68
- align-items: center;
69
- }
70
-
71
- .nav-links a {
72
- font-family: "Inter", system-ui, sans-serif;
73
- font-size: 0.95rem;
74
- font-weight: 600;
75
- color: var(--muted);
76
- text-decoration: none;
77
- padding: 8px 20px;
78
- border-radius: 8px;
79
- transition: all 0.2s ease;
80
- }
81
-
82
- .nav-links a:hover {
83
- color: var(--primary);
84
- background: #f5f2eb;
85
- }
86
-
87
- .nav-links a.active {
88
- color: white;
89
- background: var(--primary);
90
- }
91
-
92
- /* ===== CONTENT ===== */
93
- .content-box {
94
- background: var(--card-bg);
95
- padding: 42px 48px;
96
- border-radius: 12px;
97
- border: 1px solid var(--border-medium);
98
- box-shadow: 0 2px 16px rgba(0, 0, 0, 0.05);
99
- line-height: 1.8;
100
- }
101
-
102
- h2 {
103
- color: var(--primary);
104
- font-size: 2rem;
105
- margin-top: 0;
106
- letter-spacing: -0.02em;
107
- }
108
-
109
- p {
110
- font-size: 1.1rem;
111
- color: #2d3748;
112
- }
113
-
114
- ul {
115
- padding-left: 1.5rem;
116
- }
117
-
118
- li {
119
- margin-bottom: 0.5rem;
120
- font-size: 1.1rem;
121
- }
122
-
123
- @media (max-width: 640px) {
124
- .nav-container {
125
- flex-direction: column;
126
- height: auto;
127
- padding: 16px 24px;
128
- gap: 12px;
129
- }
130
- .nav-links {
131
- width: 100%;
132
- justify-content: center;
133
- }
134
- }
135
- </style>
136
- </head>
137
- <body>
138
- <nav>
139
- <div class="nav-container">
140
- <a href="index.html" class="nav-brand">Sanskrit Smart Reader</a>
141
- <div class="nav-links">
142
- <a href="index.html">Home</a>
143
- <a href="about.html" class="active">About</a>
144
- <a href="text_parser.html">Parser</a>
145
- </div>
146
- </div>
147
- </nav>
148
-
149
- <div class="container">
150
- <div class="content-box">
151
- <h2>About Sanskrit Smart Reader</h2>
152
- <p>
153
- This tool helps students and scholars analyze Sanskrit texts. By
154
- clicking on words, you can instantly retrieve morphological analysis
155
- and dictionary definitions from multiple sources.
156
- </p>
157
- <p>Features:</p>
158
- <ul>
159
- <li>Instant dictionary lookup</li>
160
- <li>Compound splitting</li>
161
- <li>Morphological analysis</li>
162
- </ul>
163
- </div>
164
- </div>
165
- </body>
166
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/html/index.html DELETED
@@ -1,620 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="sa">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Sanskrit Smart Reader</title>
7
-
8
- <style>
9
- :root {
10
- --primary: #1e4d6b;
11
- --secondary: #8b6914;
12
- --accent: #8b3a1a;
13
- --bg: #faf8f3;
14
- --card-bg: #ffffff;
15
- --text: #1a1a1a;
16
- --muted: #5a5a5a;
17
- --border-soft: #d4d4d4;
18
- --border-medium: #b8b8b8;
19
- --entry-border: #e8e5df;
20
- }
21
-
22
- /* ===== PAGE ===== */
23
- body {
24
- font-family: "Crimson Pro", "Georgia", "Times New Roman", serif;
25
- background: linear-gradient(to bottom, #f5f2eb 0%, #faf8f3 100%);
26
- color: var(--text);
27
- margin: 0;
28
- padding: 0;
29
- -webkit-font-smoothing: antialiased;
30
- min-height: 100vh;
31
- }
32
-
33
- .container {
34
- max-width: 960px;
35
- margin: auto;
36
- padding: 32px 24px;
37
- }
38
-
39
- /* ===== NAVBAR ===== */
40
- nav {
41
- background: var(--card-bg);
42
- border-bottom: 1px solid var(--border-medium);
43
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
44
- position: sticky;
45
- top: 0;
46
- z-index: 100;
47
- }
48
-
49
- .nav-container {
50
- max-width: 960px;
51
- margin: 0 auto;
52
- padding: 0 24px;
53
- display: flex;
54
- justify-content: space-between;
55
- align-items: center;
56
- height: 64px;
57
- }
58
-
59
- .nav-brand {
60
- font-family: "Crimson Pro", Georgia, serif;
61
- font-size: 1.35rem;
62
- font-weight: 700;
63
- color: var(--primary);
64
- text-decoration: none;
65
- letter-spacing: -0.02em;
66
- }
67
-
68
- .nav-links {
69
- display: flex;
70
- gap: 8px;
71
- align-items: center;
72
- }
73
-
74
- .nav-links a {
75
- font-family: "Inter", system-ui, sans-serif;
76
- font-size: 0.95rem;
77
- font-weight: 600;
78
- color: var(--muted);
79
- text-decoration: none;
80
- padding: 8px 20px;
81
- border-radius: 8px;
82
- transition: all 0.2s ease;
83
- letter-spacing: 0.01em;
84
- }
85
-
86
- .nav-links a:hover {
87
- color: var(--primary);
88
- background: #f5f2eb;
89
- }
90
-
91
- .nav-links a.active {
92
- color: white;
93
- background: var(--primary);
94
- }
95
-
96
- /* ===== SEARCH ===== */
97
- .search-container {
98
- background: var(--card-bg);
99
- padding: 22px 26px;
100
- border-radius: 12px;
101
- border: 1px solid var(--border-medium);
102
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
103
- margin-bottom: 32px;
104
- display: flex;
105
- gap: 14px;
106
- }
107
-
108
- input[type="text"] {
109
- flex: 1;
110
- padding: 13px 16px;
111
- border: 1.5px solid var(--border-soft);
112
- border-radius: 8px;
113
- font-size: 1.05rem;
114
- font-family: "Inter", system-ui, sans-serif;
115
- background: #fafafa;
116
- transition: all 0.2s ease;
117
- }
118
-
119
- input[type="text"]:focus {
120
- outline: none;
121
- border-color: var(--primary);
122
- background: white;
123
- box-shadow: 0 0 0 3px rgba(30, 77, 107, 0.08);
124
- }
125
-
126
- button {
127
- padding: 12px 28px;
128
- background: var(--primary);
129
- color: white;
130
- border: none;
131
- border-radius: 8px;
132
- cursor: pointer;
133
- font-weight: 600;
134
- font-family: "Inter", system-ui, sans-serif;
135
- font-size: 0.95rem;
136
- letter-spacing: 0.015em;
137
- transition: background 0.2s ease;
138
- }
139
-
140
- button:hover {
141
- background: #163a52;
142
- }
143
-
144
- /* ===== TEXT READER ===== */
145
- .text-box {
146
- background: var(--card-bg);
147
- padding: 42px 48px;
148
- border-radius: 12px;
149
- border: 1px solid var(--border-medium);
150
- box-shadow: 0 2px 16px rgba(0, 0, 0, 0.05);
151
- font-size: 1.65em;
152
- line-height: 2.1em;
153
- font-family: "Crimson Pro", Georgia, serif;
154
- }
155
-
156
- /* Clickable words */
157
- .word {
158
- cursor: pointer;
159
- color: var(--primary);
160
- border-bottom: 1.5px dotted var(--secondary);
161
- transition: all 0.15s ease;
162
- padding-bottom: 2px;
163
- }
164
-
165
- .word:hover {
166
- color: var(--accent);
167
- border-bottom-color: var(--accent);
168
- }
169
-
170
- /* ===== MODAL ===== */
171
- .modal {
172
- display: none;
173
- position: fixed;
174
- inset: 0;
175
- background: rgba(20, 20, 20, 0.55);
176
- backdrop-filter: blur(6px);
177
- z-index: 1000;
178
- }
179
-
180
- .modal-content {
181
- background: var(--bg);
182
- margin: 5vh auto;
183
- padding: 32px;
184
- width: 92%;
185
- max-width: 760px;
186
- border-radius: 20px;
187
- position: relative;
188
- max-height: 85vh;
189
- overflow-y: auto;
190
- box-shadow: 0 30px 80px rgba(0, 0, 0, 0.25);
191
- }
192
-
193
- .close-btn {
194
- position: absolute;
195
- right: 22px;
196
- top: 18px;
197
- font-size: 26px;
198
- color: var(--muted);
199
- cursor: pointer;
200
- }
201
-
202
- /* ===== MEANINGS ===== */
203
- .meaning-card {
204
- background: white;
205
- border-radius: 10px;
206
- padding: 28px 32px;
207
- margin-bottom: 28px;
208
- border: 1px solid var(--border-medium);
209
- box-shadow: 0 1px 8px rgba(0, 0, 0, 0.04);
210
- }
211
-
212
- .meaning-card:last-child {
213
- margin-bottom: 0;
214
- }
215
-
216
- .label-pill {
217
- display: inline-block;
218
- background: var(--primary);
219
- color: white;
220
- padding: 6px 14px;
221
- border-radius: 6px;
222
- font-size: 0.7em;
223
- font-weight: 700;
224
- letter-spacing: 0.04em;
225
- text-transform: uppercase;
226
- font-family: "Inter", system-ui, sans-serif;
227
- margin-bottom: 16px;
228
- }
229
-
230
- .dict-title {
231
- display: block;
232
- margin-top: 1.6em;
233
- margin-bottom: 0.5em;
234
- padding-top: 1.2em;
235
- border-top: 2px solid var(--entry-border);
236
- font-weight: 700;
237
- font-size: 1.1em;
238
- color: #2d3748;
239
- font-family: "Inter", system-ui, sans-serif;
240
- letter-spacing: -0.01em;
241
- }
242
-
243
- .dict-title:first-of-type {
244
- margin-top: 0.8em;
245
- padding-top: 0;
246
- border-top: none;
247
- }
248
-
249
- /* ===== DICTIONARY CONTENT ===== */
250
- .def-content {
251
- margin-top: 12px;
252
- max-width: 75ch;
253
- color: #2d3748;
254
- line-height: 1.75;
255
- font-family: "Crimson Pro", Georgia, serif;
256
- }
257
-
258
- /* Critical normalization */
259
- .def-content,
260
- .def-content * {
261
- font-size: 1.05rem !important;
262
- line-height: 1.75;
263
- }
264
-
265
- /* Sanskrit */
266
- .def-content .skt {
267
- font-family: "Noto Serif Devanagari", "Sanskrit 2003", serif;
268
- font-size: 1.15em !important;
269
- font-weight: 600;
270
- color: #1a1a1a;
271
- }
272
-
273
- /* Abbreviations */
274
- .def-content .abbr,
275
- .def-content abbr {
276
- font-size: 0.9em !important;
277
- font-weight: 600;
278
- color: #4a5568;
279
- font-family: "Inter", system-ui, sans-serif;
280
- }
281
-
282
- /* Metadata */
283
- .def-content .meta {
284
- font-size: 0.92em !important;
285
- color: var(--muted);
286
- font-style: italic;
287
- }
288
-
289
- /* Language markers */
290
- .def-content .lang {
291
- font-style: italic;
292
- font-size: 0.98em !important;
293
- color: #4a5568;
294
- }
295
-
296
- /* POS (Part of Speech) */
297
- .def-content .pos {
298
- font-weight: 700;
299
- color: #2d3748;
300
- font-family: "Inter", system-ui, sans-serif;
301
- font-size: 0.95em !important;
302
- }
303
-
304
- /* Sources */
305
- .def-content .source {
306
- font-size: 0.92em !important;
307
- color: #718096;
308
- font-style: italic;
309
- }
310
-
311
- /* Superscripts */
312
- .def-content sup {
313
- font-size: 0.7em !important;
314
- vertical-align: super;
315
- line-height: 0;
316
- }
317
-
318
- /* Prevent nesting collapse */
319
- .def-content span span span {
320
- font-size: inherit !important;
321
- }
322
-
323
- /* List items within definitions */
324
- .def-content ol,
325
- .def-content ul {
326
- margin: 0.8em 0;
327
- padding-left: 1.8em;
328
- }
329
-
330
- .def-content li {
331
- margin: 0.4em 0;
332
- line-height: 1.7;
333
- }
334
-
335
- /* Emphasis */
336
- .def-content em,
337
- .def-content i {
338
- font-style: italic;
339
- color: #2d3748;
340
- }
341
-
342
- .def-content strong,
343
- .def-content b {
344
- font-weight: 700;
345
- color: #1a1a1a;
346
- }
347
-
348
- /* ===== COMPOUND UI ===== */
349
- .split-container {
350
- display: flex;
351
- flex-wrap: wrap;
352
- justify-content: center;
353
- gap: 12px;
354
- margin: 22px 0;
355
- }
356
-
357
- .part-btn {
358
- background: white;
359
- border: 1.5px solid var(--primary);
360
- color: var(--primary);
361
- padding: 8px 18px;
362
- border-radius: 999px;
363
- cursor: pointer;
364
- font-weight: 600;
365
- font-size: 0.95em;
366
- }
367
-
368
- .part-btn.active {
369
- background: var(--primary);
370
- color: white;
371
- }
372
-
373
- /* Mobile responsive */
374
- @media (max-width: 640px) {
375
- .nav-container {
376
- flex-direction: column;
377
- height: auto;
378
- padding: 16px 24px;
379
- gap: 12px;
380
- }
381
-
382
- .nav-brand {
383
- font-size: 1.2rem;
384
- }
385
-
386
- .nav-links {
387
- width: 100%;
388
- justify-content: center;
389
- }
390
-
391
- .nav-links a {
392
- font-size: 0.9rem;
393
- padding: 6px 16px;
394
- }
395
- }
396
- </style>
397
- </head>
398
-
399
- <body>
400
- <!-- NAVBAR -->
401
- <nav>
402
- <div class="nav-container">
403
- <a href="index.html" class="nav-brand">Sanskrit Smart Reader</a>
404
- <div class="nav-links">
405
- <a href="index.html" class="active">Home</a>
406
- <a href="about.html">About</a>
407
- <a href="text_parser.html">Parser</a>
408
- </div>
409
- </div>
410
- </nav>
411
-
412
- <!-- MAIN CONTENT -->
413
- <div class="container">
414
- <div class="search-container">
415
- <input type="text" id="search-input" placeholder="Search word..." />
416
- <button onclick="handleSearch()">Search</button>
417
- </div>
418
-
419
- <div class="text-box" id="reader">
420
- तस्मात्त्वमुत्तिष्ठ यशो लभस्व जित्वा शत्रून्भुङ्क्ष्व राज्यं समृद्धम् ।
421
- </div>
422
-
423
- <div id="page-results"></div>
424
- </div>
425
-
426
- <div id="wordModal" class="modal">
427
- <div class="modal-content">
428
- <span class="close-btn" onclick="closeModal()">&times;</span>
429
- <div id="modal-body"></div>
430
- </div>
431
- </div>
432
-
433
- <script>
434
- const base_api = "https://psugam-sanskrit-parser-api.hf.space/";
435
-
436
- console.log("Using API base:", base_api);
437
-
438
- const reader = document.getElementById("reader");
439
- const modal = document.getElementById("wordModal");
440
- const modalBody = document.getElementById("modal-body");
441
- const pageResults = document.getElementById("page-results");
442
- const searchInput = document.getElementById("search-input");
443
-
444
- window.onclick = (e) => {
445
- if (e.target === modal) closeModal();
446
- };
447
-
448
- function closeModal() {
449
- modal.style.display = "none";
450
- modalBody.innerHTML = "";
451
- }
452
-
453
- function sanitizeHTML(str) {
454
- const div = document.createElement("div");
455
- div.textContent = str;
456
- return div.innerHTML;
457
- }
458
-
459
- /* ===== SANITIZERS ===== */
460
- function sanitizeAllowHTML(input) {
461
- // 1. Decode HTML entities FIRST
462
- const decoder = document.createElement("textarea");
463
- decoder.innerHTML = input;
464
- let html = decoder.value;
465
-
466
- // 2. Normalize Apte / MW structural junk
467
- html = html
468
- .replace(/<div[^>]*\/>/gi, "<br>")
469
- .replace(/<lbinfo[^>]*\/>/gi, "")
470
- .replace(/<\/?meta[^>]*>/gi, "")
471
- .replace(/<vlex[^>]*\/>/gi, "");
472
-
473
- // 3. Convert dictionary semantic tags → spans
474
- const replacements = {
475
- s: 'span class="skt"',
476
- s1: 'span class="skt"',
477
- ab: 'span class="abbr"',
478
- lex: 'span class="pos"',
479
- info: 'span class="meta"',
480
- ls: 'span class="source"',
481
- lang: 'span class="lang"',
482
- hom: "sup",
483
- };
484
-
485
- for (const [tag, repl] of Object.entries(replacements)) {
486
- html = html.replace(new RegExp(`<${tag}[^>]*>`, "gi"), `<${repl}>`);
487
- html = html.replace(
488
- new RegExp(`</${tag}>`, "gi"),
489
- `</${repl.split(" ")[0]}>`
490
- );
491
- }
492
-
493
- // 4. REMOVE unknown tags but KEEP their content
494
- html = html.replace(
495
- /<(?!\/?(br|b|i|em|strong|sup|sub|span)\b)[^>]+>/gi,
496
- ""
497
- );
498
-
499
- return html;
500
- }
501
-
502
- function sanitizeDictHTML(html) {
503
- return html
504
- .replace(/<vlex[^>]*\/>/gi, "")
505
- .replace(/<\/?meta[^>]*>/gi, "")
506
- .replace(/<\/?gk>|<\/?etym>|<\/?tib>/gi, "")
507
- .replace(/<\/span>\s*<\/span>\s*<\/span>/g, "</span>");
508
- }
509
-
510
- /* ===== TEXT CLICKABLE WORDS ===== */
511
- reader.innerHTML = reader.innerText
512
- .trim()
513
- .split(/(\s+|।)/)
514
- .map((w) => {
515
- const clean = w.replace(/[।\s]/g, "");
516
- return clean
517
- ? `<span class="word" onclick="initiateProcess('${sanitizeHTML(
518
- clean
519
- )}', true)">${sanitizeHTML(w)}</span>`
520
- : sanitizeHTML(w);
521
- })
522
- .join("");
523
-
524
- function handleSearch() {
525
- const word = searchInput.value.trim();
526
- if (word) initiateProcess(word, false);
527
- }
528
-
529
- async function initiateProcess(word, isPopup) {
530
- const target = isPopup ? modalBody : pageResults;
531
- target.innerHTML = `<p>Analyzing <b>${sanitizeHTML(word)}</b>…</p>`;
532
- if (isPopup) modal.style.display = "block";
533
-
534
- const res = await fetch(
535
- `${base_api}/split?word=${encodeURIComponent(word)}`
536
- );
537
- const data = await res.json();
538
-
539
- if (data.is_compound) renderCompoundUI(word, data.components, target);
540
- else renderDirectMeaning(word, target);
541
- }
542
-
543
- function renderCompoundUI(word, parts, target) {
544
- target.innerHTML = `
545
- <h3>${sanitizeHTML(word)}</h3>
546
- <div class="split-container">
547
- ${parts
548
- .map(
549
- (p) =>
550
- `<button class="part-btn" onclick="fetchPartMeaning('${sanitizeHTML(
551
- p
552
- )}','compound-res',this)">${sanitizeHTML(p)}</button>`
553
- )
554
- .join("")}
555
- </div>
556
- <div id="compound-res"></div>`;
557
- }
558
-
559
- async function renderDirectMeaning(word, target) {
560
- target.innerHTML = `<h3>${sanitizeHTML(
561
- word
562
- )}</h3><div id="direct-res"></div>`;
563
- fetchPartMeaning(word, "direct-res");
564
- }
565
-
566
- async function fetchPartMeaning(word, id, btn = null) {
567
- if (btn) {
568
- btn.parentElement
569
- .querySelectorAll(".part-btn")
570
- .forEach((b) => b.classList.remove("active"));
571
- btn.classList.add("active");
572
- }
573
-
574
- const display = document.getElementById(id);
575
- display.innerHTML = "Fetching dictionary…";
576
-
577
- const res = await fetch(
578
- `${base_api}/meaning?word=${encodeURIComponent(word)}`
579
- );
580
- const data = await res.json();
581
-
582
- const sourceMap = {
583
- mw: "Monier-Williams",
584
- ap90: "Apte",
585
- cae: "Cappeller",
586
- bhs: "Buddhist",
587
- };
588
-
589
- display.innerHTML = data
590
- .map((e) => {
591
- // Format the grammar tags: e.g., "Nom, Sg | Acc, Sg"
592
- const tags = e.detected_tags.map((t) => t.join(", ")).join(" | ");
593
-
594
- return `
595
- <div class="meaning-card">
596
- <span class="label-pill">${e.type}</span>
597
-
598
- <div class="grammar-tags" style="color: var(--accent); font-weight: bold; margin-bottom: 10px; font-size: 0.85em; text-transform: uppercase; letter-spacing: 0.5px;">
599
- ${sanitizeHTML(tags)}
600
- </div>
601
-
602
- <div style="margin-bottom: 10px;"><b>Stem:</b> ${sanitizeHTML(
603
- e.stem
604
- )}</div>
605
- ${Object.entries(e.definitions)
606
- .map(
607
- ([src, defs]) => `
608
- <span class="dict-title">${sourceMap[src] || src}</span>
609
- <div class="def-content">
610
- ${defs.map((d) => `• ${sanitizeAllowHTML(d)}`).join("<br>")}
611
- </div>`
612
- )
613
- .join("")}
614
- </div>`;
615
- })
616
- .join("");
617
- }
618
- </script>
619
- </body>
620
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/html/text_parser.html DELETED
@@ -1,502 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Sanskrit Text Parser</title>
7
- <style>
8
- :root {
9
- --primary: #1e4d6b;
10
- --secondary: #8b6914;
11
- --accent: #8b3a1a;
12
- --bg: #faf8f3;
13
- --card-bg: #ffffff;
14
- --text: #1a1a1a;
15
- --muted: #5a5a5a;
16
- --border-soft: #d4d4d4;
17
- --border-medium: #b8b8b8;
18
- --entry-border: #e8e5df;
19
- }
20
-
21
- body {
22
- font-family: "Crimson Pro", "Georgia", "Times New Roman", serif;
23
- background: linear-gradient(to bottom, #f5f2eb 0%, #faf8f3 100%);
24
- color: var(--text);
25
- margin: 0;
26
- padding: 0;
27
- -webkit-font-smoothing: antialiased;
28
- min-height: 100vh;
29
- }
30
-
31
- .container {
32
- max-width: 960px;
33
- margin: auto;
34
- padding: 32px 24px;
35
- }
36
-
37
- /* ===== NAVBAR ===== */
38
- nav {
39
- background: var(--card-bg);
40
- border-bottom: 1px solid var(--border-medium);
41
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
42
- position: sticky;
43
- top: 0;
44
- z-index: 100;
45
- }
46
-
47
- .nav-container {
48
- max-width: 960px;
49
- margin: 0 auto;
50
- padding: 0 24px;
51
- display: flex;
52
- justify-content: space-between;
53
- align-items: center;
54
- height: 64px;
55
- }
56
-
57
- .nav-brand {
58
- font-family: "Crimson Pro", Georgia, serif;
59
- font-size: 1.35rem;
60
- font-weight: 700;
61
- color: var(--primary);
62
- text-decoration: none;
63
- }
64
-
65
- .nav-links {
66
- display: flex;
67
- gap: 8px;
68
- align-items: center;
69
- }
70
-
71
- .nav-links a {
72
- font-family: "Inter", system-ui, sans-serif;
73
- font-size: 0.95rem;
74
- font-weight: 600;
75
- color: var(--muted);
76
- text-decoration: none;
77
- padding: 8px 20px;
78
- border-radius: 8px;
79
- transition: all 0.2s ease;
80
- }
81
-
82
- .nav-links a:hover {
83
- color: var(--primary);
84
- background: #f5f2eb;
85
- }
86
-
87
- .nav-links a.active {
88
- color: white;
89
- background: var(--primary);
90
- }
91
-
92
- /* ===== INPUT SECTION ===== */
93
- .input-section {
94
- background: var(--card-bg);
95
- padding: 22px 26px;
96
- border-radius: 12px;
97
- border: 1px solid var(--border-medium);
98
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
99
- margin-bottom: 32px;
100
- }
101
-
102
- textarea {
103
- width: 100%;
104
- height: 120px;
105
- padding: 16px;
106
- font-size: 1.1rem;
107
- border: 1.5px solid var(--border-soft);
108
- border-radius: 8px;
109
- margin-bottom: 16px;
110
- box-sizing: border-box;
111
- font-family: "Crimson Pro", serif;
112
- background: #fafafa;
113
- transition: all 0.2s ease;
114
- }
115
-
116
- textarea:focus {
117
- outline: none;
118
- border-color: var(--primary);
119
- background: white;
120
- }
121
-
122
- button {
123
- padding: 12px 28px;
124
- background: var(--primary);
125
- color: white;
126
- border: none;
127
- border-radius: 8px;
128
- cursor: pointer;
129
- font-weight: 600;
130
- font-family: "Inter", sans-serif;
131
- font-size: 0.95rem;
132
- }
133
-
134
- /* ===== PARSED TEXT ===== */
135
- #parsed-text {
136
- background: var(--card-bg);
137
- padding: 42px 48px;
138
- border-radius: 12px;
139
- border: 1px solid var(--border-medium);
140
- box-shadow: 0 2px 16px rgba(0, 0, 0, 0.05);
141
- font-size: 1.65em;
142
- line-height: 2.1em;
143
- margin-bottom: 32px;
144
- min-height: 100px;
145
- }
146
-
147
- .word-token {
148
- cursor: pointer;
149
- color: var(--primary);
150
- border-bottom: 1.5px dotted var(--secondary);
151
- transition: 0.2s;
152
- display: inline-block;
153
- padding: 0 4px;
154
- }
155
-
156
- .word-token:hover {
157
- color: var(--accent);
158
- background-color: #f5f2eb;
159
- }
160
-
161
- /* ===== MODAL ===== */
162
- .modal {
163
- display: none;
164
- position: fixed;
165
- z-index: 1000;
166
- left: 0;
167
- top: 0;
168
- width: 100%;
169
- height: 100%;
170
- background: rgba(0, 0, 0, 0.5);
171
- backdrop-filter: blur(4px);
172
- }
173
-
174
- .modal-content {
175
- background: var(--bg);
176
- margin: 5% auto;
177
- padding: 30px;
178
- width: 85%;
179
- max-width: 800px;
180
- border-radius: 16px;
181
- position: relative;
182
- max-height: 85vh;
183
- overflow-y: auto;
184
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
185
- }
186
-
187
- .close-btn {
188
- position: absolute;
189
- right: 20px;
190
- top: 15px;
191
- font-size: 35px;
192
- cursor: pointer;
193
- color: var(--accent);
194
- line-height: 1;
195
- }
196
-
197
- /* ===== COMPOUND UI ===== */
198
- .split-container {
199
- display: flex;
200
- flex-wrap: wrap;
201
- justify-content: center;
202
- gap: 12px;
203
- margin: 22px 0;
204
- }
205
-
206
- .part-btn {
207
- background: white;
208
- border: 1.5px solid var(--primary);
209
- color: var(--primary);
210
- padding: 8px 18px;
211
- border-radius: 999px;
212
- cursor: pointer;
213
- font-weight: 600;
214
- font-size: 0.95em;
215
- }
216
-
217
- .part-btn.active {
218
- background: var(--primary);
219
- color: white;
220
- }
221
-
222
- /* ===== RESULTS ===== */
223
- .meaning-card {
224
- background: white;
225
- border-radius: 10px;
226
- padding: 28px 32px;
227
- margin-top: 20px;
228
- border: 1px solid var(--border-medium);
229
- box-shadow: 0 1px 8px rgba(0, 0, 0, 0.04);
230
- }
231
-
232
- .label-pill {
233
- display: inline-block;
234
- background: var(--primary);
235
- color: white;
236
- padding: 6px 14px;
237
- border-radius: 6px;
238
- font-size: 0.7em;
239
- font-weight: 700;
240
- text-transform: uppercase;
241
- font-family: "Inter", sans-serif;
242
- margin-bottom: 16px;
243
- }
244
-
245
- .dict-title {
246
- display: block;
247
- margin-top: 1.6em;
248
- margin-bottom: 0.5em;
249
- padding-top: 1.2em;
250
- border-top: 2px solid var(--entry-border);
251
- font-weight: 700;
252
- font-size: 1.1em;
253
- color: #2d3748;
254
- font-family: "Inter", system-ui, sans-serif;
255
- }
256
-
257
- .dict-title:first-of-type {
258
- margin-top: 0.8em;
259
- padding-top: 0;
260
- border-top: none;
261
- }
262
-
263
- .def-content {
264
- margin-top: 12px;
265
- color: #2d3748;
266
- line-height: 1.75;
267
- font-family: "Crimson Pro", Georgia, serif;
268
- }
269
-
270
- .def-content .skt {
271
- font-weight: 600;
272
- color: #1a1a1a;
273
- }
274
- .def-content .abbr {
275
- font-size: 0.9em;
276
- font-weight: 600;
277
- color: #4a5568;
278
- }
279
-
280
- @media (max-width: 640px) {
281
- .nav-container {
282
- flex-direction: column;
283
- height: auto;
284
- padding: 16px 24px;
285
- gap: 12px;
286
- }
287
- .nav-links {
288
- width: 100%;
289
- justify-content: center;
290
- }
291
- }
292
- </style>
293
- </head>
294
- <body>
295
- <nav>
296
- <div class="nav-container">
297
- <a href="index.html" class="nav-brand">Sanskrit Smart Reader</a>
298
- <div class="nav-links">
299
- <a href="index.html">Home</a>
300
- <a href="about.html">About</a>
301
- <a href="text_parser.html" class="active">Parser</a>
302
- </div>
303
- </div>
304
- </nav>
305
-
306
- <div class="container">
307
- <h2 style="color: var(--primary); letter-spacing: -0.02em">
308
- Sanskrit Text Parser
309
- </h2>
310
-
311
- <div class="input-section">
312
- <p style="margin-top: 0; color: var(--muted); font-weight: 600">
313
- Enter Sanskrit text below and click Analyze.
314
- </p>
315
- <textarea id="input-text" placeholder="Enter text here..."></textarea>
316
- <button onclick="transformText()">Analyze</button>
317
- </div>
318
-
319
- <div id="parsed-text"></div>
320
- </div>
321
-
322
- <div id="wordModal" class="modal">
323
- <div class="modal-content">
324
- <span class="close-btn" onclick="closeModal()">&times;</span>
325
- <div id="modal-body"></div>
326
- </div>
327
- </div>
328
-
329
- <script>
330
- const base_api = "https://psugam-sanskrit-parser-api.hf.space/";
331
-
332
- console.log("Using API base:", base_api);
333
-
334
- const parsedTextContainer = document.getElementById("parsed-text");
335
- const modal = document.getElementById("wordModal");
336
- const modalBody = document.getElementById("modal-body");
337
-
338
- // Close modal logic
339
- window.onclick = (e) => {
340
- if (e.target == modal) closeModal();
341
- };
342
- function closeModal() {
343
- modal.style.display = "none";
344
- modalBody.innerHTML = "";
345
- }
346
-
347
- function sanitizeHTML(str) {
348
- const div = document.createElement("div");
349
- div.textContent = str;
350
- return div.innerHTML;
351
- }
352
-
353
- function sanitizeAllowHTML(input) {
354
- const decoder = document.createElement("textarea");
355
- decoder.innerHTML = input;
356
- let html = decoder.value;
357
-
358
- html = html
359
- .replace(/<div[^>]*\/>/gi, "<br>")
360
- .replace(/<lbinfo[^>]*\/>/gi, "")
361
- .replace(/<\/?meta[^>]*>/gi, "");
362
-
363
- const replacements = {
364
- s: 'span class="skt"',
365
- ab: 'span class="abbr"',
366
- lex: 'span class="pos"',
367
- ls: 'span class="source"',
368
- };
369
-
370
- for (const [tag, repl] of Object.entries(replacements)) {
371
- html = html.replace(new RegExp(`<${tag}[^>]*>`, "gi"), `<${repl}>`);
372
- html = html.replace(
373
- new RegExp(`</${tag}>`, "gi"),
374
- `</${repl.split(" ")[0]}>`
375
- );
376
- }
377
-
378
- html = html.replace(
379
- /<(?!\/?(br|b|i|em|strong|sup|sub|span)\b)[^>]+>/gi,
380
- ""
381
- );
382
- return html;
383
- }
384
-
385
- function transformText() {
386
- const input = document.getElementById("input-text").value;
387
- parsedTextContainer.innerHTML = "";
388
-
389
- const tokens = input.split(/(\s+|[।.।])/);
390
-
391
- tokens.forEach((token) => {
392
- if (token.trim()) {
393
- const clean = token.replace(/[।.।\s]/g, "");
394
- if (clean) {
395
- const span = document.createElement("span");
396
- span.className = "word-token";
397
- span.textContent = sanitizeHTML(token);
398
- span.onclick = () => initiateProcess(clean);
399
- parsedTextContainer.appendChild(span);
400
- } else {
401
- parsedTextContainer.appendChild(
402
- document.createTextNode(sanitizeHTML(token))
403
- );
404
- }
405
- }
406
- });
407
- }
408
-
409
- async function initiateProcess(word) {
410
- modalBody.innerHTML = `<p style="color: var(--muted)">Analyzing <b>${sanitizeHTML(
411
- word
412
- )}</b>…</p>`;
413
- modal.style.display = "block";
414
-
415
- const res = await fetch(
416
- `${base_api}/split?word=${encodeURIComponent(word)}`
417
- );
418
- const data = await res.json();
419
-
420
- if (data.is_compound)
421
- renderCompoundUI(word, data.components, modalBody);
422
- else renderDirectMeaning(word, modalBody);
423
- }
424
-
425
- function renderCompoundUI(word, parts, target) {
426
- target.innerHTML = `
427
- <h3 style="color: var(--primary)">${sanitizeHTML(word)}</h3>
428
- <div class="split-container">
429
- ${parts
430
- .map(
431
- (p) =>
432
- `<button class="part-btn" onclick="fetchPartMeaning('${sanitizeHTML(
433
- p
434
- )}','compound-res',this)">${sanitizeHTML(p)}</button>`
435
- )
436
- .join("")}
437
- </div>
438
- <div id="compound-res"></div>`;
439
- }
440
-
441
- async function renderDirectMeaning(word, target) {
442
- target.innerHTML = `<h3 style="color: var(--primary)">${sanitizeHTML(
443
- word
444
- )}</h3><div id="direct-res"></div>`;
445
- fetchPartMeaning(word, "direct-res");
446
- }
447
-
448
- async function fetchPartMeaning(word, id, btn = null) {
449
- if (btn) {
450
- btn.parentElement
451
- .querySelectorAll(".part-btn")
452
- .forEach((b) => b.classList.remove("active"));
453
- btn.classList.add("active");
454
- }
455
-
456
- const display = document.getElementById(id);
457
- display.innerHTML = "Fetching dictionary…";
458
-
459
- const res = await fetch(
460
- `${base_api}/meaning?word=${encodeURIComponent(word)}`
461
- );
462
- const data = await res.json();
463
-
464
- const sourceMap = {
465
- mw: "Monier-Williams",
466
- ap90: "Apte",
467
- cae: "Cappeller",
468
- bhs: "Buddhist",
469
- };
470
-
471
- display.innerHTML = data
472
- .map((e) => {
473
- // Format the grammar tags: e.g., "Nom, Sg | Acc, Sg"
474
- const tags = e.detected_tags.map((t) => t.join(", ")).join(" | ");
475
-
476
- return `
477
- <div class="meaning-card">
478
- <span class="label-pill">${sanitizeHTML(e.type)}</span>
479
-
480
- <div class="grammar-tags" style="color: var(--accent); font-weight: bold; margin-bottom: 10px; font-size: 0.85em; text-transform: uppercase; letter-spacing: 0.5px;">
481
- ${sanitizeHTML(tags)}
482
- </div>
483
-
484
- <div style="margin-bottom: 10px;"><b>Stem:</b> ${sanitizeHTML(
485
- e.stem
486
- )}</div>
487
- ${Object.entries(e.definitions)
488
- .map(
489
- ([src, defs]) => `
490
- <span class="dict-title">${sourceMap[src] || src}</span>
491
- <div class="def-content">
492
- ${defs.map((d) => `• ${sanitizeAllowHTML(d)}`).join("<br>")}
493
- </div>`
494
- )
495
- .join("")}
496
- </div>`;
497
- })
498
- .join("");
499
- }
500
- </script>
501
- </body>
502
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
frontend/js/sanitize.js DELETED
@@ -1,5 +0,0 @@
1
- function sanitizeHTML(text) {
2
- const temp = document.createElement('div');
3
- temp.textContent = text;
4
- return temp.innerHTML;
5
- }