hello-aditya commited on
Commit
f441c8d
Β·
verified Β·
1 Parent(s): 86cf068

Update static/admin.html

Browse files
Files changed (1) hide show
  1. static/admin.html +106 -21
static/admin.html CHANGED
@@ -11,12 +11,14 @@
11
  .container { max-width: 800px; margin: 0 auto; }
12
  .box { border: 1px solid var(--text-color); padding: 40px; box-shadow: 8px 8px 0 var(--shadow-color); margin-top: 10vh; }
13
  label { display: block; margin-top: 20px; font-weight: 700; font-size: 0.8rem; opacity: 0.7; }
14
- input, textarea { width: 100%; background: transparent; border: 1px solid var(--text-color); color: var(--text-color); padding: 12px; margin-top: 8px; font-family: inherit; outline: none; }
 
15
  .btn { padding: 12px 24px; font-weight: 700; cursor: pointer; border: 1px solid var(--text-color); text-transform: uppercase; font-family: inherit; margin-top: 20px; }
16
  .btn-main { background: var(--text-color); color: var(--bg-color); }
17
  .btn-alt { background: transparent; color: var(--text-color); border-color: var(--text-color); }
18
- .tabs { display: flex; border: 1px solid var(--text-color); margin: 30px 0; }
19
- .tab { flex: 1; padding: 15px; background: none; color: var(--text-color); border: none; border-right: 1px solid var(--text-color); cursor: pointer; text-transform: uppercase; font-weight: 700; }
 
20
  .tab.active { background: var(--text-color); color: var(--bg-color); }
21
  </style>
22
  </head>
@@ -37,6 +39,8 @@
37
  <div class="tabs">
38
  <button class="tab active" id="btn-post" onclick="switchTab('post')">EDITOR</button>
39
  <button class="tab" id="btn-manage" onclick="switchTab('manage')">MANAGE_DATA</button>
 
 
40
  </div>
41
 
42
  <div id="tab-post">
@@ -61,16 +65,43 @@
61
  <div id="tab-manage" style="display: none;">
62
  <div id="articleList"></div>
63
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
  </div>
65
  </div>
66
 
67
  <script>
68
  const API = '/api';
69
  let globalArticles = [];
 
70
  let currentEditId = null;
71
 
72
  function autoSlug(val) {
73
- if (currentEditId) return; // Don't auto-update slug if editing
74
  document.getElementById('postSlug').value = val.toLowerCase().trim()
75
  .replace(/[^a-z0-9]+/g, '-')
76
  .replace(/(^-|-$)/g, '');
@@ -81,19 +112,21 @@
81
  sessionStorage.setItem('key', pass);
82
 
83
  const res = await fetch(`${API}/auth/verify`, {
84
- headers: { 'X-Admin-Password': pass }
85
  });
86
 
87
  if (res.ok) {
88
  document.getElementById('loginSection').style.display = 'none';
89
  document.getElementById('adminPanel').style.display = 'block';
90
  loadArticles();
 
91
  } else {
92
- alert('ACCESS_DENIED: Invalid Key');
93
- sessionStorage.clear();
94
  }
95
  }
