diff options
| author | Guillermo Serrahima <dev@vylion.com> | 2026-03-12 11:09:46 +0100 |
|---|---|---|
| committer | Guillermo Serrahima <dev@vylion.com> | 2026-03-12 11:09:46 +0100 |
| commit | 20abd199c381eeab138563af897b54ecadc57bae (patch) | |
| tree | f1340c1d9e13585fcfd29f9fab2280fcd889387b /frontend | |
| parent | 60a0ae44cdf9bece1c15f20386e2ffdf80d80e96 (diff) | |
| download | llostre-20abd199c381eeab138563af897b54ecadc57bae.tar.xz llostre-20abd199c381eeab138563af897b54ecadc57bae.zip | |
Implemented OAuth login
Diffstat (limited to 'frontend')
| -rw-r--r-- | frontend/login.html | 25 | ||||
| -rw-r--r-- | frontend/src/login.ts | 16 | ||||
| -rw-r--r-- | frontend/src/main.ts | 12 | ||||
| -rw-r--r-- | frontend/src/style.css | 17 | ||||
| -rw-r--r-- | frontend/vite.config.ts | 13 |
5 files changed, 82 insertions, 1 deletions
diff --git a/frontend/login.html b/frontend/login.html new file mode 100644 index 0000000..0f5ba0b --- /dev/null +++ b/frontend/login.html @@ -0,0 +1,25 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>llostre - login</title> + <link rel="stylesheet" href="/src/style.css"> +</head> +<body> + <div id="login-container"> + <h2>log in to llostre</h2> + <form id="login-form"> + <input + type="text" + id="handle-input" + placeholder="your_handle.bsky.social" + required + /> + <button type="submit">log in</button> + </form> + <div id="login-error"></div> + </div> + <script type="module" src="/src/login.ts"></script> +</body> +</html> diff --git a/frontend/src/login.ts b/frontend/src/login.ts new file mode 100644 index 0000000..d8054c0 --- /dev/null +++ b/frontend/src/login.ts @@ -0,0 +1,16 @@ +const loginForm = document.getElementById('login-form') as HTMLFormElement; +const handleInput = document.getElementById('handle-input') as HTMLInputElement; +const loginError = document.getElementById('login-error') as HTMLDivElement; + +loginForm.addEventListener('submit', async (e) => { + e.preventDefault(); + const handle = handleInput.value.trim(); + + if (!handle) { + loginError.textContent = 'please enter a handle'; + return; + } + + loginError.textContent = ''; + window.location.href = `/api/login?handle=${encodeURIComponent(handle)}`; +}); diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 20c3bea..4868365 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -68,6 +68,14 @@ function renderAuthor(note: any): string { } async function main() { + const sessionCheck = await fetch('/api/session', { + credentials: 'include' + }); + if (!sessionCheck.ok) { + window.location.href = '/login.html'; + throw new Error('not authenticated'); + } + const app = document.querySelector('#app'); if (!app) { console.error('App container not found'); @@ -77,7 +85,9 @@ async function main() { app.innerHTML = '<div class="spinner"></div>'; try { - const response = await fetch('http://localhost:8080/api/posts'); + const response = await fetch('/api/posts', { + credentials: 'include' + }); if (!response.ok) throw new Error(`HTTP ${response.status}`); const notes = await response.json(); diff --git a/frontend/src/style.css b/frontend/src/style.css index 549c596..700135c 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -13,6 +13,23 @@ -moz-osx-font-smoothing: grayscale; } +#login-container { + max-width: 400px; + margin: 2rem auto; + padding: 2rem; +} + +#handle-input { + width: 100%; + padding: 0.5rem; + margin-bottom: 1rem; +} + +#login-error { + color: red; + margin-top: 1rem; +} + a { font-weight: 500; color: #646cff; diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts new file mode 100644 index 0000000..4420756 --- /dev/null +++ b/frontend/vite.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vite' +import { resolve } from 'path' + +export default defineConfig({ + build: { + rollupOptions: { + input: { + main: resolve(__dirname, 'index.html'), + login: resolve(__dirname, 'login.html'), + }, + }, + }, +}) |
