add user texts and text detail pages

new /texts page lets a user manage their own texts (list +
create form linking to /texts/{id}); /texts/{id} reuses
text.js for the node tree, with a back link to /texts. home
gains a 'My texts' link in the header. the admin texts page
now sources its cross-user list from /api/texts/all.
This commit is contained in:
Yisroel Baum 2026-05-02 21:46:41 +03:00
parent 7473af4163
commit 6d11f7e887
Signed by: yisroelbaum
GPG key ID: 0FA60884F75520A9
5 changed files with 111 additions and 4 deletions

View file

@ -3,17 +3,18 @@ document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('texts-form');
async function loadTexts() {
const res = await fetch('/api/texts', {
const res = await fetch('/api/texts/all', {
credentials: 'same-origin',
});
const texts = await res.json();
textsList.innerHTML = texts.map(text =>
'<li class="card"><a class="card-link"'
textsList.innerHTML = texts.map(function (text) {
return '<li class="card"><a class="card-link"'
+ ' href=/admin/texts/'
+ text.id
+ '>'
+ text.name
+ '</a></li>').join('');
+ '</a></li>';
}).join('');
}
form.addEventListener('submit', async (e) => {

43
public/js/userTexts.js Normal file
View file

@ -0,0 +1,43 @@
document.addEventListener('DOMContentLoaded', () => {
const textsList = document.getElementById('texts-list');
const form = document.getElementById('texts-form');
async function loadTexts() {
const response = await fetch('/api/texts', {
credentials: 'same-origin',
});
const texts = await response.json();
textsList.innerHTML = texts.map(function (text) {
return '<li class="card"><a class="card-link"'
+ ' href=/texts/'
+ text.id
+ '>'
+ text.name
+ '</a></li>';
}).join('');
}
form.addEventListener('submit', async (submitEvent) => {
submitEvent.preventDefault();
const formData = new FormData(form);
const response = await fetch('/api/texts', {
method: 'POST',
credentials: 'same-origin',
body: formData,
});
if (response.ok) {
const text = await response.json();
const li = document.createElement('li');
li.className = 'card';
const link = document.createElement('a');
link.className = 'card-link';
link.href = '/texts/' + text.id;
link.textContent = text.name;
li.appendChild(link);
textsList.appendChild(li);
form.reset();
}
});
loadTexts();
});

View file

@ -11,6 +11,9 @@
<div class="site-header-inner">
<h1>Home</h1>
<div class="cluster">
<a class="btn btn-secondary" href="/texts" id="manage-texts">
My texts
</a>
<a class="btn btn-secondary" href="/today">
Today's schedule
</a>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Daily Goals - Text</title>
<link rel="stylesheet" href="/css/app.css">
</head>
<body>
<header class="site-header">
<div class="site-header-inner">
<a class="btn btn-secondary" href="/texts" id="back">
Back to My Texts
</a>
</div>
</header>
<main class="container container-wide stack">
<div id="text-detail" class="node-tree stack"></div>
</main>
<script src="/js/text.js"></script>
</body>
</html>

View file

@ -0,0 +1,38 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Daily Goals - My Texts</title>
<link rel="stylesheet" href="/css/app.css">
</head>
<body>
<header class="site-header">
<div class="site-header-inner">
<h1>My Texts</h1>
<div class="cluster">
<a class="btn btn-secondary" href="/home" id="back">
Back to Home
</a>
<button id="logout" class="btn btn-danger">Logout</button>
</div>
</div>
</header>
<main class="container stack-lg">
<ul id="texts-list" class="list-cards"></ul>
<form id="texts-form" action="/api/texts" method="POST"
class="card stack">
<label>New text name
<input id="newTextName" name="name" type="text" />
</label>
<div class="cluster cluster-end">
<button id="submit" class="btn btn-primary" type="submit">
Add text
</button>
</div>
</form>
</main>
<script src="/js/auth.js"></script>
<script src="/js/userTexts.js"></script>
</body>
</html>