96
 
 
97
  async function submitArticle() {
98
  const data = {
99
  title: document.getElementById('postTitle').value,
@@ -109,20 +142,18 @@
109
  const res = await fetch(url, {
110
  method: method,
111
  headers: {
112
- 'Content-Type': 'application/json',
113
- 'X-Admin-Password': sessionStorage.getItem('key')
114
- },
115
  body: JSON.stringify(data)
116
  });
117
 
118
  if (res.ok) {
119
- alert(currentEditId ? 'βœ“ UPDATE_SUCCESS' : 'βœ“ UPLOAD_SUCCESS');
120
- cancelEdit();
121
  loadArticles();
122
  switchTab('manage');
123
- } else {
124
- alert('βœ— OPERATION_FAILED');
125
- }
126
  }
127
 
128
  async function loadArticles() {
@@ -143,16 +174,13 @@
143
  function editArt(id) {
144
  const article = globalArticles.find(a => a.id === id);
145
  if (!article) return;
146
-
147
  currentEditId = id;
148
  document.getElementById('postTitle').value = article.title;
149
  document.getElementById('postSlug').value = article.slug;
150
  document.getElementById('postExcerpt').value = article.excerpt || '';
151
  document.getElementById('postContent').value = article.content;
152
-
153
  document.getElementById('submitBtn').innerText = "UPDATE_DATA";
154
  document.getElementById('cancelBtn').style.display = "block";
155
-
156
  switchTab('post');
157
  }
158
 
@@ -162,7 +190,6 @@
162
  document.getElementById('postSlug').value = '';
163
  document.getElementById('postExcerpt').value = '';
164
  document.getElementById('postContent').value = '';
165
-
166
  document.getElementById('submitBtn').innerText = "EXECUTE_UPLOAD";
167
  document.getElementById('cancelBtn').style.display = "none";
168
  }
@@ -170,17 +197,75 @@
170
  async function deleteArt(id) {
171
  if (!confirm('CONFIRM_DATA_PURGE?')) return;
172
  await fetch(`${API}/articles/${id}`, {
173
- method: 'DELETE',
174
- headers: { 'X-Admin-Password': sessionStorage.getItem('key') }
175
  });
176
  loadArticles();
177
  }
178
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
  function switchTab(t) {
180
  document.getElementById('tab-post').style.display = t === 'post' ? 'block' : 'none';
181
  document.getElementById('tab-manage').style.display = t === 'manage' ? 'block' : 'none';
 
 
 
182
  document.getElementById('btn-post').classList.toggle('active', t === 'post');
183
  document.getElementById('btn-manage').classList.toggle('active', t === 'manage');
 
 
184
  }
185
 
186
  if(sessionStorage.getItem('key')) {
 
11
  .container { max-width: 800px; margin: 0 auto; }
12
  .box { border: 1px solid var(--text-color); padding: 40px; box-shadow: 8px 8px 0 var(--shadow-color); margin-top: 10vh; }
13
  label { display: block; margin-top: 20px; font-weight: 700; font-size: 0.8rem; opacity: 0.7; }
14
+ input, textarea, select { width: 100%; background: transparent; border: 1px solid var(--text-color); color: var(--text-color); padding: 12px; margin-top: 8px; font-family: inherit; outline: none; }
15
+ select option { color: #000; } /* Fix option visibility in dark mode */
16
  .btn { padding: 12px 24px; font-weight: 700; cursor: pointer; border: 1px solid var(--text-color); text-transform: uppercase; font-family: inherit; margin-top: 20px; }
17
  .btn-main { background: var(--text-color); color: var(--bg-color); }
18
  .btn-alt { background: transparent; color: var(--text-color); border-color: var(--text-color); }
19
+ .tabs { display: flex; border: 1px solid var(--text-color); margin: 30px 0; overflow-x: auto;}
20
+ .tab { flex: 1; padding: 15px; background: none; color: var(--text-color); border: none; border-right: 1px solid var(--text-color); cursor: pointer; text-transform: uppercase; font-weight: 700; white-space: nowrap;}
21
+ .tab:last-child { border-right: none; }
22
  .tab.active { background: var(--text-color); color: var(--bg-color); }
23
  </style>
24
  </head>
 
39
  <div class="tabs">
40
  <button class="tab active" id="btn-post" onclick="switchTab('post')">EDITOR</button>
41
  <button class="tab" id="btn-manage" onclick="switchTab('manage')">MANAGE_DATA</button>
42
+ <button class="tab" id="btn-link" onclick="switchTab('link')">ADD_LINK</button>
43
+ <button class="tab" id="btn-manage-links" onclick="switchTab('manage-links')">MANAGE_LINKS</button>
44
  </div>
45
 
46
  <div id="tab-post">
 
65
  <div id="tab-manage" style="display: none;">
66
  <div id="articleList"></div>
67
  </div>
68
+
69
+ <div id="tab-link" style="display: none;">
70
+ <label>RESOURCE_TITLE</label>
71
+ <input type="text" id="linkTitle" placeholder="e.g., Evaluating Whisper Medium on FLEURS">
72
+
73
+ <label>TARGET_URL</label>
74
+ <input type="url" id="linkUrl" placeholder="https://...">
75
+
76
+ <label>CATEGORY</label>
77
+ <select id="linkCategory">
78
+ <option value="Research Paper">Research Paper</option>
79
+ <option value="GitHub Repo">GitHub Repo</option>
80
+ <option value="Dataset">Dataset</option>
81
+ <option value="Article/Tutorial">Article/Tutorial</option>
82
+ </select>
83
+
84
+ <label>DESCRIPTION (Optional)</label>
85
+ <input type="text" id="linkDesc" placeholder="Brief note on why this is saved...">
86
+
87
+ <button class="btn btn-main" onclick="submitLink()">SAVE_LINK</button>
88
+ </div>
89
+
90
+ <div id="tab-manage-links" style="display: none;">
91
+ <div id="linkList"></div>
92
+ </div>
93
+
94
  </div>
95
  </div>
96
 
97
  <script>
98
  const API = '/api';
99
  let globalArticles = [];
100
+ let globalLinks = [];
101
  let currentEditId = null;
102
 
103
  function autoSlug(val) {
104
+ if (currentEditId) return;
105
  document.getElementById('postSlug').value = val.toLowerCase().trim()
106
  .replace(/[^a-z0-9]+/g, '-')
107
  .replace(/(^-|-$)/g, '');
 
112
  sessionStorage.setItem('key', pass);
113
 
114
  const res = await fetch(`${API}/auth/verify`, {
115
+ headers: { 'X-Admin-Password': pass }
116
  });
117
 
118
  if (res.ok) {
119
  document.getElementById('loginSection').style.display = 'none';
120
  document.getElementById('adminPanel').style.display = 'block';
121
  loadArticles();
122
+ loadLinks();
123
  } else {
124
+ alert('ACCESS_DENIED: Invalid Key');
125
+ sessionStorage.clear();
126
  }
127
  }
128
 
129
+ // --- ARTICLE LOGIC ---
130
  async function submitArticle() {
131
  const data = {
132
  title: document.getElementById('postTitle').value,
 
142
  const res = await fetch(url, {
143
  method: method,
144
  headers: {
145
+ 'Content-Type': 'application/json',
146
+ 'X-Admin-Password': sessionStorage.getItem('key')
147
+ },
148
  body: JSON.stringify(data)
149
  });
150
 
151
  if (res.ok) {
152
+ alert(currentEditId ? 'βœ“ UPDATE_SUCCESS' : 'βœ“ UPLOAD_SUCCESS');
153
+ cancelEdit();
154
  loadArticles();
155
  switchTab('manage');
156
+ } else { alert('βœ— OPERATION_FAILED'); }
 
 
157
  }
158
 
159
  async function loadArticles() {
 
174
  function editArt(id) {
175
  const article = globalArticles.find(a => a.id === id);
176
  if (!article) return;
 
177
  currentEditId = id;
178
  document.getElementById('postTitle').value = article.title;
179
  document.getElementById('postSlug').value = article.slug;
180
  document.getElementById('postExcerpt').value = article.excerpt || '';
181
  document.getElementById('postContent').value = article.content;
 
182
  document.getElementById('submitBtn').innerText = "UPDATE_DATA";
183
  document.getElementById('cancelBtn').style.display = "block";
 
184
  switchTab('post');
185
  }
186
 
 
190
  document.getElementById('postSlug').value = '';
191
  document.getElementById('postExcerpt').value = '';
192
  document.getElementById('postContent').value = '';
 
193
  document.getElementById('submitBtn').innerText = "EXECUTE_UPLOAD";
194
  document.getElementById('cancelBtn').style.display = "none";
195
  }
 
197
  async function deleteArt(id) {
198
  if (!confirm('CONFIRM_DATA_PURGE?')) return;
199
  await fetch(`${API}/articles/${id}`, {
200
+ method: 'DELETE',
201
+ headers: { 'X-Admin-Password': sessionStorage.getItem('key') }
202
  });
203
  loadArticles();
204
  }
205
 
206
+ // --- LINK LOGIC ---
207
+ async function submitLink() {
208
+ const data = {
209
+ title: document.getElementById('linkTitle').value,
210
+ url: document.getElementById('linkUrl').value,
211
+ category: document.getElementById('linkCategory').value,
212
+ description: document.getElementById('linkDesc').value,
213
+ tags: []
214
+ };
215
+
216
+ const res = await fetch(`${API}/links`, {
217
+ method: 'POST',
218
+ headers: {
219
+ 'Content-Type': 'application/json',
220
+ 'X-Admin-Password': sessionStorage.getItem('key')
221
+ },
222
+ body: JSON.stringify(data)
223
+ });
224
+
225
+ if (res.ok) {
226
+ alert('βœ“ LINK_SAVED');
227
+ document.getElementById('linkTitle').value = '';
228
+ document.getElementById('linkUrl').value = '';
229
+ document.getElementById('linkDesc').value = '';
230
+ loadLinks();
231
+ switchTab('manage-links');
232
+ } else { alert('βœ— OPERATION_FAILED'); }
233
+ }
234
+
235
+ async function loadLinks() {
236
+ const res = await fetch(`${API}/links`);
237
+ globalLinks = await res.json();
238
+
239
+ document.getElementById('linkList').innerHTML = globalLinks.map(l => `
240
+ <div style="border: 1px solid; padding: 20px; margin-bottom: 15px; display: flex; justify-content: space-between; align-items: center;">
241
+ <div>
242
+ <span style="text-transform: uppercase; font-weight: 700; display: block;">${l.title}</span>
243
+ <span style="font-size: 0.8rem; opacity: 0.7;">[${l.category}] ${l.url}</span>
244
+ </div>
245
+ <button class="btn" style="margin: 0; padding: 5px 15px; font-size: 0.7rem;" onclick="deleteLink(${l.id})">PURGE</button>
246
+ </div>
247
+ `).join('');
248
+ }
249
+
250
+ async function deleteLink(id) {
251
+ if (!confirm('CONFIRM_LINK_PURGE?')) return;
252
+ await fetch(`${API}/links/${id}`, {
253
+ method: 'DELETE',
254
+ headers: { 'X-Admin-Password': sessionStorage.getItem('key') }
255
+ });
256
+ loadLinks();
257
+ }
258
+
259
  function switchTab(t) {
260
  document.getElementById('tab-post').style.display = t === 'post' ? 'block' : 'none';
261
  document.getElementById('tab-manage').style.display = t === 'manage' ? 'block' : 'none';
262
+ document.getElementById('tab-link').style.display = t === 'link' ? 'block' : 'none';
263
+ document.getElementById('tab-manage-links').style.display = t === 'manage-links' ? 'block' : 'none';
264
+
265
  document.getElementById('btn-post').classList.toggle('active', t === 'post');
266
  document.getElementById('btn-manage').classList.toggle('active', t === 'manage');
267
+ document.getElementById('btn-link').classList.toggle('active', t === 'link');
268
+ document.getElementById('btn-manage-links').classList.toggle('active', t === 'manage-links');
269
  }
270
 
271
  if(sessionStorage.getItem('key')) {