~whbboyd/russet

97438677e5ac7f1c437473fc41e52886d885a19c — Will Boyd 4 months ago ce0c3ba
Bulk operations and some restyling.

Still to be done:
 * select-all
 * UI to review/undelete deleted entries
M Cargo.lock => Cargo.lock +1 -1
@@ 1964,7 1964,7 @@ dependencies = [

[[package]]
name = "russet"
version = "0.11.0"
version = "0.12.0"
dependencies = [
 "argon2",
 "atom_syndication",

M Cargo.toml => Cargo.toml +1 -1
@@ 1,6 1,6 @@
[package]
name = "russet"
version = "0.11.0"
version = "0.12.0"
edition = "2021"
license = "AGPL-3.0"


M templates/feed.stpl => templates/feed.stpl +31 -35
@@ 1,46 1,42 @@
<% include!("head.stpl"); %>
		<p>Feed URL: <a href="<%- feed.url %>"><%= feed.url %></a></p>
		<form><table>
			<thead class="alt"><tr>
				<th scope="col">
					<label for="select-all">All</label>
					<input type="checkbox" name="select-all" />
				</th>
				<th scope="col">Title</th>
				<th scope="col">Date</th>
			</tr></thead>
			<tbody><%
		<form action="<%- relative_root %>/" method="post">
			<div id="table">
				<div id="table-header">
					<div class="select">
						<label for="select-all">All</label>
						<input type="checkbox" name="select-all" disabled />
					</div>
					<div class="title">Title</div>
					<div class="date">Date</div>
				</div><%
for (i, entry) in entries.iter().enumerate() {
	let mut classes = vec![];
	if i % 2 == 1 { classes.push("alt") };
	if !entry.read { classes.push("unread") };
	let classes = if classes.len() > 0 {
		format!(" class=\"{}\"", classes.join(" "))
	if i % 2 == 1 {
		classes.push("alt")
	} else {
		"".to_string()
		classes.push("table-row")
	};
	if !entry.read { classes.push("unread") };
	let classes = classes.join(" ");
%>
				<tr<%- classes %>>
					<td class="center"><input type="checkbox" name="select-<%= entry.id.to_string() %>" /></td>
					<td><a href="<%- relative_root %>entry/<%- entry.id.to_string() %>"><%= entry.title %></a></td>
					<td class="center"><%= entry.article_date %></td>
				</tr><%
				<div class="<%- classes %>">
					<div class="select"><input type="checkbox" name="select-<%= entry.id.to_string() %>" /></div>
					<a class="title" href="<%- relative_root %>entry/<%- entry.id.to_string() %>"><%= entry.title %></a>
					<div class="date"><%= entry.article_date %></div>
				</div><%
}
%>
			</tbody>
		</table></form>
		<div>Page:
			<% if page_num > 1 { %><a href="<%- relative_root %>?page_num=0">1</a>…<% } %>
			<% if page_num > 0 { %><a href="<%- relative_root %>?page_num=<%- page_num - 1 %>"><%- page_num %></a><% } %>
			<%- page_num + 1 %>
			<a href="<%- relative_root %>?page_num=<%- page_num + 1 %>"><%- page_num + 2 %></a>
		</div>
		<div style="display: flex; justify-content: center;">
			<form action="<%- relative_root %>feed/<%- feed.id.to_string() %>" method="post" class="dialog">
				<div class="controls">
					<input type="submit" value = "Unsubscribe" />
				</div>
			</form>
		</div>
			</div>
<% include!("pagination.stpl"); %>
			<div style="display: flex; justify-content: center;"><div class="dialog">
				<span style="flex-grow: 3">
					<button name="action" value="mark_read">Mark Read</button>
					<button name="action" value="delete">Delete</button>
				</span>
				<span class="controls">
					<button name="action" value="unsubscribe" formaction="<%- relative_root %>feed/<%- feed.id.to_string() %>" formmethod="post">Unsubscribe</button>
				</span>
			</div></div>
<% include!("foot.stpl"); %>


M templates/login.stpl => templates/login.stpl +2 -2
@@ 7,7 7,7 @@
					<label for="plaintext_password">Password:</label>
					<input type="password" name="plaintext_password" />
					<label for="permanent_session">Stay logged in</label>
					<input type="checkbox" name="permanent_session" value="true"/>
					<input type="checkbox" name="permanent_session" value="true" />
				</div><%
	if redirect_to != None {
	%>


@@ 15,7 15,7 @@
	}
	%>
				<div class="controls">
					<input type="submit" value = "Log in" />
					<button>Log in</button>
				</div>
			</form>
		</div>

A templates/pagination.stpl => templates/pagination.stpl +9 -0
@@ 0,0 1,9 @@
			<div id="pagination">Page: <%
if page_num > 1 {
	%><a href="<%- relative_root %>?page_num=0">1</a>… <%
}
if page_num > 0 {
	%><a href="<%- relative_root %>?page_num=<%- page_num - 1 %>"><%- page_num %></a> <%
}
%><%- page_num + 1 %> <a href="<%- relative_root %>?page_num=<%- page_num + 1 %>"><%- page_num + 2 %></a>
			</div>

M templates/root.stpl => templates/root.stpl +35 -40
@@ 1,53 1,48 @@
<% include!("head.stpl"); %>
		<form action="<%- relative_root %>/" method="post">
			<table>
				<thead class="alt"><tr>
					<th scope="col">
			<div id="table">
				<div id="table-header">
					<div class="select">
						<label for="select-all">All</label>
						<input type="checkbox" name="select-all" />
					</th>
					<th scope="col">Title</th>
					<th scope="col">Date</th>
					<th scope="col">Feed</th>
				</tr></thead>
				<tbody><%
	for (i, entry) in entries.iter().enumerate() {
		let mut classes = vec![];
		if i % 2 == 1 { classes.push("alt") };
		if !entry.read { classes.push("unread") };
		let classes = if classes.len() > 0 {
			format!(" class=\"{}\"", classes.join(" "))
		} else {
			"".to_string()
		};
	%>
					<tr<%- classes %>>
						<td class="center"><input type="checkbox" name="select-<%= entry.id.to_string() %>" /></td>
						<td><a href="<%- relative_root %>entry/<%- entry.id.to_string() %>"><%= entry.title %></a></td>
						<td class="center"><%= entry.article_date %></td>
						<td class="center"><a href="<%- relative_root %>feed/<%= entry.feed_id.to_string() %>"><%=
						<input type="checkbox" name="select-all" disabled />
					</div>
					<div class="title">Title</div>
					<div class="date">Date</div>
					<div class="feed">Feed</div>
				</div><%
for (i, entry) in entries.iter().enumerate() {
	let mut classes = vec![];
	if i % 2 == 1 {
		classes.push("alt")
	} else {
		classes.push("table-row")
	};
	if !entry.read { classes.push("unread") };
	let classes = classes.join(" ");
%>
				<div class="<%- classes %>">
					<div class="select"><input type="checkbox" name="select-<%= entry.id.to_string() %>" /></div>
					<a class="title" href="<%- relative_root %>entry/<%- entry.id.to_string() %>"><%= entry.title %></a>
					<div class="date"><%= entry.article_date %></div>
					<a class="feed" href="<%- relative_root %>feed/<%= entry.feed_id.to_string() %>"><%=
	match feeds.get(&entry.feed_id) {
		Some(feed) => feed.title.clone(),
		None => "Unknown Feed".to_string(),
	}
	%></a></td>
					</tr><%
	}
	%>
				</tbody>
			</table>
			<div>Page:
				<% if page_num > 1 { %><a href="<%- relative_root %>?page_num=0">1</a>…<% } %>
				<% if page_num > 0 { %><a href="<%- relative_root %>?page_num=<%- page_num - 1 %>"><%- page_num %></a><% } %>
				<%- page_num + 1 %>
				<a href="<%- relative_root %>?page_num=<%- page_num + 1 %>"><%- page_num + 2 %></a>
%></a>
				</div><%
}
%>
			</div>
			<div class="dialog" style="display: flex; justify-content: center;">
				<div class="controls">
<% include!("pagination.stpl"); %>
			<div style="display: flex; justify-content: center;"><div class="dialog">
				<span style="flex-grow: 3">
					<button name="action" value="mark_read">Mark Read</button>
					<button name="action" value="delete">Delete</button>
				</span>
				<span class="controls">
					<button name="action" value="subscribe" formaction="<%- relative_root %>/subscribe" formmethod="get">Subscribe</button>
				</div>
			</div>
				</span>
			</div></div>
		</form>
<% include!("foot.stpl"); %>

M templates/static/styles.css.stpl => templates/static/styles.css.stpl +74 -22
@@ 44,22 44,56 @@ a:hover {
}

/* Table styles */
table {
#table {
	display: table;
	width: 100%;
	padding: 1em;
	border: 0.25em outset #272727;
	border-radius: 0.5em;
	box-shadow: 0.2em 0.2em 1em -0.5em #000;
}
#table-header {
	display: table-row;
	font-weight: bold;
	background: #333;
}
.table-row {
	display: table-row;
}
.alt {
	display: table-row;
	background: #333;
}
.unread {
	font-weight: bold;
.table-row:hover {
	background: #272727;
}
.alt:hover {
	background: #373737;
}
#table .select {
	display: table-cell;
	padding: 0.3em 1em;
	text-align: center;
	border-right: 1px solid #222;
}
td {
	padding-left: 1em;
	padding-right: 1em;
	border: none;
#table .title {
	display: table-cell;
	padding: 0.3em 1em;
	border-right: 1px solid #222;
}
td.center {
#table .date {
	display: table-cell;
	padding: 0.3em 1em;
	text-align: center;
	border-right: 1px solid #222;
}
#table .feed {
	display: table-cell;
	padding: 0.3em 1em;
	text-align: center;
}
.unread {
	font-weight: bold;
}

/* Footer styles */


@@ 67,27 101,51 @@ td.center {
	margin-top: 0.5em;
	text-align: center;
}
#pagination {
	margin: 1em;
}

