templates/admin.html 4.2 K raw
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
    <meta name="theme-color" content="#121113" />
7
    <link rel="stylesheet" href="/static/styles.css" />
8
    <link rel="apple-touch-icon" sizes="180x180" href="/assets/apple-touch-icon.png">
9
    <link rel="icon" type="image/png" sizes="32x32" href="/assets/favicon-32x32.png">
10
    <link rel="icon" type="image/png" sizes="16x16" href="/assets/favicon-16x16.png">
11
    <link rel="manifest" href="/assets/site.webmanifest">
12
13
    <title>Sipp - Admin</title>
14
    <meta name="description" content="Minimal Code Sharing">
15
16
    <meta property="og:url" content="https://sipp.so">
17
    <meta property="og:type" content="website">
18
    <meta property="og:title" content="Sipps">
19
    <meta property="og:description" content="Minimal Code Sharing">
20
    <meta property="og:image" content="https://sipp.so/assets/og.png">
21
22
    <meta name="twitter:card" content="summary_large_image">
23
    <meta property="twitter:domain" content="sipp.so">
24
    <meta property="twitter:url" content="https://sipp.so">
25
    <meta name="twitter:title" content="Sipps">
26
    <meta name="twitter:description" content="Minimal Code Sharing">
27
    <meta name="twitter:image" content="https://sipp.so/assets/og.png">
28
  </head>
29
  <body>
30
31
    <div class="nav">
32
      <a href="/" class="header">
33
        <h1>SIPP</h1>
34
      </a>
35
36
      <a class="icon" target="_blank" href="https://github.com/stevedylandev/sipp">
37
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
38
          <title>GitHub</title>
39
          <path d="m21.838 11.677l-9.549-9.58c-.129-.13-.451-.13-.645 0L9 4.742l2.452 2.452c.193-.097.419-.13.645-.13c.903 0 1.58.742 1.58 1.581c0 .226-.032.452-.129.645l1.968 1.968c.194-.097.42-.129.645-.129c.904 0 1.58.742 1.58 1.58c0 .904-.741 1.581-1.58 1.581c-.903 0-1.58-.742-1.58-1.58c0-.226.032-.452.129-.646l-1.968-1.967h-.032v3.71c.58.258 1 .806 1 1.483c0 .904-.742 1.581-1.581 1.581c-.903 0-1.58-.742-1.58-1.58c0-.678.419-1.259 1-1.485v-3.612c-.581-.259-1-.807-1-1.484c0-.226.032-.452.128-.645L8.225 5.613l-6.097 6.064c-.129.13-.129.452 0 .646l9.58 9.58c.13.13.452.13.646 0l9.548-9.58a.59.59 0 0 0-.064-.646"/>
40
        </svg>
41
      </a>
42
    </div>
43
44
    <div id="authForm" style="display: flex; gap: 1rem; width: 100%;">
45
      <input placeholder="API Key" type="password" id="apiKey" style="flex: 1;">
46
      <button id="loadBtn" onclick="loadSnippets()">Load Snippets</button>
47
    </div>
48
49
    <div id="error" style="display: none; color: #ff6b6b;"></div>
50
51
    <div id="snippetList" style="display: none; width: 100%;"></div>
52
53
    <script>
54
      async function loadSnippets() {
55
        const apiKey = document.getElementById('apiKey').value;
56
        const errorEl = document.getElementById('error');
57
        const listEl = document.getElementById('snippetList');
58
        const loadBtn = document.getElementById('loadBtn');
59
60
        errorEl.style.display = 'none';
61
        listEl.style.display = 'none';
62
        loadBtn.textContent = 'Loading...';
63
        loadBtn.disabled = true;
64
65
        try {
66
          const res = await fetch('/api/snippets', {
67
            headers: { 'x-api-key': apiKey }
68
          });
69
70
          if (!res.ok) {
71
            const data = await res.json();
72
            throw new Error(data.error || 'Failed to load snippets');
73
          }
74
75
          const snippets = await res.json();
76
77
          if (snippets.length === 0) {
78
            listEl.innerHTML = '<p>No snippets found.</p>';
79
          } else {
80
            listEl.innerHTML = snippets.map(s =>
81
              `<a class="snippet-item" href="/s/${s.short_id}">` +
82
                `<span class="snippet-name">${s.name}</span>` +
83
                `<span class="snippet-id">/s/${s.short_id}</span>` +
84
              `</a>`
85
            ).join('');
86
          }
87
88
          listEl.style.display = 'flex';
89
        } catch (err) {
90
          errorEl.textContent = err.message;
91
          errorEl.style.display = 'block';
92
        } finally {
93
          loadBtn.textContent = 'Load Snippets';
94
          loadBtn.disabled = false;
95
        }
96
      }
97
98
      document.getElementById('apiKey').addEventListener('keydown', (e) => {
99
        if (e.key === 'Enter') {
100
          e.preventDefault();
101
          loadSnippets();
102
        }
103
      });
104
    </script>
105
  </body>
106
</html>