chore: replace hand-rolled layout() with @fastify/view + EJS
Convert all src/views/*.ts template-literal modules to .ejs templates under views/. Register @fastify/view plugin in server.ts with EJS engine and _layout.ejs as the layout file. Update route handlers to use reply.view() instead of reply.send(layout(...)). Delete the old TypeScript view modules and layout.ts. Closes #19
This commit is contained in:
29
views/_layout.ejs
Normal file
29
views/_layout.ejs
Normal file
@@ -0,0 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="color-scheme" content="light dark">
|
||||
<title><%= title %> — Nanodrop</title>
|
||||
<link rel="stylesheet" href="/public/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<% if (!hideHeader) { %>
|
||||
<header>
|
||||
<a href="/" class="logo">Nanodrop</a>
|
||||
<% if (authed) { %>
|
||||
<nav>
|
||||
<a href="/upload">Upload</a>
|
||||
<a href="/files">My Files</a>
|
||||
<form method="POST" action="/logout" style="display:inline">
|
||||
<button type="submit">Logout</button>
|
||||
</form>
|
||||
</nav>
|
||||
<% } %>
|
||||
</header>
|
||||
<% } %>
|
||||
<main>
|
||||
<%- body %>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
31
views/file-list.ejs
Normal file
31
views/file-list.ejs
Normal file
@@ -0,0 +1,31 @@
|
||||
<h1>My files</h1>
|
||||
<p><a href="/upload">Upload new file</a></p>
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th><th>Type</th><th>Size</th><th>Uploaded</th><th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% if (files.length === 0) { %>
|
||||
<tr><td colspan="5">No files yet. <a href="/upload">Upload one.</a></td></tr>
|
||||
<% } else { %>
|
||||
<% files.forEach(function(f) { %>
|
||||
<tr>
|
||||
<td><a href="/f/<%= f.id %>"><%= f.original_name %></a></td>
|
||||
<td><%= f.mime_type %></td>
|
||||
<td><%= f.sizeFormatted %></td>
|
||||
<td><%= f.created_at %></td>
|
||||
<td>
|
||||
<button class="copy-link" onclick="navigator.clipboard.writeText('<%= baseUrl %>/f/<%= f.id %>')">Copy link</button>
|
||||
<form method="POST" action="/files/<%= f.id %>/delete" style="display:inline">
|
||||
<button type="submit" class="danger">Delete</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<% }); %>
|
||||
<% } %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
19
views/file-view.ejs
Normal file
19
views/file-view.ejs
Normal file
@@ -0,0 +1,19 @@
|
||||
<div class="file-view">
|
||||
<h1><%= file.original_name %></h1>
|
||||
<% if (file.mime_type.startsWith('image/')) { %>
|
||||
<img src="/f/<%= file.id %>/raw" alt="<%= file.original_name %>">
|
||||
<% } else if (file.mime_type.startsWith('video/')) { %>
|
||||
<video controls src="/f/<%= file.id %>/raw" preload="metadata"></video>
|
||||
<% } else if (file.mime_type.startsWith('audio/')) { %>
|
||||
<audio controls src="/f/<%= file.id %>/raw" preload="metadata"></audio>
|
||||
<% } %>
|
||||
<div class="file-actions">
|
||||
<a href="/f/<%= file.id %>/raw" download="<%= file.original_name %>" class="btn">Download</a>
|
||||
<a href="/f/<%= file.id %>/raw" target="_blank" class="btn">Open</a>
|
||||
</div>
|
||||
<% if (isOwner) { %>
|
||||
<form method="POST" action="/files/<%= file.id %>/delete">
|
||||
<button type="submit" class="danger">Delete</button>
|
||||
</form>
|
||||
<% } %>
|
||||
</div>
|
||||
17
views/login.ejs
Normal file
17
views/login.ejs
Normal file
@@ -0,0 +1,17 @@
|
||||
<div class="form-container">
|
||||
<h1>Sign in</h1>
|
||||
<% if (error) { %>
|
||||
<p class="error"><%= error %></p>
|
||||
<% } %>
|
||||
<form method="POST" action="/login">
|
||||
<label>
|
||||
Username
|
||||
<input type="text" name="username" required autofocus>
|
||||
</label>
|
||||
<label>
|
||||
Password
|
||||
<input type="password" name="password" required>
|
||||
</label>
|
||||
<button type="submit">Login</button>
|
||||
</form>
|
||||
</div>
|
||||
5
views/not-found.ejs
Normal file
5
views/not-found.ejs
Normal file
@@ -0,0 +1,5 @@
|
||||
<div class="form-container">
|
||||
<h1>404 — Not found</h1>
|
||||
<p>The page or file you requested does not exist.</p>
|
||||
<p><a href="/">Go home</a></p>
|
||||
</div>
|
||||
9
views/upload-result.ejs
Normal file
9
views/upload-result.ejs
Normal file
@@ -0,0 +1,9 @@
|
||||
<div class="form-container">
|
||||
<h1>File uploaded</h1>
|
||||
<p><strong><%= filename %></strong> is ready to share.</p>
|
||||
<div class="share-box">
|
||||
<input type="text" id="share-url" value="<%= shareUrl %>" readonly>
|
||||
<button onclick="navigator.clipboard.writeText(document.getElementById('share-url').value)">Copy link</button>
|
||||
</div>
|
||||
<p><a href="/upload">Upload another</a> · <a href="/files">My files</a></p>
|
||||
</div>
|
||||
13
views/upload.ejs
Normal file
13
views/upload.ejs
Normal file
@@ -0,0 +1,13 @@
|
||||
<div class="form-container">
|
||||
<h1>Upload a file</h1>
|
||||
<% if (error) { %>
|
||||
<p class="error"><%= error %></p>
|
||||
<% } %>
|
||||
<form method="POST" action="/upload" enctype="multipart/form-data">
|
||||
<label>
|
||||
File
|
||||
<input type="file" name="file" required>
|
||||
</label>
|
||||
<button type="submit">Upload</button>
|
||||
</form>
|
||||
</div>
|
||||
Reference in New Issue
Block a user