/* General form styles */
input[type = checkbox] {
	font-family: inherit;
	font-size: 100%;
	color: inherit;
	border-radius: 0.25em;
}
button {
	background: #282;
	color: #fff;
	border: 0.25em outset #393;
	border-radius: 0.25em;
	padding: 0.5em 1.5em 0.5em 1.5em;
	box-shadow: 0.2em 0.2em 1em -0.5em #000;
}
button:hover {
	background: #393;
	border-color: #4a4;
}
button:active {
	background: #161;
	border-color: #282;
	border-style: inset;
}

/* Dialog form styles */
.dialog {
	background: #333;
	width: 50em;
	padding: 1em;
	border: 0.25em outset #444;
	border-radius: 0.5em;
	background: #333;
	box-shadow: 0.2em 0.2em 1em -0.5em #000;
}
.dialog input {
	font-family: inherit;
	font-size: 100%;
	color: inherit;
	margin: 0.5em;
	border-radius: 0.25em;
}
.dialog input[type=checkbox] {
	width: fit-content;
}
.dialog .inputs {
	display: grid;
	grid-template-columns: 30% 70%;
	margin-bottom: 0.5em;
}
.dialog label {
	text-align: right;


@@ 100,9 158,3 @@ td.center {
.dialog .controls {
	float: right;
}
.dialog .controls input {
	background: #282;
	color: #fff;
	border: none;
	padding: 0.5em 1.5em 0.5em 1.5em;
}

M templates/subscribe.stpl => templates/subscribe.stpl +1 -1
@@ 6,7 6,7 @@
					<input type="text" name="url"/>
				</div>
				<div class="controls">
					<input type="submit" value = "Subscribe" />
					<button>Subscribe</button>
				</div>
			</form>
		</div>