Compare commits
7 Commits
96922fdd76
...
9b42d05174
Author | SHA1 | Date | |
---|---|---|---|
9b42d05174 | |||
fd261ec8c0 | |||
f8da57224f | |||
24c210e395 | |||
f18e31811c | |||
f5ba312032 | |||
8e7b167bc2 |
23
README.md
23
README.md
@ -5,16 +5,23 @@ porous forum
|
|||||||
Released under [CNPLv7+](https://thufie.lain.haus/NPL.html).
|
Released under [CNPLv7+](https://thufie.lain.haus/NPL.html).
|
||||||
Please read the [full terms](./LICENSE.md) for proper wording.
|
Please read the [full terms](./LICENSE.md) for proper wording.
|
||||||
|
|
||||||
# deps
|
# installing
|
||||||
this is all off the top of my head so if you try to run it got help you
|
1. first, install OpenResty. instructions for linux can be found [here](https://openresty.org/en/linux-packages.html).
|
||||||
|
2. then, install LuaJIT
|
||||||
|
3. then, install [LuaRocks](https://luarocks.org) (prefer your package manager instead of a local install recommended by the guide)
|
||||||
|
4. add luarocks search dirs to path:
|
||||||
|
|
||||||
- lapis
|
```bash
|
||||||
- lsqlite3
|
# in .bashrc (or other shell equivalent)
|
||||||
- [magick](https://github.com/leafo/magick)
|
eval "$(luarocks --lua-version 5.1 path)"
|
||||||
- bcrypt
|
```
|
||||||
- luaossl
|
5. clone repo
|
||||||
|
6. install the dependencies:
|
||||||
|
|
||||||
i think thats it
|
```bash
|
||||||
|
luarocks --local --lua-version 5.1 build --only-deps
|
||||||
|
```
|
||||||
|
7. rest is TBD until a start script is provided
|
||||||
|
|
||||||
# icons
|
# icons
|
||||||
the icons in the `icons/` folder are by [Gabriele Malaspina](https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license)
|
the icons in the `icons/` folder are by [Gabriele Malaspina](https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license)
|
||||||
|
@ -69,6 +69,11 @@ app:get("thread", "/:slug", function(self)
|
|||||||
end
|
end
|
||||||
self.thread = thread
|
self.thread = thread
|
||||||
|
|
||||||
|
local post_count = Posts:count(db.clause({
|
||||||
|
thread_id = thread.id
|
||||||
|
}))
|
||||||
|
self.pages = math.max(math.ceil(post_count / POSTS_PER_PAGE), 1)
|
||||||
|
|
||||||
if self.params.after then
|
if self.params.after then
|
||||||
local after_id = tonumber(self.params.after)
|
local after_id = tonumber(self.params.after)
|
||||||
local post_position = Posts:count(db.clause({
|
local post_position = Posts:count(db.clause({
|
||||||
@ -77,13 +82,9 @@ app:get("thread", "/:slug", function(self)
|
|||||||
}))
|
}))
|
||||||
self.page = math.floor((post_position - 1) / POSTS_PER_PAGE) + 1
|
self.page = math.floor((post_position - 1) / POSTS_PER_PAGE) + 1
|
||||||
else
|
else
|
||||||
self.page = tonumber(self.params.page) or 1
|
self.page = math.max(1, math.min(tonumber(self.params.page) or 1, self.pages))
|
||||||
end
|
end
|
||||||
|
|
||||||
local post_count = Posts:count(db.clause({
|
|
||||||
thread_id = thread.id
|
|
||||||
}))
|
|
||||||
self.pages = math.ceil(post_count / POSTS_PER_PAGE)
|
|
||||||
-- self.page = math.max(1, math.min(self.page, self.pages))
|
-- self.page = math.max(1, math.min(self.page, self.pages))
|
||||||
local posts = db.query([[
|
local posts = db.query([[
|
||||||
SELECT
|
SELECT
|
||||||
|
@ -12,6 +12,8 @@ local Avatars = models.Avatars
|
|||||||
local Topics = models.Topics
|
local Topics = models.Topics
|
||||||
local Threads = models.Threads
|
local Threads = models.Threads
|
||||||
|
|
||||||
|
local THREADS_PER_PAGE = 10
|
||||||
|
|
||||||
local ThreadCreateError = {
|
local ThreadCreateError = {
|
||||||
OK = 0,
|
OK = 0,
|
||||||
GUEST = 1,
|
GUEST = 1,
|
||||||
@ -53,8 +55,10 @@ app:post("topic_create", "/create", function(self)
|
|||||||
description = topic_description,
|
description = topic_description,
|
||||||
slug = slug,
|
slug = slug,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
util.inject_infobox(self, "Topic created.")
|
||||||
|
|
||||||
return {redirect_to = self:url_for("all_topics")}
|
return {redirect_to = self:url_for("topic", {slug = topic.slug})}
|
||||||
end)
|
end)
|
||||||
|
|
||||||
app:get("topic", "/:slug", function(self)
|
app:get("topic", "/:slug", function(self)
|
||||||
@ -64,11 +68,51 @@ app:get("topic", "/:slug", function(self)
|
|||||||
if not topic then
|
if not topic then
|
||||||
return {status = 404}
|
return {status = 404}
|
||||||
end
|
end
|
||||||
|
local threads_count = Threads:count(db.clause({
|
||||||
|
topic_id = topic.id
|
||||||
|
}))
|
||||||
self.topic = topic
|
self.topic = topic
|
||||||
self.threads_list = db.query("SELECT * FROM threads WHERE topic_id = ? ORDER BY is_stickied DESC, created_at DESC", topic.id)
|
|
||||||
|
self.pages = math.max(math.ceil(threads_count / THREADS_PER_PAGE), 1)
|
||||||
|
self.page = math.max(1, math.min(tonumber(self.params.page) or 1, self.pages))
|
||||||
|
-- self.threads_list = db.query("SELECT * FROM threads WHERE topic_id = ? ORDER BY is_stickied DESC, created_at DESC", topic.id)
|
||||||
|
self.threads_list = db.query([[
|
||||||
|
SELECT
|
||||||
|
threads.title, threads.slug, threads.created_at, threads.is_locked, threads.is_stickied,
|
||||||
|
users.username AS started_by,
|
||||||
|
u.username AS latest_post_username,
|
||||||
|
ph.content AS latest_post_content,
|
||||||
|
posts.created_at AS latest_post_created_at,
|
||||||
|
posts.id AS latest_post_id
|
||||||
|
FROM
|
||||||
|
threads
|
||||||
|
JOIN users ON users.id = threads.user_id
|
||||||
|
JOIN (
|
||||||
|
SELECT
|
||||||
|
posts.thread_id,
|
||||||
|
posts.id,
|
||||||
|
posts.user_id,
|
||||||
|
posts.created_at,
|
||||||
|
posts.current_revision_id,
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY posts.thread_id ORDER BY posts.created_at DESC) AS rn
|
||||||
|
FROM
|
||||||
|
posts
|
||||||
|
) posts ON posts.thread_id = threads.id AND posts.rn = 1
|
||||||
|
JOIN
|
||||||
|
post_history ph ON ph.id = posts.current_revision_id
|
||||||
|
JOIN
|
||||||
|
users u ON u.id = posts.user_id
|
||||||
|
WHERE
|
||||||
|
threads.topic_id = ?
|
||||||
|
ORDER BY
|
||||||
|
threads.is_stickied DESC,
|
||||||
|
threads.created_at DESC
|
||||||
|
LIMIT ? OFFSET ?
|
||||||
|
]], topic.id, THREADS_PER_PAGE, (self.page - 1) * THREADS_PER_PAGE)
|
||||||
|
|
||||||
local user = util.get_logged_in_user_or_transient(self)
|
local user = util.get_logged_in_user_or_transient(self)
|
||||||
print(topic.is_locked, type(topic.is_locked))
|
|
||||||
self.me = user
|
self.me = user
|
||||||
|
|
||||||
self.ThreadCreateError = ThreadCreateError
|
self.ThreadCreateError = ThreadCreateError
|
||||||
self.thread_create_error = ThreadCreateError.OK
|
self.thread_create_error = ThreadCreateError.OK
|
||||||
if user:is_logged_in_guest() then
|
if user:is_logged_in_guest() then
|
||||||
@ -79,7 +123,7 @@ app:get("topic", "/:slug", function(self)
|
|||||||
self.thread_create_error = ThreadCreateError.TOPIC_LOCKED
|
self.thread_create_error = ThreadCreateError.TOPIC_LOCKED
|
||||||
end
|
end
|
||||||
|
|
||||||
self.page_title = "all threads in " .. topic.name
|
self.page_title = "browsing topic " .. topic.name
|
||||||
|
|
||||||
return {render = "topics.topic"}
|
return {render = "topics.topic"}
|
||||||
end)
|
end)
|
||||||
|
25
porom-dev-1.rockspec
Normal file
25
porom-dev-1.rockspec
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package = "porom"
|
||||||
|
version = "dev-1"
|
||||||
|
|
||||||
|
source = {
|
||||||
|
url = "ssh://gitea@git.poto.cafe:222/yagich/porom.git"
|
||||||
|
}
|
||||||
|
|
||||||
|
description = {
|
||||||
|
summary = "Homegrown forum software",
|
||||||
|
homepage = "",
|
||||||
|
license = "CNPLv7+"
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies = {
|
||||||
|
"lua ~> 5.1",
|
||||||
|
"lapis == 1.16.0",
|
||||||
|
"lsqlite3",
|
||||||
|
"magick",
|
||||||
|
"bcrypt",
|
||||||
|
"luaossl",
|
||||||
|
}
|
||||||
|
|
||||||
|
build = {
|
||||||
|
type = "none"
|
||||||
|
}
|
@ -46,7 +46,7 @@ $button_color: color.adjust($accent_color, $hue: 90);
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
margin: 20px;
|
margin: 20px 100px;
|
||||||
background-color: $main_bg;
|
background-color: $main_bg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +86,8 @@ body {
|
|||||||
|
|
||||||
.thread-title {
|
.thread-title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post {
|
.post {
|
||||||
@ -187,6 +189,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
button, input[type="submit"], .linkbutton {
|
button, input[type="submit"], .linkbutton {
|
||||||
|
display: inline-block;
|
||||||
@include button($button_color);
|
@include button($button_color);
|
||||||
|
|
||||||
&.critical {
|
&.critical {
|
||||||
@ -205,6 +208,10 @@ input[type="file"]::file-selector-button {
|
|||||||
margin: 10px 10px;
|
margin: 10px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.pagebutton {
|
.pagebutton {
|
||||||
@include button($button_color);
|
@include button($button_color);
|
||||||
padding: 5px 5px;
|
padding: 5px 5px;
|
||||||
@ -245,13 +252,18 @@ input[type="file"]::file-selector-button {
|
|||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="text"], input[type="password"] {
|
input[type="text"], input[type="password"], textarea, select {
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
padding: 7px 10px;
|
padding: 7px 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background-color: $lighter;
|
resize: vertical;
|
||||||
|
background-color: color.scale($accent_color, $lightness: 40%);
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background-color: color.scale($accent_color, $lightness: 60%);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.infobox {
|
.infobox {
|
||||||
@ -277,3 +289,52 @@ input[type="text"], input[type="password"] {
|
|||||||
min-width: 60px;
|
min-width: 60px;
|
||||||
padding-right: 15px;
|
padding-right: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.thread {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 96px 1.6fr 96px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 0px 0px;
|
||||||
|
grid-auto-flow: row;
|
||||||
|
min-height: 96px;
|
||||||
|
grid-template-areas:
|
||||||
|
"thread-sticky-container thread-info-container thread-locked-container";
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-sticky-container {
|
||||||
|
grid-area: thread-sticky-container;
|
||||||
|
border: 2px outset $light;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-locked-container {
|
||||||
|
grid-area: thread-locked-container;
|
||||||
|
border: 2px outset $light;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contain-svg {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contain-svg > svg {
|
||||||
|
height: 50%;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-info-container {
|
||||||
|
grid-area: thread-info-container;
|
||||||
|
background-color: $accent_color;
|
||||||
|
padding: 5px 20px;
|
||||||
|
border-top: 1px solid black;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-info-post-preview {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
margin: 20px;
|
margin: 20px 100px;
|
||||||
background-color: rgb(173.5214173228, 183.6737007874, 161.0262992126);
|
background-color: rgb(173.5214173228, 183.6737007874, 161.0262992126);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +58,8 @@ body {
|
|||||||
|
|
||||||
.thread-title {
|
.thread-title {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post {
|
.post {
|
||||||
@ -153,6 +155,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
button, input[type=submit], .linkbutton {
|
button, input[type=submit], .linkbutton {
|
||||||
|
display: inline-block;
|
||||||
background-color: rgb(177, 206, 204.5);
|
background-color: rgb(177, 206, 204.5);
|
||||||
}
|
}
|
||||||
button:hover, input[type=submit]:hover, .linkbutton:hover {
|
button:hover, input[type=submit]:hover, .linkbutton:hover {
|
||||||
@ -192,6 +195,10 @@ input[type=file]::file-selector-button:active {
|
|||||||
background-color: rgb(166.6881496063, 178.0118503937, 177.4261417323);
|
background-color: rgb(166.6881496063, 178.0118503937, 177.4261417323);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin: 15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
.pagebutton {
|
.pagebutton {
|
||||||
background-color: rgb(177, 206, 204.5);
|
background-color: rgb(177, 206, 204.5);
|
||||||
padding: 5px 5px;
|
padding: 5px 5px;
|
||||||
@ -237,13 +244,17 @@ input[type=file]::file-selector-button:active {
|
|||||||
padding: 20px 0;
|
padding: 20px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=text], input[type=password] {
|
input[type=text], input[type=password], textarea, select {
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
padding: 7px 10px;
|
padding: 7px 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
background-color: rgb(229.84, 231.92, 227.28);
|
resize: vertical;
|
||||||
|
background-color: rgb(217.8, 225.6, 208.2);
|
||||||
|
}
|
||||||
|
input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus {
|
||||||
|
background-color: rgb(230.2, 235.4, 223.8);
|
||||||
}
|
}
|
||||||
|
|
||||||
.infobox {
|
.infobox {
|
||||||
@ -267,3 +278,51 @@ input[type=text], input[type=password] {
|
|||||||
min-width: 60px;
|
min-width: 60px;
|
||||||
padding-right: 15px;
|
padding-right: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.thread {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 96px 1.6fr 96px;
|
||||||
|
grid-template-rows: 1fr;
|
||||||
|
gap: 0px 0px;
|
||||||
|
grid-auto-flow: row;
|
||||||
|
min-height: 96px;
|
||||||
|
grid-template-areas: "thread-sticky-container thread-info-container thread-locked-container";
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-sticky-container {
|
||||||
|
grid-area: thread-sticky-container;
|
||||||
|
border: 2px outset rgb(217.26, 220.38, 213.42);
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-locked-container {
|
||||||
|
grid-area: thread-locked-container;
|
||||||
|
border: 2px outset rgb(217.26, 220.38, 213.42);
|
||||||
|
}
|
||||||
|
|
||||||
|
.contain-svg {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.contain-svg > svg {
|
||||||
|
height: 50%;
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-info-container {
|
||||||
|
grid-area: thread-info-container;
|
||||||
|
background-color: #c1ceb1;
|
||||||
|
padding: 5px 20px;
|
||||||
|
border-top: 1px solid black;
|
||||||
|
border-bottom: 1px solid black;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.thread-info-post-preview {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
5
svg-icons/sticky.etlua
Normal file
5
svg-icons/sticky.etlua
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<!-- https://www.figma.com/community/file/1136337054881623512/iconcino-v2-0-0-free-icons-cc0-1-0-license -->
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M13 20H6C4.89543 20 4 19.1046 4 18V6C4 4.89543 4.89543 4 6 4H18C19.1046 4 20 4.89543 20 6V13M13 20L20 13M13 20V14C13 13.4477 13.4477 13 14 13H20" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
@ -11,6 +11,7 @@
|
|||||||
<link rel="stylesheet" href="<%= "/static/style.css?" .. math.random(1, 100) %>">
|
<link rel="stylesheet" href="<%= "/static/style.css?" .. math.random(1, 100) %>">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<% render("views.common.topnav") -%>
|
||||||
<% content_for("inner") %>
|
<% content_for("inner") %>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
11
views/common/bbcode_help.etlua
Normal file
11
views/common/bbcode_help.etlua
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<details>
|
||||||
|
<summary>Supported babycode tags</summary>
|
||||||
|
<ul>
|
||||||
|
<li>[b]<b>bold</b>[/b]</li>
|
||||||
|
<li>[i]<i>italic</i>[/i]</li>
|
||||||
|
<li>[s]<del>strikethrough</del>[/s]</li>
|
||||||
|
<li>[url=https://example.com]<a href="https://example.com">labeled URL</a>[/url]</li>
|
||||||
|
<li>[url]<a href="https://unlabeled-url.example.com">https://unlabeled-url.example.com</a>[/url]</li>
|
||||||
|
<li>[code]<code>code block</code>[/code]</li>
|
||||||
|
</ul>
|
||||||
|
</details>
|
@ -1,13 +1,17 @@
|
|||||||
<h1>New thread</h1>
|
<div class="darkbg settings-container">
|
||||||
<form method="post">
|
<h1>New thread</h1>
|
||||||
<label for="topic_id">Topic:</label>
|
<form method="post">
|
||||||
<select name="topic_id", id="topic_id" autocomplete="off">
|
<label for="topic_id">Topic</label>
|
||||||
<% for _, topic in ipairs(all_topics) do %>
|
<select name="topic_id", id="topic_id" autocomplete="off">
|
||||||
<option value="<%= topic.id %>" <%- params.topic_id == tostring(topic.id) and "selected" or "" %>><%= topic.name %></value>
|
<% for _, topic in ipairs(all_topics) do %>
|
||||||
<% end %>
|
<option value="<%= topic.id %>" <%- params.topic_id == tostring(topic.id) and "selected" or "" %>><%= topic.name %></value>
|
||||||
</select><br>
|
<% end %>
|
||||||
<label for="title">Thread title:</label>
|
</select><br>
|
||||||
<input type="text" id="title" name="title" required><br>
|
<label for="title">Thread title</label>
|
||||||
<textarea id="initial_post" name="initial_post" placeholder="Post body" required></textarea><br>
|
<input type="text" id="title" name="title" placeholder="Required" required>
|
||||||
<input type="submit" value="Create thread">
|
<label for="initial_post">Post body</label>
|
||||||
</form>
|
<textarea id="initial_post" name="initial_post" placeholder="Required" rows=5 required></textarea>
|
||||||
|
<% render "views.common.bbcode_help" %>
|
||||||
|
<input type="submit" value="Create thread">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
<% render("views.common.topnav") -%>
|
|
||||||
<% local is_locked = ntob(thread.is_locked) %>
|
<% local is_locked = ntob(thread.is_locked) %>
|
||||||
<main>
|
<main>
|
||||||
<nav class="darkbg">
|
<nav class="darkbg">
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
<h1>Editing topic <%= topic.name %></h1>
|
<div class="darkbg settings-container">
|
||||||
<form method="post">
|
<h1>Editing topic <%= topic.name %></h1>
|
||||||
<input type="text" name="name" id="name" value="<%= topic.name %>" placeholder="Topic name" required><br>
|
<form method="post">
|
||||||
<textarea id="description" name="description" value="<%= topic.description %>" placeholder="Topic description"></textarea><br>
|
<label for=name>Name</label>
|
||||||
<input type="checkbox" id="is_locked" name="is_locked" value="<%= ntob(topic.is_locked) %>">
|
<input type="text" name="name" id="name" value="<%= topic.name %>" placeholder="Topic name" required>
|
||||||
<label for="is_locked">Locked</label><br>
|
<label for=description>Description</label>
|
||||||
<input type="submit" value="Save changes">
|
<textarea id="description" name="description" placeholder="Topic description" rows=4><%= topic.description %></textarea>
|
||||||
</form>
|
<input type="submit" value="Save changes">
|
||||||
<form method="get" action="<%= url_for("topic", {slug = topic.slug}) %>">
|
<a class="linkbutton" href="<%= url_for("topic", {slug = topic.slug}) %>">Cancel</a><br>
|
||||||
<input type="submit" value="Cancel">
|
<i>Note: to preserve history, you cannot change the topic URL.</i>
|
||||||
</form>
|
</form>
|
||||||
<i>Note: to preserve history, you cannot change the topic URL.</i>
|
</div>
|
||||||
|
@ -1,33 +1,68 @@
|
|||||||
<h1><%= topic.name %></h1>
|
<% if infobox then %>
|
||||||
<h2><%= topic.description %></h2>
|
<% render("views.common.infobox", infobox) %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<nav class="darkbg">
|
||||||
|
<h1 class="thread-title">All threads in "<%= topic.name %>"</h1>
|
||||||
|
<span><%= topic.description %></span>
|
||||||
|
<div>
|
||||||
|
<% if thread_create_error == ThreadCreateError.OK then %>
|
||||||
|
<a class="linkbutton" href=<%= url_for("thread_create", nil, {topic_id = topic.id}) %>>New thread</a>
|
||||||
|
<% elseif thread_create_error == ThreadCreateError.GUEST then %>
|
||||||
|
<p>Your account is still pending confirmation by a moderator. You are not able to create a new thread or post at this time.</p>
|
||||||
|
<% elseif thread_create_error == ThreadCreateError.LOGGED_OUT then %>
|
||||||
|
<p>Only logged in users can create threads. <a href="<%= url_for("user_signup") %>">Sign up</a> or <a href="<%= url_for("user_login")%>">log in</a> to create a thread.</p>
|
||||||
|
<% else %>
|
||||||
|
<p>This topic is locked.</p>
|
||||||
|
<% end %>
|
||||||
|
<% if me:is_mod() then %>
|
||||||
|
<a class="linkbutton" href="<%= url_for("topic_edit", {slug = topic.slug}) %>">Edit topic</a>
|
||||||
|
<form class="modform" method="post" action="<%= url_for("topic_edit", {slug = topic.slug}) %>">
|
||||||
|
<input type="hidden" name="is_locked" value="<%= not ntob(topic.is_locked) %>">
|
||||||
|
<input class="warn" type="submit" id="lock" value="<%= ntob(topic.is_locked) and "Unlock topic" or "Lock topic" %>">
|
||||||
|
</form>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
<% if #threads_list == 0 then %>
|
<% if #threads_list == 0 then %>
|
||||||
<p>There are no threads in this topic.</p>
|
<p>There are no threads in this topic.</p>
|
||||||
<% else %>
|
<% else %>
|
||||||
<ul>
|
<% for _, thread in ipairs(threads_list) do %>
|
||||||
<% for _, thread in ipairs(threads_list) do %>
|
<% local is_stickied = ntob(thread.is_stickied) %>
|
||||||
<li>
|
<% local is_locked = ntob(thread.is_locked) %>
|
||||||
<a href="<%= url_for("thread", {slug = thread.slug}) %>"><%= thread.title %></a><% if ntob(thread.is_stickied) then %> - pinned<% end %>
|
<div class="thread">
|
||||||
</li>
|
<div class="thread-sticky-container contain-svg">
|
||||||
<% end %>
|
<% if is_stickied then -%>
|
||||||
</ul>
|
<% render("svg-icons.sticky") %>
|
||||||
|
<i>Stickied</i>
|
||||||
|
<% end -%>
|
||||||
|
</div>
|
||||||
|
<div class="thread-info-container">
|
||||||
|
<span>
|
||||||
|
<span class="thread-title"><a href="<%= url_for("thread", {slug = thread.slug}) %>"><%= thread.title %></a></span>
|
||||||
|
•
|
||||||
|
Started by <a href=<%= url_for("user", {username = thread.started_by}) %>><%= thread.started_by %></a>
|
||||||
|
on <%= os.date("%c", thread.created_at) %>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
Latest post by <a href="<%= url_for("user", {username = thread.latest_post_username}) %>"><%= thread.latest_post_username %></a>
|
||||||
|
<a href="<%= url_for("thread", {slug = thread.slug}, {after = thread.latest_post_id}) .. "#post-" .. thread.latest_post_id %>">on <%= os.date("%c", thread.latest_post_created_at) %></a>:
|
||||||
|
</span>
|
||||||
|
<span class="thread-info-post-preview">
|
||||||
|
<%- thread.latest_post_content %>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="thread-locked-container contain-svg">
|
||||||
|
<% if is_locked then -%>
|
||||||
|
<% render("svg-icons.lock") %>
|
||||||
|
<i>Locked</i>
|
||||||
|
<% end -%>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% if thread_create_error == ThreadCreateError.OK then %>
|
<nav id="bottomnav">
|
||||||
<a href=<%= url_for("thread_create", nil, {topic_id = topic.id}) %>>New thread</a>
|
<% render("views.common.pagination", {page_count = pages, current_page = page}) %>
|
||||||
<% elseif thread_create_error == ThreadCreateError.GUEST then %>
|
</nav>
|
||||||
<p>Your account is still pending confirmation by a moderator. You are not able to create a new thread or post at this time.</p>
|
|
||||||
<% elseif thread_create_error == ThreadCreateError.LOGGED_OUT then %>
|
|
||||||
<p>Only logged in users can create threads. <a href="<%= url_for("user_signup") %>">Sign up</a> or <a href="<%= url_for("user_login")%>">log in</a> to create a thread.</p>
|
|
||||||
<% else %>
|
|
||||||
<p>This topic is locked.</p>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% if me:is_mod() then %>
|
|
||||||
<br>
|
|
||||||
<a href="<%= url_for("topic_edit", {slug = topic.slug}) %>">Edit topic</a>
|
|
||||||
<form method="post" action="<%= url_for("topic_edit", {slug = topic.slug}) %>">
|
|
||||||
<input type="hidden" name="is_locked" value="<%= not ntob(topic.is_locked) %>">
|
|
||||||
<p><%= "This topic is " .. (ntob(topic.is_locked) and "" or "un") .. "locked." %></p>
|
|
||||||
<input type="submit" id="lock" value="<%= ntob(topic.is_locked) and "Unlock" or "Lock" %>">
|
|
||||||
</form>
|
|
||||||
<% end %>
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
<% render("views.common.topnav") -%>
|
|
||||||
<div class="darkbg settings-container">
|
<div class="darkbg settings-container">
|
||||||
<h1>Are you sure you want to delete your account, <%= me.username %>?</h1>
|
<h1>Are you sure you want to delete your account, <%= me.username %>?</h1>
|
||||||
<p>This cannot be undone. This will not delete your posts, only anonymize them.</p>
|
<p>This cannot be undone. This will not delete your posts, only anonymize them.</p>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
<% render("views.common.topnav") -%>
|
|
||||||
<div class="darkbg login-container">
|
<div class="darkbg login-container">
|
||||||
<h1>Log In</h1>
|
<h1>Log In</h1>
|
||||||
<% if infobox then %>
|
<% if infobox then %>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
<% render("views.common.topnav") -%>
|
|
||||||
<div class="darkbg settings-container">
|
<div class="darkbg settings-container">
|
||||||
<h1>User settings</h1>
|
<h1>User settings</h1>
|
||||||
<% if infobox then %>
|
<% if infobox then %>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
<% render("views.common.topnav") -%>
|
|
||||||
<div class="darkbg login-container">
|
<div class="darkbg login-container">
|
||||||
<h1>Sign up</h1>
|
<h1>Sign up</h1>
|
||||||
<% if infobox then %>
|
<% if infobox then %>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
<% render("views.common.topnav") -%>
|
|
||||||
<% if infobox then %>
|
<% if infobox then %>
|
||||||
<% render("views.common.infobox", pop_infobox) %>
|
<% render("views.common.infobox", pop_infobox) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
Loading…
Reference in New Issue
Block a user