Merge branch 'master' into master2

This commit is contained in:
edshot99 2025-02-05 16:54:44 -06:00
commit 77b01aa5f8
47 changed files with 1304 additions and 572 deletions

View File

@ -24,7 +24,7 @@ module ApplicationHelper
tag.li(id: id, class: klass) do
link_to(url, id: "#{id}-link", **options) do
concat tag.i(class: icon)
concat svg_icon(icon)
concat " "
concat tag.span(text)
end
@ -189,6 +189,21 @@ module ApplicationHelper
end
end
def simple_avatar(user, **options)
return "" if user.nil?
post_id = user.avatar_id
deferred_post_ids.add(post_id) if post_id
klass = options.delete(:class)
named = options.delete(:named)
tag.a href: user_path(user), class: "simple-avatar #{klass}", data: { id: post_id, name: user.name } do
tag.span(class: "simple-avatar-button") do
concat tag.span(user.pretty_name, class: "simple-avatar-name") if named
concat tag.span(class: "simple-avatar-image", data: { name: user.name[0].capitalize })
end
end
end
def user_banner(user)
return "" if user.nil?
post_id = user.banner_id

View File

@ -0,0 +1,49 @@
# frozen_string_literal: true
module IconHelper
# https://lucide.dev/
PATHS = {
# Navigation
hamburger: %(<line x1="4" x2="20" y1="12" y2="12"/><line x1="4" x2="20" y1="6" y2="6"/><line x1="4" x2="20" y1="18" y2="18"/>),
brush: %(<path d="m9.06 11.9 8.07-8.06a2.85 2.85 0 1 1 4.03 4.03l-8.06 8.08"/><path d="M7.07 14.94c-1.66 0-3 1.35-3 3.02 0 1.33-2.5 1.52-2 2.02 1.08 1.1 2.49 2.02 4 2.02 2.2 0 4-1.8 4-4.04a3.01 3.01 0 0 0-3-3.02z"/>),
images: %(<path d="M18 22H4a2 2 0 0 1-2-2V6"/><path d="m22 13-1.296-1.296a2.41 2.41 0 0 0-3.408 0L11 18"/><circle cx="12" cy="8" r="2"/><rect width="16" height="16" x="6" y="2" rx="2"/>),
library: %(<path d="m16 6 4 14"/><path d="M12 6v14"/><path d="M8 8v12"/><path d="M4 4v16"/>),
group: %(<path d="M3 7V5c0-1.1.9-2 2-2h2"/><path d="M17 3h2c1.1 0 2 .9 2 2v2"/><path d="M21 17v2c0 1.1-.9 2-2 2h-2"/><path d="M7 21H5c-1.1 0-2-.9-2-2v-2"/><rect width="7" height="5" x="7" y="7" rx="1"/><rect width="7" height="5" x="10" y="12" rx="1"/>),
tags: %(<path d="m15 5 6.3 6.3a2.4 2.4 0 0 1 0 3.4L17 19"/><path d="M9.586 5.586A2 2 0 0 0 8.172 5H3a1 1 0 0 0-1 1v5.172a2 2 0 0 0 .586 1.414L8.29 18.29a2.426 2.426 0 0 0 3.42 0l3.58-3.58a2.426 2.426 0 0 0 0-3.42z"/><circle cx="6.5" cy="9.5" r=".5" fill="currentColor"/>),
megaphone: %(<path d="m3 11 18-5v12L3 14v-3z"/><path d="M11.6 16.8a3 3 0 1 1-5.8-1.6"/>),
message_square: %(<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>),
lectern: %(<path d="M16 12h3a2 2 0 0 0 1.902-1.38l1.056-3.333A1 1 0 0 0 21 6H3a1 1 0 0 0-.958 1.287l1.056 3.334A2 2 0 0 0 5 12h3"/><path d="M18 6V3a1 1 0 0 0-1-1h-3"/><rect width="8" height="12" x="8" y="10" rx="1"/>),
swatch: %(<path d="M11 17a4 4 0 0 1-8 0V5a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2Z"/><path d="M16.7 13H19a2 2 0 0 1 2 2v4a2 2 0 0 1-2 2H7"/><path d="M 7 17h.01"/><path d="m11 8 2.3-2.3a2.4 2.4 0 0 1 3.404.004L18.6 7.6a2.4 2.4 0 0 1 .026 3.434L9.9 19.8"/>),
settings: %(<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/>),
log_in: %(<path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"/><polyline points="10 17 15 12 10 7"/><line x1="15" x2="3" y1="12" y2="12"/>),
# Pagination
chevron_left: %(<path d="m15 18-6-6 6-6"/>),
chevron_right: %(<path d="m9 18 6-6-6-6"/>),
ellipsis: %(<circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/>),
# Posts
fullscreen: %(<path d="M3 7V5a2 2 0 0 1 2-2h2"/><path d="M17 3h2a2 2 0 0 1 2 2v2"/><path d="M21 17v2a2 2 0 0 1-2 2h-2"/><path d="M7 21H5a2 2 0 0 1-2-2v-2"/><rect width="10" height="8" x="7" y="8" rx="1"/>),
}.freeze
def svg_icon(name, *args)
options = args.extract_options!
width = options[:width] || 24
height = options[:height] || 24
tag.svg(
"xmlns": "http://www.w3.org/2000/svg",
"width": width,
"height": height,
"viewbox": "0 0 24 24",
"fill": "none",
"stroke": "currentColor",
"stroke-width": 2,
"stroke-linecap": "round",
"stroke-linejoin": "round",
) do
raw(PATHS[name]) # rubocop:disable Rails/OutputSafety
end
end
end

View File

@ -2,17 +2,23 @@
module PaginationHelper
def sequential_paginator(records)
with_paginator_wrapper do
tag.div(class: "paginator") do
return "" if records.try(:none?)
html = "".html_safe
unless records.is_first_page?
html << tag.li(link_to("< Previous", nav_params_for("a#{records[0].id}"), rel: "prev", id: "paginator-prev", data: { shortcut: "a left" }))
# Previous
html << link_to(records.is_first_page? ? "#" : nav_params_for("a#{records[0].id}"), class: "prev", id: "paginator-prev", rel: "prev", data: { shortcut: "a left", disabled: records.is_first_page? }) do
concat svg_icon(:chevron_left)
concat tag.span("Prev")
end
unless records.is_last_page?
html << tag.li(link_to("Next >", nav_params_for("b#{records[-1].id}"), rel: "next", id: "paginator-next", data: { shortcut: "d right" }))
# Next
html << link_to(records.is_last_page? ? "#" : nav_params_for("b#{records[-1].id}"), class: "next", id: "paginator-next", rel: "next", data: { shortcut: "d right", disabled: records.is_last_page? }) do
concat tag.span("Next")
concat svg_icon(:chevron_right)
end
html
end
end
@ -22,64 +28,73 @@ module PaginationHelper
return sequential_paginator(records)
end
with_paginator_wrapper do
tag.div(class: "paginator", data: { total: [records.total_pages, records.max_numbered_pages].min, current: records.current_page }) do
html = "".html_safe
icon_left = tag.i(class: "fa-solid fa-chevron-left")
if records.current_page >= 2
html << tag.li(class: "arrow") { link_to(icon_left, nav_params_for(records.current_page - 1), rel: "prev", id: "paginator-prev", data: { shortcut: "a left" }) }
else
html << tag.li(class: "arrow") { tag.span(icon_left) }
# Previous
has_prev = records.current_page < 2
html << link_to(has_prev ? "#" : nav_params_for(records.current_page - 1), class: "prev", id: "paginator-prev", rel: "prev", data: { shortcut: "a left", disabled: has_prev }) do
concat svg_icon(:chevron_left)
concat tag.span("Prev")
end
paginator_pages(records).each do |page|
html << numbered_paginator_item(page, records)
# Break
html << tag.div(class: "break")
# Numbered
paginator_pages(records).each do |page, klass|
html << numbered_paginator_item(page, klass, records)
end
icon_right = tag.i(class: "fa-solid fa-chevron-right")
if records.current_page < records.total_pages
html << tag.li(class: "arrow") { link_to(icon_right, nav_params_for(records.current_page + 1), rel: "next", id: "paginator-next", data: { shortcut: "d right" }) }
else
html << tag.li(class: "arrow") { tag.span(icon_right) }
# Next
has_next = records.current_page >= records.total_pages
html << link_to(has_next ? "#" : nav_params_for(records.current_page + 1), class: "next", id: "paginator-next", rel: "next", data: { shortcut: "d right", disabled: has_next }) do
concat tag.span("Next")
concat svg_icon(:chevron_right)
end
html
end
end
private
def with_paginator_wrapper(&)
tag.div(class: "paginator") do
tag.menu(&)
end
end
def paginator_pages(records)
window = 4
small_window = 2
large_window = 4
last_page = [records.total_pages, records.max_numbered_pages].min
left = [2, records.current_page - window].max
right = [records.current_page + window, last_page - 1].min
left_sm = [2, records.current_page - small_window].max
left_lg = [2, records.current_page - large_window].max
right_sm = [records.current_page + small_window, last_page - 1].min
right_lg = [records.current_page + large_window, last_page - 1].min
small_range = left_sm..right_sm
[
1,
("..." unless left == 2),
(left..right).to_a,
("..." unless right == last_page - 1),
(last_page unless last_page <= 1),
].flatten.compact
result = [
[1, "first"],
]
result.push([0, "spacer"]) unless left_lg == 2
(left_lg..right_lg).each do |page|
result.push([page, small_range.member?(page) ? "sm" : "lg"])
end
result.push([0, "spacer"]) unless right_lg == last_page - 1
result.push([last_page, "last"]) unless last_page <= 1
result
end
def numbered_paginator_item(page, records)
def numbered_paginator_item(page, klass, records)
return "" if page.to_i > records.max_numbered_pages
html = "".html_safe
if page == "..."
html << tag.li(class: "more") { tag.i(class: "fa-solid fa-ellipsis") }
if page == 0
html << link_to(svg_icon(:ellipsis), nav_params_for(0), class: "spacer")
elsif page == records.current_page
html << tag.li(class: "current-page") { tag.span(page) }
html << tag.span(page, class: "page current")
else
html << tag.li(class: "numbered-page") { link_to(page, nav_params_for(page)) }
html << link_to(page, nav_params_for(page), class: "page #{klass}")
end
html
end

View File

@ -0,0 +1,43 @@
import Page from "./utility/page";
const Home = {};
Home.init = function () {
const $form = $("#home-search-form");
const $tags = $("#tags");
let isEmpty = !$tags.val();
let wasEmpty = isEmpty;
if (isEmpty) $form.addClass("empty");
$tags.on("input", () => {
wasEmpty = isEmpty;
isEmpty = !$tags.val();
if (isEmpty && !wasEmpty) $form.addClass("empty");
else if (!isEmpty && wasEmpty) $form.removeClass("empty");
});
$(".home-buttons a").on("click", (event) => {
if (isEmpty) return; // Act like regular links
event.preventDefault();
const extraTags = $(event.currentTarget).attr("tags");
if (extraTags) {
$tags.val((index, value) => {
return value + " " + extraTags;
});
}
$form.trigger("submit");
return false;
});
};
$(() => {
if (!Page.matches("static", "home")) return;
Home.init();
});
export default Home;

View File

@ -2,7 +2,7 @@ const Navigation = {};
Navigation.init = function () {
const wrapper = $("html");
$("#nav-toggle, .nav-offset-left, .nav-offset-bottom").on("click", (event) => {
$("#nav-toggle, .nav-offset-left, .nav-offset-bott").on("click", (event) => {
event.preventDefault();
wrapper.toggleClass("nav-toggled");

View File

@ -10,7 +10,6 @@ NewsUpdate.initialize = function () {
let newsOpen = false;
$("#news-header, #news-show").on("click", (event) => {
event.preventDefault();
console.log("click");
newsOpen = !newsOpen;
$("#news").toggleClass("open", newsOpen);

View File

@ -0,0 +1,19 @@
const Paginator = {};
Paginator.init_fasttravel = function (button) {
button.on("click", (event) => {
event.preventDefault();
const value = prompt("Navigate to page");
if (!value) return;
window.location.replace(button.attr("href").replace("page=0", "page=" + value));
});
};
$(() => {
for (const one of $(".paginator a.spacer").get())
Paginator.init_fasttravel($(one));
});
export default Paginator;

View File

@ -35,12 +35,10 @@ PostModeMenu.change_tag_script = function (e) {
e.preventDefault();
const newScriptID = Number(e.key);
console.log(newScriptID, LStorage.Posts.TagScript.ID);
if (!newScriptID || newScriptID == LStorage.Posts.TagScript.ID)
return;
LStorage.Posts.TagScript.ID = newScriptID;
console.log("settings", LStorage.Posts.TagScript.ID, LStorage.Posts.TagScript.Content);
$("#tag-script-field").val(LStorage.Posts.TagScript.Content);
PostModeMenu.show_notice(newScriptID);
};

View File

@ -1,4 +1,5 @@
import LStorage from "./utility/storage";
import Page from "./utility/page";
const PostSearch = {};
@ -10,6 +11,8 @@ PostSearch.init = function () {
$(".wiki-excerpt").each((index, element) => {
PostSearch.initialize_wiki_preview($(element));
});
PostSearch.initialize_controls();
};
PostSearch.initialize_input = function ($form) {
@ -39,21 +42,35 @@ PostSearch.initialize_input = function ($form) {
PostSearch.initialize_wiki_preview = function ($preview) {
let visible = LStorage.Posts.WikiExcerpt;
if (visible)
$preview.removeClass("hidden");
if (visible) $preview.addClass("open");
window.setTimeout(() => { // Disable the rollout on first load
$preview.removeClass("loading");
}, 250);
$($preview.find("a.wiki-excerpt-toggle")).on("click", (event) => {
$($preview.find("h3.wiki-excerpt-toggle")).on("click", (event) => {
event.preventDefault();
visible = !visible;
$preview.toggleClass("hidden", !visible);
$preview.toggleClass("open", visible);
LStorage.Posts.WikiExcerpt = visible;
return false;
});
};
PostSearch.initialize_controls = function () {
let fullscreen = LStorage.Posts.Fullscreen;
$("#search-fullscreen").on("click", () => {
fullscreen = !fullscreen;
$("body").attr("data-st-fullscreen", fullscreen);
LStorage.Posts.Fullscreen = fullscreen;
});
};
$(() => {
if (!Page.matches("posts", "index") && !Page.matches("favorites"))
return;
PostSearch.init();
});

View File

@ -28,6 +28,7 @@ Shortcuts.initialize_data_shortcuts = function () {
Shortcuts.keydown(keys, namespace, event => {
const e = $(`[data-shortcut="${keys}"]`).get(0);
if ($e.data("disabled")) return;
if ($e.is("input, textarea")) {
$e.trigger("focus").selectEnd();
} else {

View File

@ -3,7 +3,7 @@ import LStorage from "./utility/storage";
const Theme = {};
Theme.Values = ["Main", "Extra", "StickyHeader", "Palette", "Navbar", "Gestures"];
Theme.Values = ["Main", "Extra", "StickyHeader", "ForumNotif", "Palette", "Navbar", "Gestures"];
for (const one of Theme.Values) {
Object.defineProperty(Theme, one, {

View File

@ -8,6 +8,23 @@ Thumbnails.initialize = function () {
const posts = $(".post-thumb.placeholder, .thumb-placeholder-link");
const replacedPosts = [];
// Avatar special case
for (const post of $(".simple-avatar")) {
const $post = $(post);
const postID = $post.data("id");
if (!postID) continue;
const postData = postsData[postID];
if (!postData || !postData["preview_url"]) continue;
$("<img>")
.attr("src", postData["preview_url"])
.appendTo($post.find("span.simple-avatar-image"));
continue;
}
// Reset of the deferred posts
for (const post of posts) {
const $post = $(post);

View File

@ -65,6 +65,9 @@ LStorage.Theme = {
/** @returns {boolean} True if the sticky header is enabled */
StickyHeader: ["theme-sheader", false],
/** @returns {boolean} True if the forum notification dot is enabled */
ForumNotif: ["theme-forumnotif", false],
};
StorageUtils.bootstrapMany(LStorage.Theme);
@ -85,6 +88,9 @@ LStorage.Posts = {
/** @returns {boolean} True if the wiki excerpt should be visible */
WikiExcerpt: ["e6.posts.wiki", true],
/** @returns {boolean} True if the search should be displayed in fullscreen */
Fullscreen: ["e6.posts.fusk", false],
};
StorageUtils.bootstrapMany(LStorage.Posts);

View File

@ -9,6 +9,9 @@
@import "base/links";
@import "base/fontawesome";
@import "common/standard_variables";
@import "common/standard_elements";
@import "common/footer";
@import "common/helper_classes";
@import "common/helper_palette";

View File

@ -1,73 +1,84 @@
footer#page-footer {
display: grid;
grid-template-columns: 1fr 2fr;
gap: 0.5rem 0;
padding: 0.5rem 0 1rem;
margin: 1rem 0 0;
footer.footer-wrapper {
background: var(--color-foreground);
margin-top: 1rem;
.footer-grid {
display: grid;
grid-template-columns: min-content min-content;
grid-template-areas:
"logo . "
"left right";
justify-items: center;
gap: 0.5rem 0;
width: min-content;
margin: 0 auto;
padding: 1rem;
}
.footer-logo {
grid-area: logo;
width: 100%;
text-align: right;
img {
width: 5rem;
height: auto;
// Aligning the logo with the line below
margin-right: -3.25rem;
background: themed("color-background") themed("image-background");
border-radius: 50%;
padding: 0.5rem;
}
}
.footer-left, .footer-right {
display: flex;
flex-flow: column;
gap: 0.25em;
padding: 0 0.5rem;
font-size: 1.25em;
a, span {
line-height: 1.25em;
}
box-sizing: border-box;
width: 100%;
gap: 0.25rem;
font-size: 1rem;
a, span { white-space: nowrap; }
span { line-height: 1.25em; }
}
.footer-left {
align-items: end;
border-right: 1px solid var(--color-section);
grid-area: left;
padding-right: 1rem;
text-align: right;
border-right: 1px solid var(--color-section-lighten-5);
}
.footer-logo {
grid-column: 1 / -1;
grid-row: 1;
text-align: center;
img {
width: 5rem;
height: 5rem;
}
.footer-right {
grid-area: right;
padding-left: 1rem;
}
}
// Desktop
footer#page-footer {
@include window-larger-than(800px) {
grid-template-columns: 1fr min-content 1fr;
.footer-left, .footer-right {
font-size: unset;
flex-flow: row;
align-items: center;
border: 0;
gap: 0;
a:not(:last-child)::after {
content: "";
width: 4px;
height: 4px;
background: white;
display: inline-block;
border-radius: 2px;
margin: 0.125rem 0.5rem;
}
span.footer-running { display: none; }
// Desktop-ish
footer.footer-wrapper {
@include window-larger-than(450px) {
.footer-grid {
grid-template-areas: "logo left right";
padding: 1rem 0;
}
.footer-left { justify-content: right; }
.footer-logo {
grid-column: unset;
grid-row: unset;
display: flex;
align-items: center;
padding-right: 2rem;
box-sizing: border-box;
img {
width: 6rem;
margin-right: unset;
}
}
}
}
}

View File

@ -0,0 +1,59 @@
// Standard button
// Could be applied to either a button or a link
// Semi-expected to have an icon
.st-button {
$button-font-size: st-value(100);
$button-background: themed("color-section-lighten-5");
$button-background-hover: themed("color-section-lighten-10");
$button-text-color: themed("color-text");
display: flex;
gap: st-value(100) / 4;
border-radius: radius(025);
// Button final size
// Font 1rem
// Padding 2 * 0.5rem
font-size: st-value(100);
line-height: st-value(100);
padding: st-value(100) / 2;
height: st-value(100) * 2;
// TODO What if button is on a light background
background: $button-background;
color: $button-text-color;
&:hover { background: $button-background-hover; }
& > svg {
// Icon should be slightly larger than text,
// with padding to fill the entire button height
height: st-value(100) * 1.5; // 1.5rem
width: st-value(100) * 1.5; // 1.5rem
margin: -#{st-value(100) / 2} 0; // 0.5rem
padding: st-value(100) / 4; // 0.25rem
border-radius: radius(025);
}
& > span {
text-align: left;
// Do not overflow text
overflow: hidden;
flex: 1;
}
// Full width button
&.w100 { width: 100%; }
&.stealth {
background: none;
padding: (st-value(100) / 2) 0;
svg { background: $button-background; }
span { color: themed("color-link"); }
&:hover {
svg { background: $button-background-hover; }
span { color: themed("color-link-hover"); }
}
}
}

View File

@ -0,0 +1,21 @@
@use "sass:map";
// Standard variables for typography and UI elements
$st-values: (
000: 0rem,
025: 0.25rem,
050: 0.50rem,
075: 0.75rem,
100: 1rem,
);
@function st-value($name) {
@return map-get($map: $st-values, $key: $name);
}
@function padding($value) { @return st-value(($value)); }
@mixin st-padding($value) { padding: padding(($value)); }
@function radius($value) { @return st-value($value); }
@mixin st-radius($value) { border-radius: radius($value); }

View File

@ -6,6 +6,7 @@ nav.navigation {
width: 100%; // otherwise narrow when fixed
z-index: 20; // otherwise post labels layered above
position: relative;
/* Top bar, always visible */
@ -13,16 +14,18 @@ nav.navigation {
grid-area: logo;
background-color: themed("color-background");
height: 3.75rem;
a.nav-logo-link {
display: flex;
box-sizing: border-box;
// Height: 3.75rem
// - padding 0.25 * 2 = 0.5
// - image 3.25
height: 3.25rem;
width: 3.25rem;
margin: 0.25rem;
// - padding 0.125 * 2 = 0.25
// - image 3.5
height: 3.5rem;
width: 4rem;
margin: 0.125rem;
background-image: url("main-logo.svg");
background-repeat: no-repeat;
@ -37,160 +40,208 @@ nav.navigation {
display: flex;
flex-flow: row-reverse;
align-items: center;
gap: 0.5em;
font-size: 1.15rem;
padding-right: 0.5em;
background-color: themed("color-background");
padding-right: 0.25rem;
height: 3.75rem;
// Height: 3.75rem
// - wrapper padding 0.875 * 2 = 1.75
// - link padding 0.25 * 2 = 0.5
// - font size 1.5
padding: 0.875rem;
// - link padding 0.625 * 2 = 1.25
// - internal size 2.5
& > a {
display: flex;
gap: 0.25em;
padding: 0.625rem 0.5rem;
padding: 0.25rem 0.5rem;
background: themed("color-foreground");
border-radius: 6px;
& > span {
display: flex;
justify-content: center;
align-items: center;
box-sizing: border-box;
gap: 0.5rem;
height: 2.5rem;
min-width: 2.5rem;
line-height: 1.5rem;
padding: 0 0.5rem;
& > i {
font-size: 1.5rem;
background: themed("color-foreground");
color: themed("color-link-active");
border-radius: 0.25rem;
white-space: nowrap;
}
&:hover > span, &:active > span { background: themed("color-section"); }
&:focus { outline: none; }
}
a.simple-avatar {
.simple-avatar-button {
padding: 0;
gap: 0;
.simple-avatar-name {
padding: 0.5rem;
@include window-smaller-than(32rem) {
display: none;
}
}
.simple-avatar-image {
display: flex;
justify-content: center;
align-items: center;
position: relative;
width: 2.5rem;
height: 2.5rem;
box-sizing: border-box;
border-radius: 0.25rem;
background: themed("color-section");
img {
width: 2.5rem;
height: 2.5rem;
border-radius: 0.25rem;
object-fit: cover;
z-index: 1; // above the letter
}
&::before {
content: attr(data-name);
position: absolute;
font-size: 1.5rem;
}
}
@include window-smaller-than(32rem) {
&.sign-in .simple-avatar-image {
background: themed("color-foreground");
}
}
}
}
}
/* Prevent toggled menus from being too wide */
.nav-offset-left {
grid-area: offleft;
display: none; // flex
background: #00000050;
}
.nav-offset-bottom {
grid-area: offbott;
display: none; // flex
background: #00000050;
/* Offset elements on the left and bottom */
// Needed to track clicks outside the menu area
@each $name in ("left", "bott") {
.nav-offset-#{$name} {
grid-area: off#{$name};
display: none; // flex
background: #00000050;
}
}
/* Toggled menus, hidden by default */
.nav-primary {
grid-area: primary;
display: none; // flex
flex-flow: column;
// Naming areas
@each $name in (primary, secondary, tools, help) {
.nav-#{$name} {
grid-area: $name;
display: none;
background-color: themed("color-section");
font-size: 1.5em;
li {
padding: 0;
li {
padding: 0;
a {
display: block;
border-bottom: 1px solid themed("color-foreground");
padding: 0.5em;
& > a {
display: flex;
align-items: center;
gap: 0.5rem;
// "Comments" is usually the longest and might wrap
white-space: nowrap;
white-space: nowrap;
i {
width: 1.5rem;
color: themed("color-link-active");
text-align: center;
}
}
&.current a { background-color: themed("color-foreground"); }
&.forum-updated {
position: relative;
&::after {
content: "";
width: 6px;
height: 6px;
border-radius: 3px;
background: var(--palette-text-red);
position: absolute;
right: 0.2em;
top: 1em;
svg {
margin: -0.25rem 0;
color: themed("color-link-active");
}
}
}
}
}
.nav-secondary {
grid-area: secondary;
display: none; // flex
// Common top
.nav-primary, .nav-secondary {
flex-flow: column;
background-color: themed("color-foreground");
font-size: 1.35em;
height: 440px;
// Prevent the tools / help buttons from being pushed
// way too low on pages with a lot of secondary links
overflow: scroll;
height: 422px;
overflow-y: scroll;
li a {
justify-content: start;
}
}
.nav-primary {
background-color: themed("color-section");
font-size: 1.25rem;
li > a {
border-bottom: 1px solid themed("color-foreground");
line-height: 1.25rem;
padding: 1rem 0.5rem;
}
li.current a { background-color: themed("color-foreground"); }
}
.nav-secondary {
background-color: themed("color-foreground");
font-size: 1.2rem;
li {
padding: 0;
a {
display: block;
& > a {
border-bottom: 1px solid themed("color-section");
padding: 0.5em;
line-height: 1.2rem;
padding: 0.7rem;
white-space: wrap; // forum menus are long
}
&.divider {
border-bottom: 1px solid themed("color-section");
height: 0.25em;
height: 0.25rem;
}
form input[type="text"] {
width: 100%;
box-sizing: border-box;
// Reduced font size to make the search
// box less claustrophobic
font-size: 1em;
padding: 0.25em 0.5em;
font-size: 1.25rem;
padding: 0.5rem 0.5rem;
}
}
}
.nav-tools {
grid-area: tools;
display: none; // grid
grid-template-columns: 1fr 1fr;
// Common bottom
.nav-tools, .nav-help {
grid-template-rows: min-content;
padding: 1rem;
font-size: 1.1rem;
gap: 1rem;
background-color: themed("color-section");
li > a {
justify-content: center;
border-radius: 0.25rem;
padding: 0.7rem 1rem;
line-height: 1.1rem;
}
}
.nav-tools {
grid-template-columns: 1fr 1fr;
border-top: 1px solid themed("color-foreground");
padding: 1rem 1rem 0.5rem;
li {
padding: 0;
a { background: themed("color-section-lighten-5"); }
&.nav-tools-login { grid-column: 1 / -1; }
& > a {
display: block;
background: themed("color-section-lighten-5");
border-radius: 6px;
font-size: 125%;
padding: 0.5rem 1rem;
text-align: center;
i { color: themed("color-link-active"); }
}
}
&.anonymous li.nav-tools-themes {
@ -199,42 +250,19 @@ nav.navigation {
}
.nav-help {
grid-area: help;
display: none; // grid
grid-template-columns: 1fr 1fr 1fr;
grid-template-rows: min-content;
padding: 1rem;
gap: 1rem;
background: themed("color-section");
padding: 0.5rem 1rem 1rem;
li {
padding: 0;
a { background: themed("color-section-darken-5"); }
&.nav-help-discord,
&.nav-help-subscribestar {
grid-column: 1 / -1;
}
& > a {
display: flex;
background: themed("color-section-darken-5");
border-radius: 6px;
font-size: 125%;
padding: 0.5rem 1rem;
justify-content: center;
align-items: center;
gap: 0.25em;
img {
height: 1.25em;
margin: -0.5em 0;
}
& > a img {
height: 1.5rem;
margin: -0.2rem 0;
}
// Hack to put the wiki/help links before discord/sstar on mobile
@ -255,6 +283,29 @@ body[data-th-sheader="true"] nav.navigation {
}
// Forum notification
body[data-th-forumnotif="true"] nav.navigation .nav-primary li.forum-updated {
position: relative;
&::after {
content: "";
width: 6px;
height: 6px;
border-radius: 3px;
background: palette("text-red");
position: absolute;
right: 0.2rem;
top: 1.25rem;
@include window-larger-than(800px) {
top: 0.2rem;
}
}
}
// Mobile toggle
html.nav-toggled {
@ -279,14 +330,14 @@ html.nav-toggled {
// Allow scrolling when the menu is too long
overflow-y: scroll;
.nav-primary, .nav-secondary, .nav-offset-left, .nav-offset-bottom {
.nav-primary, .nav-secondary, .nav-offset-left, .nav-offset-bott {
display: flex;
}
.nav-tools, .nav-help {
display: grid;
}
.nav-primary, .nav-tools, .nav-help {
box-shadow: -1px 0 5px -1px var(--color-background);
box-shadow: -3px 3px 5px -1px themed("color-background");
}
}
}
@ -294,74 +345,68 @@ html.nav-toggled {
// Desktop
nav.navigation, html.nav-toggled nav.navigation {
@include window-larger-than(800px) {
@include window-larger-than(50rem) {
grid-template-areas:
"logo primary help tools "
"logo secondary secondary secondary"
;
grid-template-columns: min-content min-content minmax(0, 1fr) min-content;
grid-template-rows: 1.75em 2em;
"logo primary help help controls"
"logo secondary secondary tools controls";
grid-template-columns: min-content min-content minmax(0, 1fr) min-content 3.25rem;
grid-template-rows: 1.5rem 1.75rem;
padding: 0 1em 0.5em;
padding: 0 1rem 0.5rem;
box-sizing: border-box;
height: unset;
background: var(--color-background);
background: themed("color-background");
overflow-y: hidden; // overrides mobile hack allowing the menu scrolling
.nav-logo {
a.nav-logo-link { margin: 0.25rem 0.5rem 0 0; }
.nav-logo a.nav-logo-link {
height: 3.25rem;
width: 3.25rem;
margin: 0.25rem 0.5rem 0 0;
}
.nav-offset-left, .nav-offset-bottom, .nav-controls { display: none; }
.mobile { display: none; }
.nav-primary {
// All link ribbons
.desktop {
display: flex;
flex-flow: row;
background: unset;
font-size: 1.05em;
padding: 0 0.25em;
font-size: 0.875rem;
box-shadow: unset;
li {
li a {
display: flex;
align-items: center;
height: 100%;
a {
align-content: center;
padding: 0 0.625rem;
white-space: nowrap;
}
}
border-bottom: 0;
padding: 0 0.75em;
i { display: none; }
}
.nav-primary {
background: unset;
height: unset;
padding-left: 0.25rem;
&.forum-updated::after {
top: 0.2em;
}
li a {
border-bottom: 0;
svg { display: none; }
}
}
.nav-secondary {
display: flex;
flex-flow: row;
height: unset;
padding: 0 0.25em;
font-size: 1.05em;
border-radius: 6px;
padding: 0 0.25rem;
border-radius: 0.25rem 0 0 0.25rem;
// Silly fix for too many links
overflow: hidden;
overflow: hidden; // Silly fix for too many links
z-index: 1; // above the avatar
li {
display: flex;
a {
align-content: center;
border-bottom: 0;
padding: 0 0.75em;
white-space: nowrap;
}
a { border-bottom: 0; }
&.divider {
display: flex;
@ -371,50 +416,46 @@ nav.navigation, html.nav-toggled nav.navigation {
&::after { content: "|"; }
}
form {
display: flex;
align-items: center;
input[type="text"] { min-width: 10em; }
form input[type="text"] {
width: 12rem;
padding: 0.25rem 0.5rem;
font-size: 1rem;
border-radius: 0.25rem;
}
}
}
.nav-tools, .nav-help {
display: flex;
padding: 0;
background: unset;
border: none;
gap: 0;
li {
display: flex;
li a {
gap: 0.25rem;
a {
align-content: center;
background: unset;
font-size: 1.05em;
padding: 0 0.75em;
text-align: unset;
white-space: nowrap;
border-radius: 0;
}
background: unset;
text-align: unset;
border-radius: 0;
}
}
.nav-tools {
// Otherwise help gets layered above it
// When the viewport is narrow (but not mobile)
background: themed("color-foreground");
z-index: 1;
background: var(--color-background);
border-radius: 0 0.25rem 0.25rem 0;
margin-right: 0.25rem;
li {
a {
i { color: themed("color-link"); }
&:hover i { color: themed("color-link-hover"); }
padding: 0 0.5rem;
svg {
color: themed("color-link");
height: 1.25rem;
width: 1.25rem;
}
&:hover svg { color: themed("color-link-hover"); }
}
&.nav-tools-themes, &.nav-tools-settings {
@ -422,26 +463,123 @@ nav.navigation, html.nav-toggled nav.navigation {
}
}
}
.nav-help {
li a img { display: none; }
.nav-help {
// At small resolutions, overflow can
// cause scrollbars to appear
overflow: hidden;
li a img { display: none; }
li.current a {
background-color: themed("color-foreground");
}
}
.nav-primary, .nav-tools, .nav-help { box-shadow: unset; }
.nav-controls {
position: absolute;
right: 0;
top: 0;
height: 3.25rem;
box-sizing: border-box;
padding: 0.25rem 0 0;
#nav-toggle { display: none; }
a.simple-avatar {
padding: 0;
height: 100%;
.simple-avatar-button {
background: none;
color: inherit;
align-items: start;
font-size: 0.875rem;
line-height: 0.875rem;
.simple-avatar-name {
padding: 0 0.5rem;
}
.simple-avatar-image {
height: 3rem;
width: 3rem;
background: themed("color-foreground");
img {
width: 2.75rem;
height: 2.75rem;
}
}
}
}
}
// Icon collapse
// Stage 1: discord and subscribestar buttons
.collapse-1 { display: none; }
@include window-larger-than(77rem) {
.collapse-1 { display: flex; }
}
// Stage 2: account label
.collapse-2 .simple-avatar-name { display: none; }
@include window-larger-than(65rem) {
.collapse-2 .simple-avatar-name { display: unset; }
}
}
}
// Tweak for the secondary menu on desktop
body.c-static.a-home {
@include window-larger-than(800px) {
nav.navigation, menu.nav-logo, menu.nav-secondary {
@include window-larger-than(50rem) {
nav.navigation {
// Center and align the navbar
grid-template-areas: "logo primary help controls";
grid-template-columns: repeat(4, min-content);
justify-content: center;
// Remove padding to prevent a scrollbar
// at low desktop resolutions
padding: 0 0 0.5rem;
#nav-subscribestar, #nav-discord, .nav-secondary, .nav-tools { display: none; }
}
// Match the background colors
nav.navigation, menu.nav-logo, menu.nav-secondary, menu.nav-controls {
background: unset;
}
menu.nav-tools {
background: var(--bg-color);
}
menu.nav-controls {
position: static;
height: unset;
padding: 0;
.simple-avatar-button {
height: unset;
align-items: center;
.simple-avatar-image { display: none; }
}
}
}
@include window-smaller-than(50rem) {
// Only show the primary navbar on mobile
// since the secondary is empty anyways
nav.navigation {
grid-template-areas:
"logo logo controls"
"offleft primary primary "
"offleft tools tools "
"offleft help help "
"offleft offbott offbott ";
.nav-secondary { display: none; }
}
}
}

View File

@ -17,6 +17,8 @@ div#page div#news {
&.open {
max-height: none;
#news-body { pointer-events: unset; }
}
#news-header {
@ -26,26 +28,27 @@ div#page div#news {
cursor: pointer;
width: 100%;
text-align: center;
padding: 0.5rem 0.5rem 0;
padding: 0.5rem;
}
#news-body {
display: block;
box-sizing: border-box;
margin-top: 5px;
max-width: 800px;
padding: 0 0.5rem 0.5rem;
pointer-events: none;
}
#news-dismiss {
position: absolute;
right: 0.5rem;
top: 0.25rem;
right: 0;
top: 0;
padding: 0.25rem 1rem;
cursor: pointer;
font-size: 1.15rem;
font-size: 1.25rem;
font-weight: bold;
color: white;
}
}

View File

@ -1,35 +1,101 @@
.paginator {
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
background-color: themed("color-foreground");
border-radius: 0.25rem;
div.paginator {
display: block;
padding: 2em 0 1em 0;
text-align: center;
clear: both;
width: max-content;
margin: 0 auto;
menu {
& > a, & > span {
display: flex;
box-sizing: border-box;
justify-content: center;
align-items: center;
min-width: 2.15rem;
font-size: 1rem;
line-height: 1rem;
padding: 0.75rem 0.3rem; // otherwise large page numbers wrap
border-radius: 0.25rem;
&:hover {
background: themed("color-section");
}
}
li {
a {
margin: 0 0.25em;
padding: 0.25em 0.75em;
& > a[data-disabled="true"] {
color: var(--color-text);
pointer-events: none;
}
// Ordering
// Oh boy
.page {
order: 20;
&.lg { display: none; }
&.current { cursor: default; }
}
.prev {
order: 1;
margin-right: auto;
}
.spacer {
order: 20;
padding: 0;
&:last-child { display: none; }
svg {
height: 1rem;
transform: rotate(90deg);
}
}
.next {
order: 9;
margin-left: auto;
}
.break {
order: 10;
width: 100%;
}
// Tablet
@include window-larger-than(35rem) {
justify-content: center;
gap: 0.125rem;
a, span {
order: 0 !important;
min-width: 2.25rem;
font-size: 0.9rem;
}
a:hover {
background: $paginator-hover-background;
color: $paginator-hover-color;
.break { display: none; }
.spacer {
padding: inherit;
svg { transform: unset; }
}
&.more {
color: $paginator-more-color;
.prev { margin-right: 1rem; }
.next { margin-left: 1rem; }
}
@include window-larger-than(50rem) {
a, span {
padding: 0.75rem 0.5rem;
font-size: 0.95rem;
}
span {
margin: 0 0.25em;
padding: 0.25em 0.75em;
font-weight: bold;
.prev, .next {
span { display: none; }
}
}
@include window-larger-than(65rem) {
a.page.lg { display: flex; }
}
}

View File

@ -59,14 +59,6 @@
}
}
.guest-warning {
.guest-warning-dialog {
top: 5vh;
height: 90vh;
width: 80vw;
}
}
div#page {
> div /* div#c-$controller */

View File

@ -1,33 +1,55 @@
.guest-warning {
position: fixed;
left: 0;
top: 0;
height: 100vh;
width: 100vw;
z-index: 500;
background-color: themed("color-background");
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
display: flex;
justify-content: center;
background: themed("color-background");
.guest-warning-dialog {
z-index: 500;
position: relative;
top: 20vh;
margin-left: auto;
margin-right: auto;
height: 40vh;
width: 40vw;
overflow-x: scroll;
background-color: themed("color-section");
margin: 20vh 0.5em 0;
height: min-content;
max-width: 360px;
.dialog-header {
padding: $padding-050 $base-padding;
background-color: themed("color-section-lighten-5");
border-bottom: 1px solid themed("color-background");
padding: 0 0.5em;
margin-bottom: 0.5em;
}
.dialog-content {
padding: $padding-050 $base-padding;
background: var(--color-foreground);
padding: 2em 1em 1em;
border-radius: 3px 3px 0 0;
p:last-child { margin-bottom: 0; }
}
.dialog-footer {
padding: $padding-050 $base-padding;
display: flex;
flex-wrap: wrap;
gap: 0.5em;
background: var(--color-foreground);
padding: 1em 1em 2em;
border-radius: 0 0 3px 3px;
button {
background: var(--color-section-lighten-5);
color: var(--color-link);
padding: 0.5em 1em;
border-radius: 3px;
&:hover {
background: var(--color-section-lighten-10);
color: var(--color-link-hover);
}
}
}
}
}

View File

@ -3,6 +3,12 @@ body.c-static.a-home {
background-color: var(--bg-color);
background-image: var(--bg-image);
background-position-y: 3.75rem;
@include window-larger-than(800px) {
background-position-y: unset;
}
#page {
background: none;
margin: 8rem auto 0;
@ -20,7 +26,7 @@ body.c-static.a-home {
padding: 1rem;
margin: 0.5rem;
border-radius: 0.5rem;
border-radius: 0.25rem;
text-align: center;
}
@ -73,6 +79,10 @@ body.c-static.a-home {
}
}
#home-search-form:not(.empty) .home-buttons a span::before {
content: "Search ";
}
// Footer
.home-footer-top {
@ -86,7 +96,7 @@ body.c-static.a-home {
justify-content: space-between;
align-items: center;
border-radius: 0.5rem 0.5rem 0 0;
border-radius: 0.25rem 0.25rem 0 0;
@include window-larger-than(480px) {
margin: 0.5rem 0.5rem 0;
@ -109,7 +119,7 @@ body.c-static.a-home {
margin: 0;
padding: 0.5rem;
border-radius: 0 0 0.5rem 0.5rem;
border-radius: 0 0 0.25rem 0.25rem;
@include window-larger-than(480px) {
margin: 0 0.5rem;

View File

@ -1,3 +1,22 @@
body.c-posts.a-index, body.c-favorites.a-index {
#page {
// Override the theme to instead
// project it upon the content area
background: none;
padding: 0;
}
// Exhibit A
// Makes the content area take up the
// full height of the page. Yes, really.
#page, #c-posts, #c-favorites, #a-index {
// I hate both this and myself
display: flex;
flex-flow: column;
flex: 1;
}
}
.post-index {
display: grid;
@ -7,24 +26,46 @@
"sidebar";
grid-template-columns: 1fr;
grid-template-rows: min-content 1fr min-content;
gap: 1em;
flex: 1; // See Exhibit A
// 1. Searchbox
.search {
grid-area: search;
padding: 0.5rem 0.25rem;
background-color: #152f56;
background-color: themed("color-foreground");
box-shadow: inset 0px -0.25rem 0.25rem -0.25rem themed("color-background");
h1 {
font-size: $h3-size;
}
.search-controls {
display: none;
flex-flow: column;
}
}
// 2. Content
.content {
display: flex; // See Exhibit A
flex-flow: column;
grid-area: content;
// Imported from #page
padding: 0.5rem 0.25rem themed("content-padding-bottom");
background-color: #152f56;
background-color: themed("color-foreground");
background-image: themed("image-foreground");
background-position: themed("image-foreground-position");
background-repeat: themed("image-foreground-repeat");
// Quick tag edit
#edit-dialog textarea {
margin-bottom: 0.25em;
margin-bottom: 0.25rem;
}
// Actual content area:
@ -32,86 +73,13 @@
.post-index-gallery {
display: flex;
flex-flow: column;
gap: 1em;
gap: 1rem;
.wiki-excerpt {
display: flex;
flex-flow: column;
position: relative;
padding: 1em 1em 0;
gap: 0.5em;
flex: 1; // See Exhibit A
background: var(--color-section);
max-width: 60em;
.wiki-excerpt-toggle {
position: absolute;
top: 0;
right: 0;
padding: 1em;
outline: none;
transition: transform 0.25s;
&::after {
@include font-awesome-icon;
content: unicode("f0d8");
}
}
.styled-dtext {
background: linear-gradient(to top, var(--color-section), var(--color-text));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
max-height: 10em;
overflow: hidden;
transition: max-height 0.25s;
// Disable links
pointer-events: none;
cursor: unset;
a {
color: unset;
text-decoration: underline;
&::after { content: none; }
}
}
.wiki-excerpt-readmore {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 3em;
// Makes the button appear in the middle of the animation
transition: visibility 0s 0.125s;
span {
padding: 0.5em 1em;
background: var(--color-section);
border-radius: 6px;
}
}
&.hidden{
.wiki-excerpt-toggle { transform: rotate(-90deg); }
.styled-dtext {
max-height: 0;
}
.wiki-excerpt-readmore { visibility: hidden; }
}
}
.paginator {
padding: 1em 0;
.posts-container {
flex: 1; // See Exhibit A
grid-auto-rows: min-content;
}
}
}
@ -124,6 +92,11 @@
flex-flow: column;
gap: 1em;
padding: 0.5rem 0.25rem;
background-color: #152f56;
background-color: themed("color-foreground");
box-shadow: inset 0px 0.25rem 0.25rem -0.25rem themed("color-background");
// Mode selection
#mode-box-mode, #mode-box #set-id {
width: 100%;
@ -139,11 +112,170 @@
// Desktop
.post-index {
@include window-larger-than(800px) {
@include window-larger-than(50rem) {
grid-template-areas:
"search content"
"sidebar content";
grid-template-columns: 15em 1fr;
grid-template-columns: 14rem 1fr;
grid-template-rows: min-content 1fr;
.search {
box-shadow: inset -0.25rem 0px 0.25rem -0.25rem themed("color-background");
margin-top: 0.25rem;
border-top-left-radius: 0.25rem;
padding: 0.5rem;
.search-controls {
display: flex;
margin-top: 0.5rem;
}
}
.sidebar {
box-shadow: inset -0.25rem 0px 0.25rem -0.25rem themed("color-background");
margin-bottom: 0.25rem;
border-bottom-left-radius: 0.25rem;
padding: 0.5rem
}
.content {
border-radius: 0.25rem;
}
}
}
// Fullscreen
body.c-posts.a-index[data-st-fullscreen="true"] {
// Desktop-only, for obvious reasons
@include window-larger-than(50rem) {
.post-index {
grid-template-areas:
"search "
"content";
grid-template-columns: 1fr;
.search {
display: flex;
border-radius: 0.25rem 0.25rem 0 0;
box-shadow: inset 0px -0.25rem 0.25rem -0.25rem themed("color-background");
.post-search {
flex: 1;
}
.search-controls {
display: flex;
justify-content: right;
align-self: end;
margin: 0 0 0 0.5rem;
.st-button.w100 {
width: unset;
span { display: none; }
}
}
}
.sidebar { display: none; }
.content {
border-radius: 0 0 0.25rem 0.25rem;
}
}
}
}
// FEATURES
// Wiki Excerpt
.wiki-excerpt {
display: flex;
flex-flow: column;
position: relative;
background: themed("color-section");
border-radius: 0.25rem;
// header
h3 {
cursor: pointer;
padding: 0.5rem 1rem 0.5rem 1.5rem;
&::after {
@include font-awesome-icon;
content: unicode("f0da");
transition: transform 0.25s;
position: absolute;
top: 0;
left: 0;
padding: 0.5rem;
}
}
// body
.styled-dtext {
background: linear-gradient(to top, themed("color-section"), themed("color-text"));
-webkit-background-clip: text;
background-clip: text;
color: transparent;
max-height: 0rem;
max-width: 50rem;
overflow: hidden;
padding: 0 0.5rem;
transition: max-height 0.25s;
// Disable links
pointer-events: none;
cursor: unset;
a {
color: unset;
text-decoration: underline;
&::after { content: none; }
}
p:last-child { margin-bottom: 0; }
}
// wiki link
.wiki-excerpt-readmore {
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 3rem;
max-width: 50rem;
box-sizing: border-box;
// Makes the button appear in the middle of the animation
transition: visibility 0s 0.125s;
visibility: hidden;
span {
padding: 0.5rem 1rem;
background: themed("color-section");
border-radius: 0.25rem;
}
}
&.open{
.wiki-excerpt-toggle::after { transform: rotate(90deg); }
.styled-dtext {
max-height: 10rem;
}
.wiki-excerpt-readmore { visibility: visible; }
}
&.loading {
h3::after, .styled-dtext { transition: none; }
}
}

View File

@ -20,7 +20,7 @@ $modes: (
);
@each $mode, $color in $modes {
#page[data-mode-menu="#{$mode}"] {
#page[data-mode-menu="#{$mode}"] .content {
background-color: $color;
}
}

View File

@ -2,6 +2,7 @@
#has-parent-relationship-preview, #has-children-relationship-preview {
display: flex;
flex-direction: row;
flex-wrap: wrap;

View File

@ -1,20 +1,12 @@
div#c-static {
div#a-site-map {
width: 80em;
display: flex;
flex-flow: row wrap;
max-width: 80em;
section {
width: 20em;
float: left;
h1 {
font-size: $h3-size;
}
ul {
margin-bottom: 1.5em;
}
ul { margin-bottom: 1.5em; }
}
}
}

View File

@ -249,8 +249,9 @@ div#c-users {
div.input {
input[type="text"], input[type="email"], input[type="password"], select {
width: 100%;
max-width: unset;
// z_responsive is the absolute worst
width: 100% !important;
max-width: unset !important;
box-sizing: border-box;
}
}

View File

@ -3,18 +3,27 @@
module GitHelper
def self.init
if Rails.root.join("REVISION").exist?
@hash = Rails.root.join("REVISION").read.strip
@hash = @tag = Rails.root.join("REVISION").read.strip
elsif system("type git > /dev/null && git rev-parse --show-toplevel > /dev/null")
@hash = `git rev-parse HEAD`.strip
@tag = `git describe --abbrev=0`
else
@hash = ""
@hash = @tag = ""
end
end
def self.tag
@tag
end
def self.hash
@hash
end
def self.version
@tag.presence || short_hash
end
def self.short_hash
@hash[0..8]
end
@ -22,4 +31,13 @@ module GitHelper
def self.commit_url(commit_hash)
"#{Danbooru.config.source_code_url}/commit/#{commit_hash}"
end
def self.release_url(tag_name)
"#{Danbooru.config.source_code_url}/releases/tag/#{tag_name}"
end
def self.version_url
return release_url(@tag) if @tag.present?
commit_url(@hash)
end
end

View File

@ -38,9 +38,6 @@ class UserFeedback < ApplicationRecord
def log_destroy
ModAction.log(:user_feedback_destroy, { user_id: user_id, reason: body, type: category, record_id: id })
deletion_user = "\"#{CurrentUser.name}\":/users/#{CurrentUser.id}"
creator_user = "\"#{creator.name}\":/users/#{creator.id}"
StaffNote.create(body: "#{deletion_user} deleted #{category} feedback, created #{created_at.to_date} by #{creator_user}: #{body}", user_id: user_id, creator: User.system)
end
end

View File

@ -1,4 +1,4 @@
<% if comment.should_see?(CurrentUser.user) || (current_page?(:controller => "comments", :action => "show") && CurrentUser.id == comment.creator_id) %>
<% if comment.should_see?(CurrentUser.user) || (params[:controller] == "comments" && params[:action] == "show" && CurrentUser.id == comment.creator_id) %>
<article class="comment comment-post-grid <%= "below-threshold" if comment.below_threshold? %>" data-post-id="<%= comment.post_id %>"
data-comment-id="<%= comment.id %>" data-score="<%= comment.score %>"
data-creator="<%= comment.creator&.name.downcase %>" data-is-sticky="<%= comment.is_sticky %>" data-creator-id="<%= comment.creator_id %>"

View File

@ -1,7 +1,8 @@
<%= decorated_nav_link_to("Posts", "fas fa-images", posts_path) %>
<%= decorated_nav_link_to("Pools", "fas fa-book", gallery_pools_path) %>
<%= decorated_nav_link_to("Sets", "fas fa-clone", post_sets_path) %>
<%= decorated_nav_link_to("Tags", "fas fa-tags", tags_path) %>
<%= decorated_nav_link_to("Blips", "fas fa-bullhorn", blips_path) %>
<%= decorated_nav_link_to("Comments", "fas fa-comment-alt", comments_path(group_by: "post")) %>
<%= decorated_nav_link_to("Forum", "fas fa-chalkboard", forum_topics_path, class: (CurrentUser.has_forum_been_updated? ? "forum-updated" : nil)) %>
<%= decorated_nav_link_to("Artists", :brush, artists_path) %>
<%= decorated_nav_link_to("Posts", :images, posts_path) %>
<%= decorated_nav_link_to("Pools", :library, gallery_pools_path) %>
<%= decorated_nav_link_to("Sets", :group, post_sets_path) %>
<%= decorated_nav_link_to("Tags", :tags, tags_path) %>
<%= decorated_nav_link_to("Blips", :megaphone, blips_path) %>
<%= decorated_nav_link_to("Comments", :message_square, comments_path(group_by: "post")) %>
<%= decorated_nav_link_to("Forum", :lectern, forum_topics_path, class: (CurrentUser.has_forum_been_updated? ? "forum-updated" : nil)) %>

View File

@ -3,45 +3,45 @@
<a href="/" class="nav-logo-link"></a>
</menu>
<menu class="nav-primary">
<menu class="nav-primary desktop">
<%= render "layouts/main_links" %>
</menu>
<menu class="nav-offset-left"></menu>
<menu class="nav-offset-bottom"></menu>
<menu class="nav-offset-left mobile"></menu>
<menu class="nav-offset-bott mobile"></menu>
<menu class="nav-secondary <%= "empty" unless content_for(:secondary_links) %>">
<menu class="nav-secondary desktop <%= "empty" unless content_for(:secondary_links) %>">
<%= yield :secondary_links %>
</menu>
<menu class="nav-controls">
<a href="" id="nav-toggle">
<i class="fas fa-bars"></i>
<menu class="nav-controls desktop">
<a role="button" href="" id="nav-toggle" class="nav-controls-toggle">
<span><%= svg_icon(:hamburger) %></span>
</a>
<% if CurrentUser.is_anonymous? %>
<%= link_to(new_session_path, class: "nav-tools-login") do %>
<i class="fas fa-sign-in-alt"></i>
Sign in
<% end %>
<a href="<%= new_session_path %>" class="simple-avatar nav-controls-profile collapse-2">
<span class="simple-avatar-button sign-in">
<span class="simple-avatar-name">
Sign In
</span>
<span class="simple-avatar-image">
<%= svg_icon(:log_in) %>
</span>
</span>
</a>
<% else %>
<%= link_to(user_path(CurrentUser.user), class: "nav-tools-login") do %>
<i class="far fa-user-circle"></i>
Profile
<% end %>
<%= simple_avatar(CurrentUser.user, named: true, class: "nav-controls-profile collapse-2") %>
<% end %>
</menu>
<menu class="nav-tools <%= CurrentUser.is_anonymous? ? "anonymous" : "" %>">
<%= decorated_nav_link_to("Themes", "fas fa-swatchbook", theme_path, class: "nav-tools-themes") %>
<% if CurrentUser.is_anonymous? %>
<%= decorated_nav_link_to("Sign in", "fas fa-sign-in-alt", new_session_path, class: "nav-tools-login") %>
<% else %>
<%= decorated_nav_link_to("Settings", "fas fa-cog", edit_user_path(CurrentUser.user), class: "nav-tools-settings") %>
<%= decorated_nav_link_to("Account #{unread_dmails(CurrentUser.user)}", "far fa-user-circle", home_users_path, class: "nav-tools-login") %>
<menu class="nav-tools desktop <%= CurrentUser.is_anonymous? ? "anonymous" : "" %>">
<%= decorated_nav_link_to("Themes", :swatch, theme_path, class: "nav-tools-themes") %>
<% unless CurrentUser.is_anonymous? %>
<%= decorated_nav_link_to("Settings", :settings, edit_user_path(CurrentUser.user), class: "nav-tools-settings") %>
<% end %>
</menu>
<menu class="nav-help <%= CurrentUser.is_anonymous? ? "anonymous" : "" %>">
<menu class="nav-help desktop <%= CurrentUser.is_anonymous? ? "anonymous" : "" %>">
<%= nav_link_to("Wiki", wiki_pages_path(title: "help:home"), class: "nav-help-wiki") %>
<%= nav_link_to("Help", help_pages_path, class: "nav-help-help") %>
<%= nav_link_to("More", site_map_path, class: "nav-help-map") %>

View File

@ -1,17 +1,23 @@
<%= javascript_tag nonce: true do -%>
(function() {
try {
var theme = localStorage.getItem('theme') || 'hexagon';
var extra = localStorage.getItem('theme-extra') || 'none';
var sheader = localStorage.getItem('theme-sheader') || false;
var palette = localStorage.getItem('theme-palette') || 'default';
var nav = localStorage.getItem('theme-nav') || 'top';
const values = {
// Theme
"th-main": localStorage.getItem("theme") || "hexagon",
"th-extra": localStorage.getItem("theme-extra") || "none",
"th-sheader": localStorage.getItem("theme-sheader") || false,
"th-forumnotif": localStorage.getItem("theme-forumnotif") || false,
"th-palette": localStorage.getItem("theme-palette") || "default",
"th-nav": localStorage.getItem("theme-nav") || "top",
// Settings
"st-fullscreen": localStorage.getItem("e6.posts.fusk") || false,
};
var b = document.body;
b.setAttribute('data-th-main', theme);
b.setAttribute('data-th-extra', extra);
b.setAttribute('data-th-sheader', sheader);
b.setAttribute('data-th-palette', palette);
b.setAttribute('data-th-nav', nav);
for (const [name, value] of Object.entries(values)) {
b.setAttribute("data-" + name, value);
}
} catch(e) {}
})();
<% end -%>

View File

@ -10,8 +10,11 @@
<% if CurrentUser.is_anonymous? %>
<%= render "static/guest_warning" %>
<% end %>
<div id="page">
<%= yield :layout %>
</div>
<%= render "static/deferred_posts" %>
<% end %>
</html>

View File

@ -1,8 +1,8 @@
<% if news_update.present? %>
<div class="ui-state-highlight site-notice" style="display: none;" id="news" data-id="<%= news_update.id %>">
<a href="" id="news-dismiss" title="Dismiss"><i class="fas fa-times"></i></a>
<a href="" role="button" id="news-dismiss" title="Dismiss"><i class="fas fa-times"></i></a>
<h6 id="news-header">News: <%= news_update.created_at.strftime("%b %d, %Y") %>
<a href="" id="news-show">Show</a>
<a href="" role="button" id="news-show">Show</a>
</h6>
<div id="news-body" class="dtext-container"><%= format_text(news_update.message) %></div>
</div>

View File

@ -3,6 +3,7 @@
<div class="search">
<%= render "posts/partials/common/search", title: "Posts", tags: params[:tags] %>
<%= render "posts/partials/index/controls" %>
</div>
<div class="sidebar">

View File

@ -0,0 +1,6 @@
<div class="search-controls">
<button id="search-fullscreen" class="st-button w100 stealth">
<%= svg_icon(:fullscreen) %>
<span>Fullscreen</span>
</button>
</div>

View File

@ -33,9 +33,7 @@
<% if CurrentUser.is_privileged? %>
<span id="tag-script-ui" style="display: none;">
<input id="tag-script-field" data-autocomplete="tag-edit" placeholder="Enter tag script" style="display: none;"/>
<% if CurrentUser.is_staff? %>
<button id="tag-script-all">All</button>
<% end %>
<button id="tag-script-all">All</button>
</span>
<input id="quick-mode-reason" placeholder="Reason" style="display: none;"/>
<% end %>

View File

@ -1,8 +1,7 @@
<div id="posts" class="post-index-gallery user-disable-cropped-<%= Danbooru.config.enable_image_cropping? && CurrentUser.user.disable_cropped_thumbnails? %>">
<% if @wiki_text.present? %>
<section class="wiki-excerpt hidden">
<h3><%= @wiki_page.pretty_title %></h3>
<a href="" class="wiki-excerpt-toggle" role="button"></a>
<section class="wiki-excerpt loading">
<h3 role="button" class="wiki-excerpt-toggle"><%= @wiki_page.pretty_title %></h3>
<%= format_text(@wiki_text, allow_color: true, max_thumbs: 0) %>
<a href="<%= wiki_page_path(@wiki_page) %>" class="wiki-excerpt-readmore"><span>Read More</span></a>
</section>

View File

@ -1,20 +1,29 @@
<footer id="page-footer">
<span class="footer-left">
<%= link_to "Rules", terms_of_service_path %>
<%= link_to "Takedowns", takedown_static_path %>
<%= link_to "Privacy", privacy_policy_path %>
<%= link_to "Contact", contact_path %>
<%= link_to "Advertising", help_page_path(id: "advertising") %>
</span>
<span class="footer-logo">
<a href="/"><%= image_pack_tag("main-logo.svg", class: "footer-logo", title: "Running #{Danbooru.config.software_name} #{GitHelper.short_hash}") %></a>
</span>
<span class="footer-right">
<span class="footer-running">Running <%= Danbooru.config.software_name %> <%= link_to GitHelper.short_hash.to_s, GitHelper.commit_url(GitHelper.hash) %></span>
<%= link_to "Themes / Gestures", theme_path %>
<% if CurrentUser.user.enable_keyboard_navigation %>
<%= link_to "Keyboard Shortcuts", keyboard_shortcuts_path %>
<% end %>
<%= link_to disable_mobile_mode? ? "Mobile mode: OFF": "Mobile mode: ON", disable_mobile_mode_path, :rel => "nofollow" %>
</span>
<footer class="footer-wrapper">
<div class="footer-grid">
<span class="footer-logo">
<a href="/"><%= image_pack_tag("main-logo.svg") %></a>
</span>
<span class="footer-left">
<%= link_to "Rules", terms_of_service_path %>
<%= link_to "Takedowns", takedown_static_path %>
<%= link_to "Privacy", privacy_policy_path %>
<%= link_to "Contact", contact_path %>
<%= link_to "Advertising", help_page_path(id: "advertising") %>
</span>
<span class="footer-right">
<span class="footer-running">Running e621ng</span>
<span class="footer-version">
<% if GitHelper.version.empty? %>
v. unknown
<% else %>
v. <%= link_to GitHelper.version, GitHelper.version_url %>
<% end %>
</span>
<%= link_to "Themes / Gestures", theme_path %>
<% if CurrentUser.user.enable_keyboard_navigation %>
<%= link_to "Keyboard Shortcuts", keyboard_shortcuts_path %>
<% end %>
<%= link_to disable_mobile_mode? ? "Mobile mode: OFF": "Mobile mode: ON", disable_mobile_mode_path, :rel => "nofollow" %>
</span>
</div>
</footer>

View File

@ -4,12 +4,11 @@
<h1 class="dialog-header">Over 18?</h1>
<div class="dialog-content">
<p>
You must be over the age of 18 and agree
to <%= link_to "the terms of service", terms_of_service_path, target: "_blank" %> to access this page.
You must be <b>18 years or older</b> and agree to the <%= link_to "terms of service", terms_of_service_path, target: "_blank" %> to access this website.
</p>
<p>
By default a limited blacklist has been applied hiding content that is commonly objected to. You may remove
items from this blacklist by using the blacklist menu item.
Content that is commonly considered objectionable is blacklisted by default.
You may remove tags from this blacklist using the corresponding menu item.
</p>
</div>
<div class="dialog-footer">

View File

@ -4,24 +4,27 @@
<% end -%>
<section class="home-section">
<h1><%= Danbooru.config.app_name %></h1>
<br/>
<h1><%= Danbooru.config.app_name %></h1><br/>
<%= form_tag(posts_path, method: "get", id: "home-search-form") do %>
<%= form_tag(posts_path, method: "get", class: "home-search") do %>
<%= text_field_tag("tags", "", autofocus: "autofocus", placeholder: "Search posts by tag (title:\"video name\")", data: { shortcut: "q", autocomplete: "tag-query" }) %>
<%= tag.button(tag.i(class: "fa-solid fa-magnifying-glass"), type: "submit") %>
<!-- Primary Searchbar -->
<div class="home-search">
<%= text_field_tag("tags", "", autofocus: "autofocus", placeholder: "Search posts by tag (title:\"video name\")", data: { shortcut: "q", autocomplete: "tag-query" }) %>
<%= tag.button(tag.i(class: "fa-solid fa-magnifying-glass"), type: "submit") %>
</div>
<!-- Secondary search buttons -->
<div class="home-buttons">
<a href="<%= posts_path %>" tags="">
<i class="fas fa-splotch"></i>
<span>Latest</span>
</a>
<a href="<%= posts_path(tags: "order:rank") %>" tags="order:rank">
<i class="fas fa-fire-alt"></i>
<span>Popular</span>
</a>
</div>
<% end %>
<div class="home-buttons">
<a href="/posts">
<i class="fas fa-splotch"></i>
Latest
</a>
<a href="/popular">
<i class="fas fa-fire-alt"></i>
Popular
</a>
</div>
</section>
<% if news_update = NewsUpdate.recent %>

View File

@ -2,7 +2,7 @@
<div id="a-site-map">
<section>
<ul>
<li><h1>Posts</h1></li>
<li><h3>Posts</h3></li>
<li><%= link_to("Listing", posts_path) %></li>
<li><%= link_to("Upload", new_upload_path) %></li>
<% if CurrentUser.is_janitor? %>
@ -17,7 +17,7 @@
<li><%= link_to("Help", help_page_path(id: "posts")) %></li>
</ul>
<ul>
<li><h1>Post Events</h1></li>
<li><h3>Post Events</h3></li>
<li><%= link_to("Listing", post_events_path) %></li>
<li><%= link_to("Tag Changes", post_versions_path) %></li>
<li><%= link_to("Approvals", post_approvals_path) %></li>
@ -25,7 +25,7 @@
<li><%= link_to("Replacements", post_replacements_path) %></li>
</ul>
<ul>
<li><h1>Tools</h1></li>
<li><h3>Tools</h3></li>
<li><%= link_to("News Updates", news_updates_path) %></li>
<li><%= link_to("Mascots", mascots_path) %></li>
<li><%= link_to("Source Code", Danbooru.config.source_code_url) %></li>
@ -35,7 +35,7 @@
<li><%= link_to("DB Export", "/db_export/") %></li>
</ul>
<ul>
<li><h1>Artists</h1></li>
<li><h3>Artists</h3></li>
<li><%= link_to("Listing", artists_path) %></li>
<li><%= link_to("Avoid Posting Entries", avoid_postings_path) %></li>
<li><%= link_to("Avoid Posting List", avoid_posting_static_path) %></li>
@ -45,7 +45,7 @@
</section>
<section>
<ul>
<li><h1>Tags</h1></li>
<li><h3>Tags</h3></li>
<li><%= link_to("Listing", tags_path) %></li>
<li><%= link_to("Aliases", tag_aliases_path) %></li>
<li><%= link_to("Implications", tag_implications_path) %></li>
@ -53,13 +53,13 @@
<li><%= link_to("Help", help_page_path(id: "tags")) %></li>
</ul>
<ul>
<li><h1>Notes</h1></li>
<li><h3>Notes</h3></li>
<li><%= link_to("Listing", notes_path) %></li>
<li><%= link_to("Changes", note_versions_path) %></li>
<li><%= link_to("Help", help_page_path(id: "notes")) %></li>
</ul>
<ul>
<li><h1>Pools</h1></li>
<li><h3>Pools</h3></li>
<li><%= link_to("Listing", gallery_pools_path) %></li>
<li><%= link_to("Changes", pool_versions_path) %></li>
<li><%= link_to("Help", help_page_path(id: "pools")) %></li>
@ -67,30 +67,30 @@
</section>
<section>
<ul>
<li><h1>Comments</h1></li>
<li><h3>Comments</h3></li>
<li><%= link_to("Listing", comments_path) %></li>
<li><%= link_to("Help", help_page_path(id: "comments")) %></li>
</ul>
<ul>
<li><h1>Forum</h1></li>
<li><h3>Forum</h3></li>
<li><%= link_to("Listing", forum_topics_path) %></li>
<li><%= link_to("Help", help_page_path(id: "forum")) %></li>
</ul>
<ul>
<li><h1>Wiki</h1></li>
<li><h3>Wiki</h3></li>
<li><%= link_to("Listing", wiki_pages_path) %></li>
<li><%= link_to("Changes", wiki_page_versions_path) %></li>
<li><%= link_to("Help", help_page_path(id: "wiki")) %></li>
</ul>
<ul>
<li><h1>Blips</h1></li>
<li><h3>Blips</h3></li>
<li><%= link_to("Listing", blips_path) %></li>
<li><%= link_to("Help", help_page_path(id: "blips")) %></li>
</ul>
</section>
<section>
<ul>
<li><h1>Users</h1></li>
<li><h3>Users</h3></li>
<li><%= link_to("Listing", users_path) %></li>
<li><%= link_to("Bans", bans_path) %></li>
<% if CurrentUser.is_anonymous? %>
@ -105,7 +105,7 @@
<li><%= link_to("Help", help_page_path(id: "accounts")) %></li>
</ul>
<ul>
<li><h1>Admin</h1></li>
<li><h3>Admin</h3></li>
<% if CurrentUser.is_moderator? %>
<li><%= link_to("Mod Dashboard", moderator_dashboard_path) %></li>
<% end %>

View File

@ -43,6 +43,12 @@
<option value="true">Enabled</option>
</select>
<label for="theme_forumnotif">Forum Activity Dot</label>
<select id="theme_forumnotif">
<option value="false">Disabled</option>
<option value="true">Enabled</option>
</select>
<h3>Accessibility</h3>
<label for="theme_palette">Palette</label>
<select id="theme_palette">

View File

@ -0,0 +1,56 @@
#!/usr/bin/env ruby
# frozen_string_literal: true
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "config", "environment"))
destroyed_feedback_ids = []
CurrentUser.as_system do
ModAction.where(action: "user_feedback_destroy")
# On July 24, 2024, we deployed the ability to soft-delete feedback records.
# We only care about restoring destroyed feedbacks that were destroyed before this date.
# Any entries after this are "real" destructions, that do not need to be restored.
.where("created_at < ?", CUTOFF_DATE = Date.new(2024, 8, 1))
.find_in_batches(batch_size: 10_000) do |batch|
feedback_data = batch.map do |mod_action|
record_id = mod_action.values["record_id"].to_i
destroyed_feedback_ids << record_id
{
id: record_id,
user_id: mod_action.values["user_id"].to_i,
creator_id: User.system.id, # placeholder
category: mod_action.values["type"],
body: mod_action.values["reason"]&.strip,
created_at: Date.new(1970, 1, 1), # placeholder
updated_at: mod_action.created_at,
updater_id: mod_action.creator_id,
is_deleted: true,
}
end
UserFeedback.insert_all(feedback_data) if feedback_data.any?
end
end
CurrentUser.as_system do
ModAction.where(action: "user_feedback_create")
.where("values->>'record_id' IN (?)", destroyed_feedback_ids.map(&:to_s))
.find_in_batches(batch_size: 10_000) do |batch|
batch.each do |mod_action|
record_id = mod_action.values["record_id"].to_i
next unless destroyed_feedback_ids.include?(record_id)
UserFeedback.where(id: record_id).update_all(
creator_id: mod_action.creator_id,
created_at: mod_action.created_at,
)
end
end
end
StaffNote.where(creator: User.system)
.where("body LIKE ?", "%deleted%feedback%")
.find_in_batches(batch_size: 10_000) do |batch|
StaffNote.where(id: batch.map(&:id)).delete_all
end

View File

@ -93,7 +93,7 @@ class UserFeedbacksControllerTest < ActionDispatch::IntegrationTest
end
should "delete a feedback" do
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 2 }) do
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 1 }) do
delete_auth user_feedback_path(@user_feedback), @critic
end
end
@ -101,7 +101,7 @@ class UserFeedbacksControllerTest < ActionDispatch::IntegrationTest
context "by a moderator" do
should "allow destroying feedbacks they created" do
as(@mod) { @user_feedback = create(:user_feedback, user: @user) }
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 2 }) do
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 1 }) do
delete_auth user_feedback_path(@user_feedback), @mod
end
end
@ -126,13 +126,13 @@ class UserFeedbacksControllerTest < ActionDispatch::IntegrationTest
context "by an admin" do
should "allow destroying feedbacks they created" do
as(@admin) { @user_feedback = create(:user_feedback, user: @user) }
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 2 }) do
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 1 }) do
delete_auth user_feedback_path(@user_feedback), @admin
end
end
should "allow destroying feedbacks they did not create" do
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 2 }) do
assert_difference({ "UserFeedback.count" => -1, "ModAction.count" => 1 }) do
delete_auth user_feedback_path(@user_feedback, format: :json), @admin
end
end