forked from e621ng/e621ng
Merge branch 'master' into master2
This commit is contained in:
commit
9923b01141
@ -19,6 +19,12 @@ class PostsController < ApplicationController
|
||||
@query = tag_query.nil? ? [] : tag_query.strip.split(/ /, 2).compact_blank
|
||||
if @query.length == 1
|
||||
@wiki_page = WikiPage.titled(@query[0])
|
||||
|
||||
# redirect?
|
||||
if @wiki_page.present? && @wiki_page.parent.present?
|
||||
@wiki_page = WikiPage.titled(@wiki_page.parent)
|
||||
end
|
||||
|
||||
@wiki_text = @wiki_page.present? ? @wiki_page.body : ""
|
||||
if @wiki_text.present?
|
||||
@wiki_text = @wiki_text
|
||||
|
@ -123,9 +123,10 @@ class WikiPagesController < ApplicationController
|
||||
end
|
||||
|
||||
def wiki_page_params(context)
|
||||
permitted_params = %i[body edit_reason]
|
||||
permitted_params = %i[body category_id edit_reason]
|
||||
permitted_params += %i[parent] if CurrentUser.is_privileged?
|
||||
permitted_params += %i[is_locked is_deleted skip_secondary_validations] if CurrentUser.is_janitor?
|
||||
permitted_params += %i[category_is_locked] if CurrentUser.is_admin?
|
||||
permitted_params += %i[title] if context == :create || CurrentUser.is_janitor?
|
||||
|
||||
params.fetch(:wiki_page, {}).permit(permitted_params)
|
||||
|
@ -121,6 +121,10 @@ module ApplicationHelper
|
||||
time_tag(time.strftime("%Y-%m-%d %H:%M"), time)
|
||||
end
|
||||
|
||||
def compact_date(time)
|
||||
time_tag(time.strftime("%Y-%m-%d"), time)
|
||||
end
|
||||
|
||||
def external_link_to(url, truncate: nil, strip_scheme: false, link_options: {})
|
||||
text = url
|
||||
text = text.gsub(%r!\Ahttps?://!i, "") if strip_scheme
|
||||
@ -189,21 +193,6 @@ 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: home_users_path, 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
|
||||
|
@ -17,10 +17,21 @@ module IconHelper
|
||||
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"/>),
|
||||
user: %(<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>),
|
||||
|
||||
# Utility
|
||||
plus: %(<path d="M5 12h14"/><path d="M12 5v14"/>),
|
||||
times: %(<path d="M18 6 6 18"/><path d="m6 6 12 12"/>),
|
||||
reset: %(<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/>),
|
||||
replace: %(<path d="M14 4a2 2 0 0 1 2-2"/><path d="M16 10a2 2 0 0 1-2-2"/><path d="M20 2a2 2 0 0 1 2 2"/><path d="M22 8a2 2 0 0 1-2 2"/><path d="m3 7 3 3 3-3"/><path d="M6 10V5a3 3 0 0 1 3-3h1"/><rect x="2" y="14" width="8" height="8" rx="2"/>),
|
||||
upload: %(<path d="M12 13v8"/><path d="M4 14.899A7 7 0 1 1 15.71 8h1.79a4.5 4.5 0 0 1 2.5 8.242"/><path d="m8 17 4-4 4 4"/>),
|
||||
stamp: %(<path d="M19.27 13.73A2.5 2.5 0 0 0 17.5 13h-11A2.5 2.5 0 0 0 4 15.5V17a1 1 0 0 0 1 1h14a1 1 0 0 0 1-1v-1.5c0-.66-.26-1.3-.73-1.77Z"/><path d="M14 13V8.5C14 7 15 7 15 5a3 3 0 0 0-3-3c-1.66 0-3 1-3 3s1 2 1 3.5V13"/>),
|
||||
power: %(<path d="M12 2v10"/><path d="M18.4 6.6a9 9 0 1 1-12.77.04"/>),
|
||||
circle_help: %(<circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/>),
|
||||
notepad: %(<path d="M8 2v4"/><path d="M12 2v4"/><path d="M16 2v4"/><path d="M16 4h2a2 2 0 0 1 2 2v2"/><path d="M20 12v2"/><path d="M20 18v2a2 2 0 0 1-2 2h-1"/><path d="M13 22h-2"/><path d="M7 22H6a2 2 0 0 1-2-2v-2"/><path d="M4 14v-2"/><path d="M4 8V6a2 2 0 0 1 2-2h2"/><path d="M8 10h6"/><path d="M8 14h8"/><path d="M8 18h5"/>),
|
||||
flag_left: %(<path d="M17 22V2L7 7l10 5"/>),
|
||||
ticket: %(<path d="M2 9a3 3 0 0 1 0 6v2a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-2a3 3 0 0 1 0-6V7a2 2 0 0 0-2-2H4a2 2 0 0 0-2 2Z"/><path d="M13 5v2"/><path d="M13 17v2"/><path d="M13 11v2"/>),
|
||||
key_square: %(<path d="M12.4 2.7a2.5 2.5 0 0 1 3.4 0l5.5 5.5a2.5 2.5 0 0 1 0 3.4l-3.7 3.7a2.5 2.5 0 0 1-3.4 0L8.7 9.8a2.5 2.5 0 0 1 0-3.4z"/><path d="m14 7 3 3"/><path d="m9.4 10.6-6.814 6.814A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814"/>),
|
||||
|
||||
# Pagination
|
||||
chevron_left: %(<path d="m15 18-6-6 6-6"/>),
|
||||
@ -28,7 +39,9 @@ module IconHelper
|
||||
ellipsis: %(<circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/>),
|
||||
|
||||
# Posts
|
||||
search: %(<circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/>),
|
||||
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"/>),
|
||||
anchor: %(<path d="M12 22V8"/><path d="M5 12H2a10 10 0 0 0 20 0h-3"/><circle cx="12" cy="5" r="3"/>),
|
||||
}.freeze
|
||||
|
||||
def svg_icon(name, *args)
|
||||
|
@ -1,6 +1,29 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module PaginationHelper
|
||||
def approximate_count(records)
|
||||
return "" if records.pagination_mode != :numbered
|
||||
|
||||
if records.total_pages > records.max_numbered_pages
|
||||
pages = records.max_numbered_pages
|
||||
schar = "over "
|
||||
count = pages * records.records_per_page
|
||||
title = "Over #{count} results found.\nActual result count may be much larger."
|
||||
else
|
||||
pages = records.total_pages
|
||||
schar = "~"
|
||||
count = pages * records.records_per_page
|
||||
title = "Approximately #{count} results found.\nActual result count may differ."
|
||||
end
|
||||
|
||||
tag.span(class: "approximate-count", title: title, data: { count: count, pages: pages, per: records.max_numbered_pages }) do
|
||||
concat schar
|
||||
concat number_to_human(count, precision: 2, format: "%n%u", units: { thousand: "k" })
|
||||
concat " "
|
||||
concat "result".pluralize(count)
|
||||
end
|
||||
end
|
||||
|
||||
def sequential_paginator(records)
|
||||
tag.nav(class: "pagination sequential", aria: { label: "Pagination" }) do
|
||||
return "" if records.try(:none?)
|
||||
@ -64,12 +87,12 @@ module PaginationHelper
|
||||
html = "".html_safe
|
||||
|
||||
if disabled
|
||||
html << tag.span(class: "next", id: "paginator-next", data: { shortcut: "a left" }) do
|
||||
html << tag.span(class: "next", id: "paginator-next", data: { shortcut: "d right" }) do
|
||||
concat tag.span("Next")
|
||||
concat svg_icon(:chevron_right)
|
||||
end
|
||||
else
|
||||
html << link_to(link, class: "next", id: "paginator-prev", rel: "next", data: { shortcut: "a left" }) do
|
||||
html << link_to(link, class: "next", id: "paginator-next", rel: "next", data: { shortcut: "d right" }) do
|
||||
concat tag.span("Next")
|
||||
concat svg_icon(:chevron_right)
|
||||
end
|
||||
|
@ -11,4 +11,47 @@ module UsersHelper
|
||||
domain = email.split("@").last
|
||||
link_to "»", users_path(search: { email_matches: "*@#{domain}" })
|
||||
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 placeholder #{klass}", data: { id: post_id, name: user.name } do
|
||||
tag.span(class: "avatar-button") do
|
||||
concat tag.span(user.pretty_name, class: "avatar-name") if named
|
||||
concat tag.span(class: "avatar-image", data: { name: user.name[0].capitalize })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def profile_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)
|
||||
|
||||
render "/application/profile_avatar", user: user, post_id: post_id, klass: klass
|
||||
end
|
||||
|
||||
def user_level_badge(user)
|
||||
return if user.nil?
|
||||
|
||||
tag.span(class: "level-badge level-#{user.level_string.downcase}") do
|
||||
user.level_string.upcase
|
||||
end
|
||||
end
|
||||
|
||||
def user_feedback_badge(user)
|
||||
return if user.nil?
|
||||
|
||||
feedbacks = user.feedback_pieces
|
||||
deleted = CurrentUser.user.is_staff? ? feedbacks[:deleted] : 0
|
||||
active = feedbacks[:positive] + feedbacks[:neutral] + feedbacks[:negative]
|
||||
|
||||
render "/application/feedback_badge", user: user, positive: feedbacks[:positive], neutral: feedbacks[:neutral], negative: feedbacks[:negative], deleted: deleted, active: active
|
||||
end
|
||||
end
|
||||
|
@ -67,6 +67,13 @@ PostSearch.initialize_controls = function () {
|
||||
$("body").attr("data-st-fullscreen", fullscreen);
|
||||
LStorage.Posts.Fullscreen = fullscreen;
|
||||
});
|
||||
|
||||
let stickySearch = LStorage.Posts.StickySearch;
|
||||
$("#search-sticky").on("click", () => {
|
||||
stickySearch = !stickySearch;
|
||||
$("body").attr("data-st-ssearch", stickySearch);
|
||||
LStorage.Posts.StickySearch = stickySearch;
|
||||
});
|
||||
};
|
||||
|
||||
$(() => {
|
||||
|
170
app/javascript/src/javascripts/tabs.js
Normal file
170
app/javascript/src/javascripts/tabs.js
Normal file
@ -0,0 +1,170 @@
|
||||
class Tabs {
|
||||
|
||||
constructor ($element) {
|
||||
this.$menu = $element;
|
||||
|
||||
const id = this.$menu.attr("id");
|
||||
const pagesWrap = $(`tabs-content[for="${id}"]`);
|
||||
if (!pagesWrap) {
|
||||
console.error("E6.Tabs", "No content");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create page and search indices
|
||||
this.index = new TabIndex(pagesWrap, this.$menu);
|
||||
|
||||
// Bootstrap search
|
||||
const input = this.$menu.find("input[name='search']").on("input", (event, crabs) => {
|
||||
const val = (input.val() + "").trim();
|
||||
this.index.find(val);
|
||||
|
||||
// Set the query param
|
||||
if (crabs) return;
|
||||
|
||||
const url = new URL(window.location);
|
||||
if (!val) url.searchParams.delete("find");
|
||||
else url.searchParams.set("find", input.val() + "");
|
||||
url.searchParams.delete("tab");
|
||||
|
||||
window.history.pushState({}, "", url);
|
||||
});
|
||||
|
||||
// Bootstrap tab buttons
|
||||
const firstButtonName = this.$menu.find("button").first().attr("name");
|
||||
this.$menu.on("click", "button", (event, crabs) => {
|
||||
const button = $(event.currentTarget);
|
||||
const name = button.attr("name");
|
||||
if (!name) return;
|
||||
|
||||
// Toggle the page
|
||||
this.index.openPage(name);
|
||||
this.$menu.find("button.active").removeClass("active");
|
||||
button.addClass("active");
|
||||
input.val("");
|
||||
|
||||
// Set the query param
|
||||
if (crabs) return;
|
||||
|
||||
const url = new URL(window.location);
|
||||
if (name == firstButtonName) url.searchParams.delete("tab");
|
||||
else url.searchParams.set("tab", name);
|
||||
url.searchParams.delete("find");
|
||||
|
||||
window.history.pushState({}, "", url);
|
||||
});
|
||||
|
||||
// Attempt to restore previous state
|
||||
const queryParams = new URLSearchParams(window.location.search);
|
||||
if (queryParams.get("tab")) {
|
||||
// No error handling: if the button does not exist nothing loads
|
||||
this.$menu.find(`button[name="${queryParams.get("tab")}"]`).trigger("click", [ true ]);
|
||||
input.val("");
|
||||
} else if (queryParams.get("find")) {
|
||||
input.val(queryParams.get("find"), [ true ]);
|
||||
input.trigger("input");
|
||||
} else {
|
||||
// Just open the first tab
|
||||
this.$menu.find("button").first().click();
|
||||
input.val("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TabIndex {
|
||||
|
||||
constructor (wrapper, $menu) {
|
||||
|
||||
this.$menu = $menu;
|
||||
|
||||
this.pages = {};
|
||||
this.search = {};
|
||||
this._allEntries = wrapper.children("tab-entry");
|
||||
for (const one of this._allEntries) {
|
||||
const $one = $(one);
|
||||
|
||||
const tab = $one.attr("tab");
|
||||
if (tab) {
|
||||
if (!this.pages[tab]) this.pages[tab] = [];
|
||||
this.pages[tab].push($one);
|
||||
}
|
||||
|
||||
// TODO Not a great way of doing this.
|
||||
// Entries with the same search string will get overwriten.
|
||||
const search = $one.attr("search");
|
||||
if (search) this.search[search] = $one;
|
||||
}
|
||||
|
||||
this.groups = {};
|
||||
this._allGroups = wrapper.children("tab-group");
|
||||
for (const one of this._allGroups) {
|
||||
const $one = $(one);
|
||||
const name = $one.attr("name");
|
||||
if (!name) return;
|
||||
this.groups[name] = $one;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Show all entries on a specific tab
|
||||
* @param {string} name Tab name
|
||||
*/
|
||||
openPage (name) {
|
||||
|
||||
if (!name || !this.pages[name]) {
|
||||
console.error("E6.Tabs", name, "does not exist");
|
||||
return;
|
||||
}
|
||||
|
||||
// Activate tab entries
|
||||
const groups = new Set();
|
||||
this._allEntries.removeClass("active");
|
||||
for (const entry of this.pages[name]) {
|
||||
entry.addClass("active");
|
||||
if (entry.attr("group"))
|
||||
groups.add(entry.attr("group"));
|
||||
}
|
||||
|
||||
// Activate group headers
|
||||
this._allGroups.removeClass("active");
|
||||
for (const group of groups)
|
||||
this.groups[group].addClass("active");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find settings inputs based on keywords
|
||||
* @param {string} query Search query
|
||||
*/
|
||||
find (query) {
|
||||
this._allEntries.removeClass("active");
|
||||
this._allGroups.removeClass("active");
|
||||
|
||||
// Restore the previous session
|
||||
if (query.length == 0) {
|
||||
this.$menu.find("button").first().trigger("click", [ false ]);
|
||||
return;
|
||||
}
|
||||
|
||||
const terms = query.split(" ");
|
||||
const groups = new Set();
|
||||
for (const [tags, $element] of Object.entries(this.search)) {
|
||||
for (const term of terms) {
|
||||
if (!tags.includes(term)) continue;
|
||||
$element.addClass("active");
|
||||
if ($element.attr("group"))
|
||||
groups.add($element.attr("group"));
|
||||
}
|
||||
}
|
||||
|
||||
// Activate group headers
|
||||
this._allGroups.removeClass("active");
|
||||
for (const group of groups)
|
||||
this.groups[group].addClass("active");
|
||||
}
|
||||
}
|
||||
|
||||
$(() => {
|
||||
for (const one of $("tabs-menu"))
|
||||
new Tabs($(one));
|
||||
});
|
@ -39,8 +39,8 @@ Takedown.add_posts_by_tags_preview = function (id) {
|
||||
$("#takedown-add-posts-tags-warning").html(preview_text).show();
|
||||
$("#takedown-add-posts-tags").prop("disabled", true);
|
||||
$("#takedown-add-posts-tags-preview").hide();
|
||||
$("#takedown-add-posts-tags-confirm").show();
|
||||
$("#takedown-add-posts-tags-cancel").show();
|
||||
$("#takedown-add-posts-tags-confirm").css("display", "inline-block");
|
||||
$("#takedown-add-posts-tags-cancel").css("display", "inline-block");
|
||||
}).fail(function (data) {
|
||||
Utility.error(data.responseText);
|
||||
});
|
||||
|
@ -3,17 +3,23 @@ import LStorage from "./utility/storage";
|
||||
|
||||
const Theme = {};
|
||||
|
||||
Theme.Values = ["Main", "Extra", "StickyHeader", "ForumNotif", "Palette", "Navbar", "Gestures"];
|
||||
Theme.Values = {
|
||||
"Theme": ["Main", "Extra", "Palette", "Font", "StickyHeader", "Navbar", "Gestures", "ForumNotif"],
|
||||
"Posts": ["WikiExcerpt", "StickySearch"],
|
||||
};
|
||||
|
||||
for (const one of Theme.Values) {
|
||||
Object.defineProperty(Theme, one, {
|
||||
get () { return LStorage.Theme[one]; },
|
||||
set (value) {
|
||||
// No value checking, we die like men
|
||||
LStorage.Theme[one] = value;
|
||||
$("body").attr("data-th-" + one.toLowerCase(), value);
|
||||
},
|
||||
});
|
||||
for (const [label, settings] of Object.entries(Theme.Values)) {
|
||||
for (const one of settings) {
|
||||
Object.defineProperty(Theme, one, {
|
||||
get () { return LStorage.Theme[one]; },
|
||||
set (value) {
|
||||
// This has the unintended side effect of setting
|
||||
// attribute values that don't exist on the body.
|
||||
LStorage[label][one] = value;
|
||||
$("body").attr("data-th-" + one.toLowerCase(), value);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Theme.initialize_selector = function () {
|
||||
@ -24,13 +30,15 @@ Theme.initialize_selector = function () {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const one of Theme.Values) {
|
||||
$("#theme_" + one.toLowerCase())
|
||||
.val(LStorage.Theme[one] + "")
|
||||
.on("change", (event) => {
|
||||
const data = event.target.value;
|
||||
Theme[one] = data;
|
||||
});
|
||||
for (const [label, settings] of Object.entries(Theme.Values)) {
|
||||
for (const one of settings)
|
||||
$(`#${label}_${one}`)
|
||||
.val(LStorage[label][one] + "")
|
||||
.on("change", (event) => {
|
||||
const data = event.target.value;
|
||||
console.log("change", one, data);
|
||||
Theme[one] = data;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -42,12 +50,6 @@ Theme.initialize_buttons = function () {
|
||||
LStorage.Site.Mascot = 0;
|
||||
$("#mascot-value").text(LStorage.Site.Mascot);
|
||||
});
|
||||
|
||||
$("#wiki-excerpt-value").text(LStorage.Posts.WikiExcerpt);
|
||||
$("#wiki-excerpt-reset").on("click", () => {
|
||||
LStorage.Posts.WikiExcerpt = 1;
|
||||
$("#wiki-excerpt-value").text(LStorage.Posts.WikiExcerpt);
|
||||
});
|
||||
};
|
||||
|
||||
$(() => {
|
||||
|
@ -9,8 +9,9 @@ Thumbnails.initialize = function () {
|
||||
const replacedPosts = [];
|
||||
|
||||
// Avatar special case
|
||||
for (const post of $(".simple-avatar")) {
|
||||
for (const post of $(".simple-avatar.placeholder, .profile-avatar.placeholder")) {
|
||||
const $post = $(post);
|
||||
$post.removeClass("placeholder");
|
||||
|
||||
const postID = $post.data("id");
|
||||
if (!postID) continue;
|
||||
@ -20,7 +21,11 @@ Thumbnails.initialize = function () {
|
||||
|
||||
$("<img>")
|
||||
.attr("src", postData["preview_url"])
|
||||
.appendTo($post.find("span.simple-avatar-image"));
|
||||
.appendTo($post.find("span.avatar-image"));
|
||||
|
||||
if ($post.hasClass("profile-avatar"))
|
||||
$post.attr("href", "/posts/" + postID);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
25
app/javascript/src/javascripts/users.js
Normal file
25
app/javascript/src/javascripts/users.js
Normal file
@ -0,0 +1,25 @@
|
||||
import LStorage from "./utility/storage";
|
||||
|
||||
const Users = {};
|
||||
|
||||
Users.init_section = function ($wrapper) {
|
||||
const $header = $wrapper.find(".profile-section-header").first();
|
||||
const $body = $(".profile-section-body").first();
|
||||
const name = $wrapper.attr("name");
|
||||
if (!name || !$header.length || !$body.length) return;
|
||||
|
||||
let state = LStorage.Users[name];
|
||||
if (state) $wrapper.removeClass("hidden");
|
||||
|
||||
$header.on("click", () => {
|
||||
$wrapper.toggleClass("hidden", state);
|
||||
|
||||
state = !state;
|
||||
LStorage.Users[name] = state;
|
||||
});
|
||||
};
|
||||
|
||||
$(() => {
|
||||
for (const one of $((".profile-section")))
|
||||
Users.init_section($((one)));
|
||||
});
|
@ -57,6 +57,9 @@ LStorage.Theme = {
|
||||
/** @returns {string} Colorblind-friendly palette (default / deut / trit) */
|
||||
Palette: ["theme-palette", "default"],
|
||||
|
||||
/** @returns {string} Font family (verdana / leto / lexend / dyslexic ) */
|
||||
Font: ["theme-font", "Verdana"],
|
||||
|
||||
/** @returns {string} Position of the navbar on the post page (top / bottom / both / none) */
|
||||
Navbar: ["theme-nav", "top"],
|
||||
|
||||
@ -91,6 +94,9 @@ LStorage.Posts = {
|
||||
|
||||
/** @returns {boolean} True if the search should be displayed in fullscreen */
|
||||
Fullscreen: ["e6.posts.fusk", false],
|
||||
|
||||
/** @returns {boolean} True if the search should be displayed in fullscreen */
|
||||
StickySearch: ["e6.posts.ssearch", false],
|
||||
};
|
||||
StorageUtils.bootstrapMany(LStorage.Posts);
|
||||
|
||||
@ -184,6 +190,17 @@ LStorage.Blacklist = {
|
||||
StorageUtils.bootstrapSome(LStorage.Blacklist, ["Collapsed"]);
|
||||
|
||||
|
||||
// Users page config
|
||||
LStorage.Users = {
|
||||
/** @returns {boolean} True to show staff stats, false to hide them */
|
||||
StaffStats: ["e6.users.staffstats", false],
|
||||
|
||||
/** @returns {boolean} True to show user stats, false to hide them */
|
||||
StaffNotes: ["e6.users.staffnotes", false],
|
||||
};
|
||||
StorageUtils.bootstrapMany(LStorage.Users);
|
||||
|
||||
|
||||
/**
|
||||
* Patches the add, delete, and clear methods for the filter cache set.
|
||||
* Otherwise, modifying the set with these methods would not update the local storage
|
||||
|
@ -8,6 +8,7 @@
|
||||
@import "base/base";
|
||||
@import "base/links";
|
||||
@import "base/fontawesome";
|
||||
@import "base/fonts";
|
||||
|
||||
@import "common/standard_variables";
|
||||
@import "common/standard_elements";
|
||||
@ -42,6 +43,10 @@
|
||||
@import "common/user_styles.scss";
|
||||
@import "common/voting.scss";
|
||||
|
||||
@import "views/application/application";
|
||||
@import "views/posts/posts";
|
||||
@import "views/users/users";
|
||||
|
||||
@import "specific/admin_dashboards.scss";
|
||||
@import "specific/api_keys.scss";
|
||||
@import "specific/artists.scss";
|
||||
@ -68,8 +73,6 @@
|
||||
@import "specific/popular.scss";
|
||||
@import "specific/post_delete.scss";
|
||||
@import "specific/post_flags.scss";
|
||||
@import "specific/post_index.scss";
|
||||
@import "specific/post_mode_menu.scss";
|
||||
@import "specific/posts.scss";
|
||||
@import "specific/post_replacements.scss";
|
||||
@import "specific/post_versions.scss";
|
||||
|
161
app/javascript/src/styles/base/_fonts.scss
Normal file
161
app/javascript/src/styles/base/_fonts.scss
Normal file
@ -0,0 +1,161 @@
|
||||
// Picker
|
||||
body {
|
||||
&[data-th-font="Lato"] { font-family: "Lato", $base_font_family; }
|
||||
&[data-th-font="Lexend"] { font-family: "Lexend", $base_font_family; }
|
||||
&[data-th-font="Monospace"] { font-family: monospace, monospace; }
|
||||
&[data-th-font="OpenDyslexic"] { font-family: "OpenDyslexic", $base_font_family; }
|
||||
&[data-th-font="OpenSans"] { font-family: "OpenSans", $base_font_family; }
|
||||
&[data-th-font="ComicSans"] { font-family: "Comic Sans MS", "Comic Sans", cursive; }
|
||||
}
|
||||
|
||||
/** Font Definitions **/
|
||||
// Lato
|
||||
@font-face {
|
||||
font-family: "Lato";
|
||||
src: url("/public/fonts/Lato/Lato-Regular.woff2") format("woff2"),
|
||||
url("/public/fonts/Lato/Lato-Regular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Lato";
|
||||
src: url("/public/fonts/Lato/Lato-Bold.woff2") format("woff2"),
|
||||
url("/public/fonts/Lato/Lato-Bold.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Lato";
|
||||
src: url("/public/fonts/Lato/Lato-Italic.woff2") format("woff2"),
|
||||
url("/public/fonts/Lato/Lato-Italic.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Lato";
|
||||
src: url("/public/fonts/Lato/Lato-BoldItalic.woff2") format("woff2"),
|
||||
url("/public/fonts/Lato/Lato-BoldItalic.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
|
||||
// Lexend
|
||||
@font-face {
|
||||
font-family: "Lexend";
|
||||
src: url("/public/fonts/Lexend/Lexend-Regular.woff2") format("woff2"),
|
||||
url("/public/fonts/Lexend/Lexend-Regular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Lexend";
|
||||
src: url("/public/fonts/Lexend/Lexend-Bold.woff2") format("woff2"),
|
||||
url("/public/fonts/Lexend/Lexend-Bold.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Lexend";
|
||||
src: url("/public/fonts/Lexend/Lexend-Italic.woff2") format("woff2"),
|
||||
url("/public/fonts/Lexend/Lexend-Italic.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Lexend";
|
||||
src: url("/public/fonts/Lexend/Lexend-BoldItalic.woff2") format("woff2"),
|
||||
url("/public/fonts/Lexend/Lexend-BoldItalic.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
|
||||
// OpenDyslexic
|
||||
@font-face {
|
||||
font-family: "OpenDyslexic";
|
||||
src: url("/public/fonts/OpenDyslexic/OpenDyslexic-Regular.woff2") format("woff2"),
|
||||
url("/public/fonts/OpenDyslexic/OpenDyslexic-Regular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "OpenDyslexic";
|
||||
src: url("/public/fonts/OpenDyslexic/OpenDyslexic-Bold.woff2") format("woff2"),
|
||||
url("/public/fonts/OpenDyslexic/OpenDyslexic-Bold.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "OpenDyslexic";
|
||||
src: url("/public/fonts/OpenDyslexic/OpenDyslexic-Italic.woff2") format("woff2"),
|
||||
url("/public/fonts/OpenDyslexic/OpenDyslexic-Italic.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "OpenDyslexic";
|
||||
src: url("/public/fonts/OpenDyslexic/OpenDyslexic-BoldItalic.woff2") format("woff2"),
|
||||
url("/public/fonts/OpenDyslexic/OpenDyslexic-BoldItalic.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
|
||||
// OpenSans
|
||||
@font-face {
|
||||
font-family: "OpenSans";
|
||||
src: url("/public/fonts/OpenSans/OpenSans-Regular.woff2") format("woff2"),
|
||||
url("/public/fonts/OpenSans/OpenSans-Regular.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "OpenSans";
|
||||
src: url("/public/fonts/OpenSans/OpenSans-Bold.woff2") format("woff2"),
|
||||
url("/public/fonts/OpenSans/OpenSans-Bold.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "OpenSans";
|
||||
src: url("/public/fonts/OpenSans/OpenSans-Italic.woff2") format("woff2"),
|
||||
url("/public/fonts/OpenSans/OpenSans-Italic.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "OpenSans";
|
||||
src: url("/public/fonts/OpenSans/OpenSans-BoldItalic.woff2") format("woff2"),
|
||||
url("/public/fonts/OpenSans/OpenSans-BoldItalic.woff") format("woff");
|
||||
font-weight: bold;
|
||||
font-style: italic;
|
||||
font-display: swap;
|
||||
}
|
@ -19,3 +19,15 @@
|
||||
@function themed($key) {
|
||||
@return var(--#{$key});
|
||||
}
|
||||
|
||||
@mixin with-theme($key, $value) {
|
||||
body[data-th-#{$key}="#{$value}"] {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin with-setting($key, $value) {
|
||||
body[data-st-#{$key}="#{$value}"] {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ $dtext_h3_size: 1.6em;
|
||||
$dtext_h4_size: 1.4em;
|
||||
$dtext_h5_size: 1.2em;
|
||||
$dtext_h6_size: 1em;
|
||||
$base_font_family: Verdana, sans-serif;
|
||||
$base_font_family: Verdana, Geneva, sans-serif;
|
||||
|
||||
$box-shadow-size: 2px 2px 5px;
|
||||
|
||||
|
@ -29,7 +29,7 @@ footer.footer-wrapper {
|
||||
margin-right: -3.25rem;
|
||||
|
||||
background: themed("color-background") themed("image-background");
|
||||
border-radius: 50%;
|
||||
border-radius: 25%;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
@ -21,11 +21,12 @@
|
||||
line-height: st-value(100);
|
||||
padding: st-value(100) / 2;
|
||||
height: st-value(100) * 2;
|
||||
box-sizing: border-box;
|
||||
|
||||
// TODO What if button is on a light background
|
||||
background: $button-background;
|
||||
color: $button-text-color;
|
||||
&:hover { background: $button-background-hover; }
|
||||
&:hover, &:active { background: $button-background-hover; }
|
||||
|
||||
& > svg {
|
||||
// Icon should be slightly larger than text,
|
||||
@ -64,3 +65,57 @@
|
||||
padding: (st-value(100) / 2) 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Colored buttons
|
||||
.st-button.danger {
|
||||
background: palette("background-red");
|
||||
&:hover, &:active {
|
||||
background: palette("background-red-d5")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Toggle switch
|
||||
label.st-toggle {
|
||||
display: flex;
|
||||
width: 2.5rem;
|
||||
height: 0.75rem;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
|
||||
background-color: themed("color-foreground");
|
||||
// transition: background-color 200ms;
|
||||
border-radius: 0.25rem;
|
||||
cursor: pointer;
|
||||
font-size: 0;
|
||||
|
||||
box-shadow: inset 0 0 0.25rem #00000060;
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
position: absolute;
|
||||
top: -0.125rem;
|
||||
left: 0rem;
|
||||
|
||||
background: themed("color-link");
|
||||
border-radius: 0.25rem;
|
||||
transition: left 100ms, background-color 200ms;
|
||||
}
|
||||
}
|
||||
input[type="checkbox"][disabled].st-toggle + label.st-toggle {
|
||||
background: palette("background-grey");
|
||||
cursor: not-allowed;
|
||||
}
|
||||
input[type="checkbox"].st-toggle { display: none; }
|
||||
input[type="checkbox"].st-toggle:checked + label.st-toggle {
|
||||
// background-color: palette("background-green-d5");
|
||||
&::after {
|
||||
content: "";
|
||||
left: 1.5rem;
|
||||
background: themed("color-link-active");
|
||||
}
|
||||
}
|
||||
|
@ -17,5 +17,5 @@ $st-values: (
|
||||
@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); }
|
||||
@function radius($value: 025) { @return st-value($value); }
|
||||
@mixin st-radius($value: 025) { border-radius: radius($value); }
|
||||
|
@ -5,7 +5,7 @@ nav.navigation {
|
||||
grid-template-rows: min-content min-content min-content min-content auto;
|
||||
|
||||
width: 100%; // otherwise narrow when fixed
|
||||
z-index: 20; // otherwise post labels layered above
|
||||
z-index: 200; // above post labels and notes
|
||||
position: relative;
|
||||
|
||||
|
||||
@ -76,11 +76,11 @@ nav.navigation {
|
||||
}
|
||||
|
||||
a.simple-avatar {
|
||||
.simple-avatar-button {
|
||||
.avatar-button {
|
||||
padding: 0;
|
||||
gap: 0;
|
||||
|
||||
.simple-avatar-name {
|
||||
.avatar-name {
|
||||
padding: 0.5rem;
|
||||
|
||||
@include window-smaller-than(32rem) {
|
||||
@ -88,7 +88,7 @@ nav.navigation {
|
||||
}
|
||||
}
|
||||
|
||||
.simple-avatar-image {
|
||||
.avatar-image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@ -119,7 +119,7 @@ nav.navigation {
|
||||
}
|
||||
|
||||
@include window-smaller-than(32rem) {
|
||||
&.sign-in .simple-avatar-image {
|
||||
&.sign-in .avatar-image {
|
||||
background: themed("color-foreground");
|
||||
}
|
||||
}
|
||||
@ -187,6 +187,8 @@ nav.navigation {
|
||||
padding: 1rem 0.5rem;
|
||||
}
|
||||
li.current a { background-color: themed("color-foreground"); }
|
||||
|
||||
li.nav-hidden { display: none; }
|
||||
}
|
||||
|
||||
.nav-secondary {
|
||||
@ -493,18 +495,18 @@ nav.navigation, html.nav-toggled nav.navigation {
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
|
||||
.simple-avatar-button {
|
||||
.avatar-button {
|
||||
background: none;
|
||||
color: inherit;
|
||||
align-items: start;
|
||||
font-size: 0.875rem;
|
||||
line-height: 0.875rem;
|
||||
|
||||
.simple-avatar-name {
|
||||
.avatar-name {
|
||||
padding: 0 0.5rem;
|
||||
}
|
||||
|
||||
.simple-avatar-image {
|
||||
.avatar-image {
|
||||
height: 3rem;
|
||||
width: 3rem;
|
||||
background: themed("color-foreground");
|
||||
@ -526,9 +528,9 @@ nav.navigation, html.nav-toggled nav.navigation {
|
||||
}
|
||||
|
||||
// Stage 2: account label
|
||||
.collapse-2 .simple-avatar-name { display: none; }
|
||||
.collapse-2 .avatar-name { display: none; }
|
||||
@include window-larger-than(65rem) {
|
||||
.collapse-2 .simple-avatar-name { display: unset; }
|
||||
.collapse-2 .avatar-name { display: unset; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -562,10 +564,10 @@ body.c-static.a-home {
|
||||
position: static;
|
||||
height: unset;
|
||||
padding: 0;
|
||||
.simple-avatar-button {
|
||||
.avatar-button {
|
||||
height: unset;
|
||||
align-items: center;
|
||||
.simple-avatar-image { display: none; }
|
||||
.avatar-image { display: none; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ div#notice {
|
||||
top: 1rem;
|
||||
left: 25%;
|
||||
width: 50%;
|
||||
z-index: 100;
|
||||
z-index: 500;
|
||||
|
||||
color: themed("color-text");
|
||||
background-color: themed("color-success");
|
||||
|
@ -102,7 +102,7 @@ nav.pagination {
|
||||
|
||||
|
||||
// Sequential paginator
|
||||
.paginator.sequential {
|
||||
nav.pagination.sequential {
|
||||
gap: 5rem;
|
||||
a span { display: block; }
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
textarea {
|
||||
|
||||
// Override default texarea styles
|
||||
font-family: Verdana, sans-serif;
|
||||
font-family: $base_font_family;
|
||||
font-size: 1rem;
|
||||
line-height: 1rem;
|
||||
padding: 0.5rem 0 0.5rem 0.5rem;
|
||||
@ -30,7 +30,7 @@
|
||||
// Disable manual resizing
|
||||
resize: none;
|
||||
|
||||
border-radius: 3px 0 0 3px;
|
||||
border-radius: 0.25rem 0 0 0.25rem;
|
||||
box-sizing: border-box;
|
||||
flex: 1;
|
||||
|
||||
@ -43,19 +43,27 @@
|
||||
font-size: unset;
|
||||
max-width: unset;
|
||||
|
||||
font-size: 1rem;
|
||||
line-height: 1rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0.5rem;
|
||||
|
||||
border-radius: 0 3px 3px 0;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
background: white;
|
||||
color: black;
|
||||
|
||||
span { display: none; }
|
||||
svg {
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
margin: -0.25rem 0 -0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
@include window-larger-than(800px) {
|
||||
textarea, button[type="submit"] {
|
||||
font-size: 0.85rem;
|
||||
textarea { font-size: 0.85rem; }
|
||||
button[type="submit"] svg {
|
||||
height: 1.25rem;
|
||||
width: 1.25rem;
|
||||
margin: -0.125rem 0 -0.125rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,8 +92,6 @@ table.search {
|
||||
}
|
||||
|
||||
table.aligned-vertical {
|
||||
@extend .search;
|
||||
|
||||
tr {
|
||||
height: 1.75em;
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ body.c-static.a-home {
|
||||
input[type="text"] {
|
||||
flex: 1;
|
||||
border: 0;
|
||||
border-radius: 3px 0 0 3px;
|
||||
border-radius: 0.25rem 0 0 0.25rem;
|
||||
padding: 0.5rem;
|
||||
font-size: 1rem;
|
||||
|
||||
@ -57,9 +57,14 @@ body.c-static.a-home {
|
||||
|
||||
button[type="submit"] {
|
||||
background: white;
|
||||
border-radius: 0 3px 3px 0;
|
||||
padding: 0 0.5em;
|
||||
font-size: 1rem;
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
padding: 0 0.5rem;
|
||||
|
||||
svg {
|
||||
height: 1.25rem;
|
||||
width: 1.25rem;
|
||||
margin: -0.125rem 0 -0.125rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,287 +0,0 @@
|
||||
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;
|
||||
|
||||
grid-template-areas:
|
||||
"search "
|
||||
"content"
|
||||
"sidebar";
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: min-content 1fr min-content;
|
||||
|
||||
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.25rem;
|
||||
}
|
||||
|
||||
// Actual content area:
|
||||
// posts and pagination
|
||||
.post-index-gallery {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 1rem;
|
||||
|
||||
flex: 1; // See Exhibit A
|
||||
|
||||
.posts-container {
|
||||
flex: 1; // See Exhibit A
|
||||
grid-auto-rows: min-content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Sidebar
|
||||
.sidebar {
|
||||
grid-area: sidebar;
|
||||
|
||||
display: flex;
|
||||
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%;
|
||||
|
||||
// Match the searchbox
|
||||
padding: 0.5em;
|
||||
font-family: Verdana, sans-serif;
|
||||
font-size: 1.05em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Desktop
|
||||
.post-index {
|
||||
@include window-larger-than(50rem) {
|
||||
grid-template-areas:
|
||||
"search content"
|
||||
"sidebar content";
|
||||
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;
|
||||
|
||||
&.hidden { display: none; }
|
||||
|
||||
// header
|
||||
h3 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 1rem;
|
||||
padding: 0.5rem;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
& > svg {
|
||||
transition: transform 0.25s;
|
||||
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.wiki-excerpt-dismiss { margin-left: auto; }
|
||||
}
|
||||
|
||||
// body
|
||||
.styled-dtext {
|
||||
background: linear-gradient(to top, themed("color-section"), themed("color-text"));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
|
||||
min-height: 0rem;
|
||||
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 svg { transform: rotate(90deg); }
|
||||
.styled-dtext {
|
||||
max-height: 10rem;
|
||||
min-height: 2rem;
|
||||
}
|
||||
.wiki-excerpt-readmore { visibility: visible; }
|
||||
}
|
||||
|
||||
&.loading {
|
||||
h3::after, .styled-dtext { transition: none; }
|
||||
}
|
||||
}
|
@ -15,7 +15,7 @@ div#c-users {
|
||||
gap: 1em;
|
||||
|
||||
& > div {
|
||||
max-width: 1600px;
|
||||
max-width: 100rem;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@ -76,107 +76,7 @@ div#c-users {
|
||||
// Middle section: uploads and favorites
|
||||
.blacklist-ui { padding: 0; }
|
||||
|
||||
.posts-section {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 1em;
|
||||
|
||||
.profile-sample {
|
||||
display: grid;
|
||||
grid-template: "p-header"
|
||||
"p-links"
|
||||
"p-posts";
|
||||
gap: 0.5em 0;
|
||||
|
||||
@include window-larger-than(800px) {
|
||||
grid-template: "p-header p-links"
|
||||
"p-posts p-posts";
|
||||
grid-template-columns: 12em 1fr;
|
||||
gap: 0 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-sample-header a, .profile-sample-links a {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
align-content: center;
|
||||
text-align: center;
|
||||
|
||||
height: 100%;
|
||||
padding: 0.5em;
|
||||
border-radius: 6px;
|
||||
background-color: themed("color-section");
|
||||
|
||||
&:hover {
|
||||
background-color: themed("color-section-lighten-5");
|
||||
}
|
||||
&:focus, &:active {
|
||||
outline: 0;
|
||||
color: themed("color-link-active");
|
||||
}
|
||||
}
|
||||
|
||||
.profile-sample-header {
|
||||
grid-area: p-header;
|
||||
display: flex;
|
||||
|
||||
a {
|
||||
font-size: 1.25em;
|
||||
font-weight: bold;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@include window-larger-than(800px) {
|
||||
a { border-radius: 6px 6px 0 0; }
|
||||
}
|
||||
}
|
||||
|
||||
.profile-sample-links {
|
||||
grid-area: p-links;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.5rem;
|
||||
text-align: center;
|
||||
|
||||
span {
|
||||
padding: 0.5em;
|
||||
color: themed("color-text-muted");
|
||||
}
|
||||
|
||||
.spacer { display: none; }
|
||||
.profile-comments-link {
|
||||
grid-row: 1 / 3;
|
||||
grid-column: 3;
|
||||
}
|
||||
|
||||
@include window-larger-than(800px) {
|
||||
display: flex;
|
||||
a { height: min-content; }
|
||||
.spacer { display: block; }
|
||||
}
|
||||
}
|
||||
|
||||
.profile-sample-posts {
|
||||
grid-area: p-posts;
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
gap: 1em;
|
||||
padding: 0.5em;
|
||||
|
||||
background: var(--color-section);
|
||||
border-radius: 6px;
|
||||
|
||||
// Desktop
|
||||
@include window-larger-than(800px) {
|
||||
flex-wrap: nowrap;
|
||||
border-top-left-radius: 0;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Bottom section: about me and commission info
|
||||
@ -200,29 +100,6 @@ div#c-users {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div#a-edit {
|
||||
h1 {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
div.input {
|
||||
margin-bottom: 2em;
|
||||
}
|
||||
|
||||
div.input span.hint {
|
||||
display: block;
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
.active {
|
||||
color: themed("color-link-active");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// User signup and login
|
||||
|
@ -0,0 +1,3 @@
|
||||
@import "avatar";
|
||||
@import "feedback_badge";
|
||||
@import "level_badge";
|
41
app/javascript/src/styles/views/application/_avatar.scss
Normal file
41
app/javascript/src/styles/views/application/_avatar.scss
Normal file
@ -0,0 +1,41 @@
|
||||
.profile-avatar {
|
||||
.avatar-image {
|
||||
display: flex;
|
||||
width: 5rem;
|
||||
height: 5rem;
|
||||
|
||||
position: relative;
|
||||
|
||||
background: themed("color-section");
|
||||
@include st-radius;
|
||||
|
||||
// Letter if no avatar image
|
||||
&::after {
|
||||
content: attr(data-initial);
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
font-size: 5rem;
|
||||
font-weight: bold;
|
||||
color: themed("color-foreground");
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
// On top of the letter
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
z-index: 1;
|
||||
|
||||
@include st-radius;
|
||||
}
|
||||
}
|
||||
}
|
103
app/javascript/src/styles/views/application/_feedback_badge.scss
Normal file
103
app/javascript/src/styles/views/application/_feedback_badge.scss
Normal file
@ -0,0 +1,103 @@
|
||||
$hex-size: 1.25rem;
|
||||
|
||||
.user-record {
|
||||
display: flex;
|
||||
|
||||
height: $hex-size * 0.6; // 0.75rem
|
||||
width: $hex-size; // 1.25rem
|
||||
margin: ($hex-size / 5) 0; // 0.25rem 0
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: ($hex-size / 5 * 4) * 0.9;
|
||||
svg { width: ($hex-size / 5 * 4) * 0.9; }
|
||||
|
||||
background: palette("plain-black");
|
||||
color: white;
|
||||
|
||||
// Place corners under the text
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
|
||||
&::before, &::after {
|
||||
content: "";
|
||||
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
|
||||
border-left: ($hex-size / 2) solid transparent;
|
||||
border-right: ($hex-size / 2) solid transparent;
|
||||
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
&::before {
|
||||
top: -($hex-size / 5);
|
||||
border-bottom: ($hex-size / 5) solid palette("plain-black");
|
||||
}
|
||||
|
||||
&::after {
|
||||
bottom: -($hex-size / 5);
|
||||
border-top: ($hex-size / 5) solid palette("plain-black");
|
||||
}
|
||||
|
||||
|
||||
// Variations
|
||||
&.deleted {
|
||||
background: palette("background-yellow");
|
||||
&::before { border-bottom-color: palette("background-yellow"); }
|
||||
&::after { border-top-color: palette("background-yellow"); }
|
||||
}
|
||||
|
||||
&.negative {
|
||||
background: palette("background-red");
|
||||
&::before { border-bottom-color: palette("background-red"); }
|
||||
&::after { border-top-color: palette("background-red"); }
|
||||
}
|
||||
|
||||
&.neutral {
|
||||
background: palette("background-grey");
|
||||
&::before { border-bottom-color: palette("background-grey"); }
|
||||
&::after { border-top-color: palette("background-grey"); }
|
||||
}
|
||||
|
||||
&.positive {
|
||||
background: palette("background-green");
|
||||
&::before { border-bottom-color: palette("background-green"); }
|
||||
&::after { border-top-color: palette("background-green"); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.user-records-list {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
gap: 0.25rem;
|
||||
|
||||
&:hover .user-record {
|
||||
&.deleted {
|
||||
background: palette("background-yellow-d5");
|
||||
&::before { border-bottom-color: palette("background-yellow-d5"); }
|
||||
&::after { border-top-color: palette("background-yellow-d5"); }
|
||||
}
|
||||
|
||||
&.negative {
|
||||
background: palette("background-red-d5");
|
||||
&::before { border-bottom-color: palette("background-red-d5"); }
|
||||
&::after { border-top-color: palette("background-red-d5"); }
|
||||
}
|
||||
|
||||
&.neutral {
|
||||
background: palette("background-grey-d5");
|
||||
&::before { border-bottom-color: palette("background-grey-d5"); }
|
||||
&::after { border-top-color: palette("background-grey-d5"); }
|
||||
}
|
||||
|
||||
&.positive {
|
||||
background: palette("background-green-d5");
|
||||
&::before { border-bottom-color: palette("background-green-d5"); }
|
||||
&::after { border-top-color: palette("background-green-d5"); }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
$user-levels: (
|
||||
"unactivated"
|
||||
"blocked"
|
||||
"member"
|
||||
"privileged"
|
||||
"former-staff"
|
||||
"janitor"
|
||||
"moderator"
|
||||
"admin"
|
||||
);
|
||||
$user-level-text: (
|
||||
"moderator": #ffffff,
|
||||
"janitor": #ffffff,
|
||||
);
|
||||
|
||||
.level-badge {
|
||||
font-weight: bold;
|
||||
font-size: 0.65rem;
|
||||
color: black;
|
||||
|
||||
background: themed("color-user-member");
|
||||
padding: 0.1rem 0.25rem;
|
||||
@include st-radius;
|
||||
|
||||
@each $level in $user-levels {
|
||||
&.level-#{$level} {
|
||||
background: themed("color-user-" + $level);
|
||||
}
|
||||
}
|
||||
@each $level, $color in $user-level-text {
|
||||
&.level-#{$level} {
|
||||
color: $color;
|
||||
}
|
||||
}
|
||||
|
||||
&.level-unactivated {
|
||||
background: themed("palette-background-red");
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
19
app/javascript/src/styles/views/posts/_posts.scss
Normal file
19
app/javascript/src/styles/views/posts/_posts.scss
Normal file
@ -0,0 +1,19 @@
|
||||
// Main themes
|
||||
@import "index/index";
|
||||
@include window-larger-than(50rem) {
|
||||
@import "index/index.desktop";
|
||||
}
|
||||
|
||||
// Features
|
||||
@import "index/partials/mode_menu";
|
||||
@import "index/partials/wiki_excerpt";
|
||||
@import "index/partials/stats";
|
||||
|
||||
@include window-larger-than(50rem) {
|
||||
@include with-setting("fullscreen", "true") {
|
||||
@import "index/partials/fullscreen";
|
||||
}
|
||||
@include with-setting("ssearch", "true") {
|
||||
@import "index/partials/sticky";
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
// Desktop-only
|
||||
// Rollout at 50rem
|
||||
.post-index {
|
||||
grid-template-areas:
|
||||
"search content"
|
||||
"sidebar content";
|
||||
grid-template-columns: 15rem 1fr;
|
||||
grid-template-rows: min-content 1fr;
|
||||
|
||||
.search {
|
||||
box-shadow: inset -0.25rem 0px 0.25rem -0.25rem themed("color-background");
|
||||
padding: 0.5rem 0.75rem 0.5rem 0.5rem;
|
||||
|
||||
// Align the controls properly
|
||||
position: relative;
|
||||
|
||||
.search-controls {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
justify-content: right;
|
||||
|
||||
position: absolute;
|
||||
bottom: -1.633rem;
|
||||
right: 0.5rem;
|
||||
|
||||
padding: 0.25rem;
|
||||
gap: 0.5rem;
|
||||
|
||||
background: themed("color-foreground");
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
|
||||
button {
|
||||
height: 1.5rem;
|
||||
padding: 0;
|
||||
|
||||
svg {
|
||||
height: 1.25rem;
|
||||
width: 1.25rem;
|
||||
padding: 0.25rem;
|
||||
margin: -0.125rem 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
box-shadow: inset -0.25rem 0px 0.25rem -0.25rem themed("color-background");
|
||||
padding: 0.5rem 0.75rem 0.5rem 0.5rem;
|
||||
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
border-radius: 0 0.25rem 0.25rem 0;
|
||||
padding: 0.5rem 0.75rem themed("content-padding-bottom");
|
||||
}
|
||||
}
|
108
app/javascript/src/styles/views/posts/index/_index.scss
Normal file
108
app/javascript/src/styles/views/posts/index/_index.scss
Normal file
@ -0,0 +1,108 @@
|
||||
body.c-posts.a-index, body.c-favorites.a-index {
|
||||
#page {
|
||||
// Override the theme to instead
|
||||
// project it upon the content area
|
||||
background: var(--color-foreground);
|
||||
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 gallery
|
||||
.post-index {
|
||||
display: grid;
|
||||
|
||||
grid-template-areas:
|
||||
"search "
|
||||
"content"
|
||||
"sidebar";
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: min-content 1fr min-content;
|
||||
|
||||
flex: 1; // See Exhibit A
|
||||
|
||||
// 1. Searchbox
|
||||
.search {
|
||||
grid-area: search;
|
||||
|
||||
padding: 0.5rem 0.25rem;
|
||||
box-shadow: inset 0px -0.25rem 0.25rem -0.25rem themed("color-background");
|
||||
|
||||
h1 {
|
||||
font-size: $h3-size;
|
||||
}
|
||||
|
||||
.search-controls { display: none; }
|
||||
}
|
||||
|
||||
// 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.25rem;
|
||||
}
|
||||
|
||||
// Actual content area:
|
||||
// posts and pagination
|
||||
.post-index-gallery {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 1rem;
|
||||
|
||||
flex: 1; // See Exhibit A
|
||||
|
||||
.posts-container {
|
||||
flex: 1; // See Exhibit A
|
||||
grid-auto-rows: min-content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Sidebar
|
||||
.sidebar {
|
||||
grid-area: sidebar;
|
||||
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 1em;
|
||||
|
||||
padding: 0.5rem 0.25rem;
|
||||
box-shadow: inset 0px 0.25rem 0.25rem -0.25rem themed("color-background");
|
||||
|
||||
// By popular demand
|
||||
font-size: 150%;
|
||||
|
||||
// Mode selection
|
||||
#mode-box-mode, #mode-box #set-id {
|
||||
width: 100%;
|
||||
|
||||
// Match the searchbox
|
||||
padding: 0.5em;
|
||||
font-family: $base_font_family;
|
||||
font-size: 1.05em;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
// Fullscreen mode
|
||||
// Only relevant on desktop
|
||||
.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");
|
||||
|
||||
margin: 0.25rem 0 0;
|
||||
padding: 0.5rem;
|
||||
|
||||
flex-wrap: wrap;
|
||||
justify-content: right;
|
||||
z-index: 11; // above posts and labels
|
||||
|
||||
.post-search { width: 100%; }
|
||||
|
||||
#search-fullscreen {
|
||||
background: themed("color-button-active");
|
||||
color: black;
|
||||
}
|
||||
|
||||
.search-controls { right: 0.25rem; }
|
||||
}
|
||||
.sidebar { display: none; }
|
||||
.content {
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
.posts-index-stats { margin-right: 5rem; }
|
||||
}
|
||||
}
|
@ -32,4 +32,4 @@ $modes: (
|
||||
|
||||
input { flex: 1; }
|
||||
button { padding: 0 0.25em; }
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
.posts-index-stats {
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
|
||||
margin: -0.5rem 0rem 0.25rem;
|
||||
|
||||
font-size: 0.75rem;
|
||||
line-height: 0.75rem;
|
||||
color: #fffa;
|
||||
font-family: monospace;
|
||||
|
||||
& > span { cursor: help; }
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
.post-index .search {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
|
||||
background: themed("color-foreground");
|
||||
border-radius: 0.25rem;
|
||||
|
||||
// on top of thumbnail labels
|
||||
z-index: 11;
|
||||
|
||||
#search-sticky {
|
||||
background: themed("color-button-active");
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
|
||||
&[data-th-sheader="true"] {
|
||||
.post-index .search { top: 3.75rem; }
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
.wiki-excerpt {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
position: relative;
|
||||
|
||||
background: themed("color-section");
|
||||
border-radius: 0.25rem;
|
||||
|
||||
&.hidden { display: none; }
|
||||
|
||||
// header
|
||||
h3 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
font-size: 1rem;
|
||||
padding: 0.5rem;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
& > svg {
|
||||
transition: transform 0.25s;
|
||||
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
}
|
||||
|
||||
.wiki-excerpt-dismiss { margin-left: auto; }
|
||||
}
|
||||
|
||||
// body
|
||||
.styled-dtext {
|
||||
background: linear-gradient(to top, themed("color-section"), themed("color-text"));
|
||||
-webkit-background-clip: text;
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
|
||||
min-height: 0rem;
|
||||
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; }
|
||||
}
|
||||
|
||||
// Quote visual bug
|
||||
blockquote { background: unset; }
|
||||
|
||||
// Remove offset caused by paragraphs
|
||||
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 svg { transform: rotate(90deg); }
|
||||
.styled-dtext {
|
||||
max-height: 10rem;
|
||||
min-height: 2rem;
|
||||
}
|
||||
.wiki-excerpt-readmore { visibility: visible; }
|
||||
}
|
||||
|
||||
&.loading {
|
||||
h3::after, .styled-dtext { transition: none; }
|
||||
}
|
||||
}
|
2
app/javascript/src/styles/views/users/_users.scss
Normal file
2
app/javascript/src/styles/views/users/_users.scss
Normal file
@ -0,0 +1,2 @@
|
||||
@import "show/show";
|
||||
@import "edit/edit";
|
200
app/javascript/src/styles/views/users/edit/_edit.scss
Normal file
200
app/javascript/src/styles/views/users/edit/_edit.scss
Normal file
@ -0,0 +1,200 @@
|
||||
body.c-users.a-edit {
|
||||
|
||||
form.simple_form {
|
||||
background: unset;
|
||||
padding: unset;
|
||||
margin: unset;
|
||||
|
||||
input[type="text"], input[type="number"], textarea, select {
|
||||
width: 100%;
|
||||
max-width: unset;
|
||||
box-sizing: border-box;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 1rem;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
#settings-account-buttons tab-body {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 0.5rem;
|
||||
|
||||
.st-button {
|
||||
white-space: nowrap;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
tab-submit {
|
||||
input[type="submit"] {
|
||||
background: themed("color-tag-artist");
|
||||
font-size: 1.25rem;
|
||||
padding: 0.25rem 1rem;
|
||||
margin: 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
|
||||
&:hover, &:active { background: themed("color-tag-artist-alt"); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Tabs section
|
||||
tabs-menu {
|
||||
margin-top: 0.5rem;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
max-width: 50rem;
|
||||
flex-wrap: wrap;
|
||||
|
||||
// TODO Smooth drag when overflowing
|
||||
overflow: auto;
|
||||
|
||||
& > button {
|
||||
background: unset;
|
||||
color: themed("color-link");
|
||||
padding: 0.5rem 1rem;
|
||||
border-bottom: 2px solid themed("color-section");
|
||||
font-size: 1rem;
|
||||
line-height: 1rem;
|
||||
|
||||
&.active {
|
||||
background: themed("color-section");
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
&:first-child {
|
||||
border-bottom-left-radius: 0.25rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
span.spacer {
|
||||
flex: 1;
|
||||
border-bottom: 2px solid themed("color-section");
|
||||
}
|
||||
|
||||
input[name="search"] {
|
||||
border-radius: 0 0 0.25rem 0.25rem;
|
||||
font-size: 1rem;
|
||||
line-height: 1rem;
|
||||
padding: 0.25rem;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Tabs structure
|
||||
tabs-content {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
max-width: 50rem;
|
||||
|
||||
tab-group {
|
||||
display: none;
|
||||
&.active { display: flex; }
|
||||
|
||||
font-size: 1rem;
|
||||
line-height: 1rem;
|
||||
padding: 0.5rem 0.75rem 0.5rem;
|
||||
margin: 0.5rem 0 0;
|
||||
|
||||
background: themed("color-section-lighten-5");
|
||||
border-radius: 0.25rem 0.25rem 0 0;
|
||||
}
|
||||
|
||||
tab-entry {
|
||||
display: none !important;
|
||||
&.active { display: grid !important; }
|
||||
&.flex.active { display: flex !important; }
|
||||
grid-template-areas: "head" "body" "hint";
|
||||
grid-template-columns: 1fr;
|
||||
|
||||
align-items: center;
|
||||
gap: 0.25rem;
|
||||
|
||||
background: themed("color-section");
|
||||
padding: 0.5rem;
|
||||
|
||||
tab-head {
|
||||
grid-area: head;
|
||||
margin-left: 0.25em;
|
||||
font-size: 0.85rem;
|
||||
|
||||
label { font-weight: normal; }
|
||||
}
|
||||
|
||||
tab-body {
|
||||
grid-area: body;
|
||||
}
|
||||
|
||||
tab-hint {
|
||||
grid-area: hint;
|
||||
|
||||
font-size: 90%;
|
||||
color: themed("color-text-muted");
|
||||
}
|
||||
|
||||
&.inline {
|
||||
grid-template-areas: "head body" "hint hint";
|
||||
grid-template-columns: 2fr 1fr;
|
||||
|
||||
tab-body { justify-self: end; }
|
||||
}
|
||||
|
||||
&.blocky {
|
||||
grid-template-areas: "body";
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
&.bigtext {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-areas: "head" "body" "hint";
|
||||
}
|
||||
|
||||
&.buttony tab-body {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 4rem;
|
||||
|
||||
input[type="text"] { border-radius: 0.25rem 0 0 0.25rem !important; }
|
||||
input[disabled] { cursor: not-allowed; }
|
||||
a.st-button {
|
||||
border-radius: 0 0.25rem 0.25rem 0 !important;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tab-submit {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
|
||||
background: themed("color-section");
|
||||
border-radius: 0.25rem;
|
||||
width: min-content;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
@include window-larger-than(50rem) {
|
||||
tabs-menu {
|
||||
input[name="search"] {
|
||||
width: unset;
|
||||
border-radius: 0.25rem 0.25rem 0.25rem 0;
|
||||
border-bottom: 2px solid themed("color-section");
|
||||
}
|
||||
}
|
||||
|
||||
tabs-content {
|
||||
tab-entry {
|
||||
grid-template-areas: "head body" ". hint";
|
||||
grid-template-columns: 1fr 1fr;
|
||||
&.inline {
|
||||
grid-template-areas: "head hint body";
|
||||
grid-template-columns: 8fr 7fr 1fr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
10
app/javascript/src/styles/views/users/show/_show.scss
Normal file
10
app/javascript/src/styles/views/users/show/_show.scss
Normal file
@ -0,0 +1,10 @@
|
||||
body.c-users.a-show {
|
||||
|
||||
@import "partials/about";
|
||||
@import "partials/ban_banner";
|
||||
@import "partials/card";
|
||||
@import "partials/post_summary";
|
||||
@import "partials/profile_section";
|
||||
@import "partials/staff_info";
|
||||
@import "partials/user_info";
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
tabs-menu, tabs-content {
|
||||
max-width: 100rem;
|
||||
}
|
||||
|
||||
#profile-tabs[data-has-about="false"][data-has-artinfo="false"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.profile-about-section, .profile-artinfo-section {
|
||||
flex-flow: column;
|
||||
align-items: start;
|
||||
|
||||
tab-head {
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@include window-larger-than(50rem) {
|
||||
tabs-menu { display: none; }
|
||||
tabs-content {
|
||||
display: grid;
|
||||
grid-template-columns: 15rem 1fr;
|
||||
grid-template-rows: min-content min-content;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.profile-user-info {
|
||||
display: grid !important;
|
||||
grid-template-areas: unset;
|
||||
grid-row: 1 / 4;
|
||||
height: min-content;
|
||||
}
|
||||
|
||||
.profile-about-section {
|
||||
display: flex !important;
|
||||
grid-column: 2 / -1;
|
||||
}
|
||||
|
||||
.profile-artinfo-section {
|
||||
display: flex !important;
|
||||
grid-column: 2 / -1;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
.profile-ban {
|
||||
background: var(--palette-background-red);
|
||||
padding: 0.5rem;
|
||||
@include st-radius;
|
||||
|
||||
.styled-dtext p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
.profile-card {
|
||||
display: grid;
|
||||
grid-template-columns: min-content auto;
|
||||
gap: 1rem;
|
||||
|
||||
// Info block
|
||||
.profile-info {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
justify-content: center;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.profile-name {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
gap: 0.5rem;
|
||||
align-items: center;
|
||||
|
||||
a {
|
||||
color: themed("color-text");
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-joined {
|
||||
font-size: 0.75rem;
|
||||
color: themed("color-text-muted");
|
||||
margin-top: -0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-quickie {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
|
||||
margin-top: 1rem;
|
||||
|
||||
.entry {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.entry > a {
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr;
|
||||
grid-template-areas:
|
||||
"icon header"
|
||||
"icon title ";
|
||||
column-gap: 0.25rem;
|
||||
align-items: center;
|
||||
|
||||
width: 7rem;
|
||||
padding: 0.5rem;
|
||||
font-size: 1rem;
|
||||
|
||||
@include st-radius;
|
||||
background: themed("color-section");
|
||||
|
||||
&:hover { background: themed("color-section-lighten-5"); }
|
||||
|
||||
.entry-icon {
|
||||
grid-area: icon;
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
color: themed("color-link-active");
|
||||
}
|
||||
.entry-header {
|
||||
grid-area: header;
|
||||
font-size: 1.1rem;
|
||||
line-height: 1.1rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.entry-title {
|
||||
grid-area: title;
|
||||
font-size: 0.9rem;
|
||||
line-height: 0.9rem;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.entry-extra {
|
||||
a, a:visited { color: themed("color-text-muted"); }
|
||||
a:hover, a:active { color: themed("color-link-active"); }
|
||||
}
|
||||
}
|
@ -0,0 +1,107 @@
|
||||
.posts-section {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
gap: 1em;
|
||||
|
||||
// Hack to fix spacing on mobile
|
||||
margin-top: 1rem;
|
||||
@include window-larger-than(50rem) {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.profile-sample {
|
||||
display: grid;
|
||||
grid-template: "p-header"
|
||||
"p-links"
|
||||
"p-posts";
|
||||
gap: 0.5em 0;
|
||||
|
||||
@include window-larger-than(50rem) {
|
||||
grid-template: "p-header p-links"
|
||||
"p-posts p-posts";
|
||||
grid-template-columns: 12em 1fr;
|
||||
gap: 0 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-sample-header a, .profile-sample-links a {
|
||||
display: block;
|
||||
box-sizing: border-box;
|
||||
align-content: center;
|
||||
text-align: center;
|
||||
|
||||
height: 100%;
|
||||
padding: 0.5em;
|
||||
border-radius: 6px;
|
||||
background-color: themed("color-section");
|
||||
|
||||
&:hover {
|
||||
background-color: themed("color-section-lighten-5");
|
||||
}
|
||||
&:focus, &:active {
|
||||
outline: 0;
|
||||
color: themed("color-link-active");
|
||||
}
|
||||
}
|
||||
|
||||
.profile-sample-header {
|
||||
grid-area: p-header;
|
||||
display: flex;
|
||||
|
||||
a {
|
||||
font-size: 1.25em;
|
||||
font-weight: bold;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@include window-larger-than(800px) {
|
||||
a { border-radius: 6px 6px 0 0; }
|
||||
}
|
||||
}
|
||||
|
||||
.profile-sample-links {
|
||||
grid-area: p-links;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 0.5rem;
|
||||
text-align: center;
|
||||
|
||||
span {
|
||||
padding: 0.5em;
|
||||
color: themed("color-text-muted");
|
||||
}
|
||||
|
||||
.spacer { display: none; }
|
||||
.profile-comments-link {
|
||||
grid-row: 1 / 3;
|
||||
grid-column: 3;
|
||||
}
|
||||
|
||||
@include window-larger-than(50rem) {
|
||||
display: flex;
|
||||
a { height: min-content; }
|
||||
.spacer { display: block; }
|
||||
}
|
||||
}
|
||||
|
||||
.profile-sample-posts {
|
||||
grid-area: p-posts;
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
gap: 1em;
|
||||
padding: 0.5em;
|
||||
|
||||
background: var(--color-section);
|
||||
border-radius: 6px;
|
||||
|
||||
// Desktop
|
||||
@include window-larger-than(50rem) {
|
||||
flex-wrap: nowrap;
|
||||
border-top-left-radius: 0;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
.profile-section {
|
||||
background: themed("color-section");
|
||||
|
||||
.profile-section-header {
|
||||
background: themed("color-section-lighten-5");
|
||||
@include st-radius;
|
||||
padding: 0.25rem 0.5rem;
|
||||
cursor: pointer;
|
||||
|
||||
&::before {
|
||||
content: "⮟";
|
||||
display: inline-flex;
|
||||
transition: transform 200ms;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-section-body {
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0 0 radius() radius();
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// Collapsed
|
||||
&.hidden {
|
||||
.profile-section-header::before {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.profile-section-body {
|
||||
padding: 0 0.5rem;
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
.profile-staff-info {
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr;
|
||||
gap: 0.25rem 1rem;
|
||||
|
||||
h4 {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.block { grid-column: 1 / -1; }
|
||||
h4.block { margin-bottom: -0.25rem; }
|
||||
|
||||
@include window-larger-than(50rem) {
|
||||
grid-template-columns: min-content 1fr min-content 1fr;
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
.profile-user-info {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: repeat(auto-fit, minmax(min-content, 5rem));
|
||||
background: themed("color-section");
|
||||
@include st-radius;
|
||||
|
||||
@include window-larger-than(38rem) { grid-template-columns: 1fr 1fr; }
|
||||
@include window-larger-than(50rem) { grid-template-columns: 1fr; }
|
||||
|
||||
.profile-line {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr min-content;
|
||||
padding: 1rem 0.5rem;
|
||||
border-bottom: 2px solid themed("color-foreground");
|
||||
|
||||
h4 {
|
||||
// Not necessary, but it aligns
|
||||
// with the -extra line better
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.25em;
|
||||
|
||||
svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
||||
&-number {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&-extra {
|
||||
grid-column: 1 / -1;
|
||||
font-size: 90%;
|
||||
color: themed("color-text-muted");
|
||||
|
||||
margin-left: 1.25em;
|
||||
}
|
||||
|
||||
// Stats display section
|
||||
&-show {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem 2rem;
|
||||
margin-top: 0.5rem;
|
||||
|
||||
.entry {
|
||||
text-align: center;
|
||||
width: 5rem;
|
||||
& > span { color: themed("color-text-muted"); }
|
||||
}
|
||||
}
|
||||
|
||||
// Dot-separated, less important
|
||||
&-list {
|
||||
display: flex;
|
||||
gap: 0.25em;
|
||||
|
||||
a:not(:last-child)::after {
|
||||
content: "•";
|
||||
margin-left: 0.25rem;
|
||||
color: themed("color-text-muted");
|
||||
}
|
||||
}
|
||||
|
||||
&:last-child { border-bottom: none; }
|
||||
}
|
||||
}
|
@ -487,6 +487,8 @@ class Artist < ApplicationRecord
|
||||
|
||||
if params[:is_linked].to_s.truthy?
|
||||
q = q.where("linked_user_id IS NOT NULL")
|
||||
elsif params[:is_linked].to_s.falsy?
|
||||
q = q.where("linked_user_id IS NULL")
|
||||
end
|
||||
|
||||
case params[:order]
|
||||
|
@ -80,10 +80,14 @@ class Tag < ApplicationRecord
|
||||
|
||||
def category_for(tag_name)
|
||||
Cache.fetch("tc:#{tag_name}") do
|
||||
Tag.where(name: tag_name).pick(:category).to_i
|
||||
category_for!(tag_name).to_i
|
||||
end
|
||||
end
|
||||
|
||||
def category_for!(tag_name)
|
||||
Tag.where(name: tag_name).pick(:category)
|
||||
end
|
||||
|
||||
def categories_for(tag_names, disable_cache: false)
|
||||
if disable_cache
|
||||
tag_cats = {}
|
||||
|
@ -574,6 +574,11 @@ class User < ApplicationRecord
|
||||
base_upload_limit + (pieces[:approved] / 10) - (pieces[:deleted] / 4) - pieces[:pending]
|
||||
end
|
||||
|
||||
def upload_limit_max
|
||||
pieces = upload_limit_pieces
|
||||
base_upload_limit + (pieces[:approved] / 10) - (pieces[:deleted] / 4)
|
||||
end
|
||||
|
||||
def upload_limit_pieces
|
||||
@upload_limit_pieces ||= begin
|
||||
deleted_count = Post.deleted.for_user(id).count
|
||||
@ -739,6 +744,28 @@ class User < ApplicationRecord
|
||||
user_status.ticket_count
|
||||
end
|
||||
|
||||
def feedback_pieces
|
||||
@feedback_pieces ||= begin
|
||||
count = {
|
||||
deleted: 0,
|
||||
negative: 0,
|
||||
neutral: 0,
|
||||
positive: 0,
|
||||
}
|
||||
|
||||
feedback.each do |one|
|
||||
if one.is_deleted
|
||||
count[:deleted] += 1
|
||||
next
|
||||
end
|
||||
|
||||
count[one.category.to_sym] += 1
|
||||
end
|
||||
|
||||
count
|
||||
end
|
||||
end
|
||||
|
||||
def positive_feedback_count
|
||||
feedback.active.positive.count
|
||||
end
|
||||
|
@ -1,14 +1,21 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class WikiPage < ApplicationRecord
|
||||
class RevertError < Exception ; end
|
||||
class RevertError < Exception; end
|
||||
|
||||
before_validation :normalize_title
|
||||
before_validation :normalize_other_names
|
||||
before_validation :normalize_parent
|
||||
before_save :log_changes
|
||||
before_save :update_tag, if: :tag_changed?
|
||||
before_destroy :validate_not_used_as_help_page
|
||||
before_destroy :log_destroy
|
||||
after_save :create_version
|
||||
after_save :update_help_page, if: :saved_change_to_title?
|
||||
|
||||
normalizes :body, with: ->(body) { body.gsub("\r\n", "\n") }
|
||||
validates :title, uniqueness: { :case_sensitive => false }
|
||||
|
||||
validates :title, uniqueness: { case_sensitive: false }
|
||||
validates :title, presence: true
|
||||
validates :title, tag_name: true, if: :title_changed?
|
||||
validates :body, presence: { unless: -> { is_deleted? || other_names.present? || parent.present? } }
|
||||
@ -19,12 +26,8 @@ class WikiPage < ApplicationRecord
|
||||
validate :validate_redirect
|
||||
validate :validate_not_locked
|
||||
|
||||
before_destroy :validate_not_used_as_help_page
|
||||
before_destroy :log_destroy
|
||||
before_save :log_changes
|
||||
after_save :update_help_page, if: :saved_change_to_title?
|
||||
|
||||
attr_accessor :skip_secondary_validations, :edit_reason
|
||||
|
||||
array_attribute :other_names
|
||||
belongs_to_creator
|
||||
belongs_to_updater
|
||||
@ -33,19 +36,19 @@ class WikiPage < ApplicationRecord
|
||||
has_many :versions, -> { order("wiki_page_versions.id ASC") }, class_name: "WikiPageVersion", dependent: :destroy
|
||||
has_one :help_page, foreign_key: "wiki_page", primary_key: "title"
|
||||
|
||||
def log_destroy
|
||||
ModAction.log(:wiki_page_delete, {wiki_page: title, wiki_page_id: id})
|
||||
end
|
||||
|
||||
def log_changes
|
||||
if title_changed? && !new_record?
|
||||
ModAction.log(:wiki_page_rename, {new_title: title, old_title: title_was})
|
||||
ModAction.log(:wiki_page_rename, { new_title: title, old_title: title_was })
|
||||
end
|
||||
if is_locked_changed?
|
||||
ModAction.log(is_locked ? :wiki_page_lock : :wiki_page_unlock, {wiki_page: title})
|
||||
ModAction.log(is_locked ? :wiki_page_lock : :wiki_page_unlock, { wiki_page: title })
|
||||
end
|
||||
end
|
||||
|
||||
def log_destroy
|
||||
ModAction.log(:wiki_page_delete, { wiki_page: title, wiki_page_id: id })
|
||||
end
|
||||
|
||||
module SearchMethods
|
||||
def titled(title)
|
||||
find_by(title: WikiPage.normalize_name(title))
|
||||
@ -123,7 +126,7 @@ class WikiPage < ApplicationRecord
|
||||
|
||||
module ApiMethods
|
||||
def method_attributes
|
||||
super + [:creator_name, :category_id]
|
||||
super + %i[creator_name category_id]
|
||||
end
|
||||
end
|
||||
|
||||
@ -140,9 +143,92 @@ class WikiPage < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
module TagMethods
|
||||
def tag
|
||||
@tag ||= super
|
||||
end
|
||||
|
||||
def category_id
|
||||
return @category_id if instance_variable_defined?(:@category_id)
|
||||
@category_id = tag&.category
|
||||
end
|
||||
|
||||
def category_id=(value)
|
||||
return if value.blank? || value.to_i == category_id
|
||||
category_id_will_change!
|
||||
@category_id = value.to_i
|
||||
end
|
||||
|
||||
def category_is_locked
|
||||
return @category_is_locked if instance_variable_defined?(:@category_is_locked)
|
||||
@category_is_locked = tag&.is_locked || false
|
||||
end
|
||||
|
||||
def category_is_locked=(value)
|
||||
return if value == category_is_locked
|
||||
category_is_locked_will_change!
|
||||
@category_is_locked = value
|
||||
end
|
||||
|
||||
def category_id_changed?
|
||||
attribute_changed?("category_id")
|
||||
end
|
||||
|
||||
def category_id_will_change!
|
||||
attribute_will_change!("category_id")
|
||||
end
|
||||
|
||||
def category_is_locked_changed?
|
||||
attribute_changed?("category_is_locked")
|
||||
end
|
||||
|
||||
def category_is_locked_will_change!
|
||||
attribute_will_change!("category_is_locked")
|
||||
end
|
||||
|
||||
def tag_update_map
|
||||
{}.tap do |updates|
|
||||
updates[:category] = @category_id if category_id_changed?
|
||||
updates[:is_locked] = @category_is_locked if category_is_locked_changed?
|
||||
end
|
||||
end
|
||||
|
||||
def tag_changed?
|
||||
tag_update_map.present?
|
||||
end
|
||||
|
||||
def update_tag
|
||||
updates = tag_update_map
|
||||
@tag = Tag.find_or_create_by_name(title)
|
||||
|
||||
return if updates.empty?
|
||||
unless @tag.category_editable_by?(CurrentUser.user)
|
||||
reload_tag_attributes
|
||||
errors.add(:category_id, "Cannot be changed")
|
||||
throw(:abort)
|
||||
end
|
||||
|
||||
@tag.update(updates)
|
||||
@tag.save
|
||||
|
||||
if @tag.invalid?
|
||||
errors.add(:category_id, @tag.errors.full_messages.join(", "))
|
||||
throw(:abort)
|
||||
end
|
||||
|
||||
reload_tag_attributes
|
||||
end
|
||||
|
||||
def reload_tag_attributes
|
||||
remove_instance_variable(:@category_id) if instance_variable_defined?(:@category_id)
|
||||
remove_instance_variable(:@category_is_locked) if instance_variable_defined?(:@category_is_locked)
|
||||
end
|
||||
end
|
||||
|
||||
extend SearchMethods
|
||||
include ApiMethods
|
||||
include HelpPageMethods
|
||||
include TagMethods
|
||||
|
||||
def user_not_limited
|
||||
allowed = CurrentUser.can_wiki_edit_with_reason
|
||||
@ -156,7 +242,7 @@ class WikiPage < ApplicationRecord
|
||||
def validate_not_locked
|
||||
if is_locked? && !CurrentUser.is_janitor?
|
||||
errors.add(:is_locked, "and cannot be updated")
|
||||
return false
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
@ -203,7 +289,12 @@ class WikiPage < ApplicationRecord
|
||||
end
|
||||
|
||||
def normalize_title
|
||||
self.title = title.downcase.tr(" ", "_")
|
||||
title = self.title.downcase.tr(" ", "_")
|
||||
if title =~ /\A(#{Tag.categories.regexp}):(.+)\Z/
|
||||
self.category_id = Tag.categories.value_for($1)
|
||||
title = $2
|
||||
end
|
||||
self.title = title
|
||||
end
|
||||
|
||||
def normalize_other_names
|
||||
@ -226,16 +317,12 @@ class WikiPage < ApplicationRecord
|
||||
@skip_secondary_validations = value.to_s.truthy?
|
||||
end
|
||||
|
||||
def category_id
|
||||
Tag.category_for(title)
|
||||
end
|
||||
|
||||
def pretty_title
|
||||
title&.tr("_", " ") || ''
|
||||
title&.tr("_", " ") || ""
|
||||
end
|
||||
|
||||
def pretty_title_with_category
|
||||
return pretty_title if category_id == 0
|
||||
return pretty_title if category_id.blank? || category_id == 0
|
||||
"#{Tag.category_for_value(category_id)}: #{pretty_title}"
|
||||
end
|
||||
|
||||
@ -274,10 +361,6 @@ class WikiPage < ApplicationRecord
|
||||
else
|
||||
match
|
||||
end
|
||||
end.map {|x| x.downcase.tr(" ", "_").to_s}.uniq
|
||||
end
|
||||
|
||||
def visible?
|
||||
true
|
||||
end.map { |x| x.downcase.tr(" ", "_").to_s }.uniq
|
||||
end
|
||||
end
|
||||
|
@ -6,7 +6,6 @@ class WikiPageVersion < ApplicationRecord
|
||||
belongs_to_updater
|
||||
user_status_counter :wiki_edit_count, foreign_key: :updater_id
|
||||
belongs_to :artist, optional: true
|
||||
delegate :visible?, to: :wiki_page
|
||||
|
||||
module SearchMethods
|
||||
def for_user(user_id)
|
||||
|
@ -53,6 +53,11 @@ class UserPresenter
|
||||
= <abbr title="User Upload Limit Remaining">#{user.upload_limit}</abbr>}.html_safe
|
||||
end
|
||||
|
||||
def upload_limit_short
|
||||
return "none" if user.can_upload_free?
|
||||
"#{user.upload_limit} / #{user.upload_limit_max}"
|
||||
end
|
||||
|
||||
def uploads
|
||||
posts = Post.tag_match("user:#{user.name}").limit(8)
|
||||
PostsDecorator.decorate_collection(posts)
|
||||
|
34
app/views/application/_feedback_badge.erb
Normal file
34
app/views/application/_feedback_badge.erb
Normal file
@ -0,0 +1,34 @@
|
||||
<a
|
||||
href="<%= user_feedbacks_path(search: { user_id: user.id }) %>"
|
||||
class="user-records-list"
|
||||
data-negative="<%= negative %>"
|
||||
data-neutral="<%= negative %>"
|
||||
data-positive="<%= neutral %>"
|
||||
data-total="<%= positive - negative %>"
|
||||
>
|
||||
<% if deleted > 0 %>
|
||||
<span class="user-record deleted"><%= deleted %></span>
|
||||
<% end %>
|
||||
|
||||
<% if negative > 0 %>
|
||||
<span class="user-record negative"><%= negative %></span>
|
||||
<% end %>
|
||||
|
||||
<% if neutral > 0 %>
|
||||
<span class="user-record neutral"><%= neutral %></span>
|
||||
<% end %>
|
||||
|
||||
<% if positive > 0 %>
|
||||
<span class="user-record positive"><%= positive %></span>
|
||||
<% end %>
|
||||
</a>
|
||||
|
||||
<% if CurrentUser.is_moderator? && CurrentUser.user != user && active == 0 %>
|
||||
<a
|
||||
href="<%= new_user_feedback_path(user_feedback: { user_id: user.id, category: "neutral" }) %>"
|
||||
class="user-records-list"
|
||||
title="New Feedback"
|
||||
>
|
||||
<span class="user-record neutral"><%= svg_icon(:plus) %></span>
|
||||
</a>
|
||||
<% end %>
|
11
app/views/application/_profile_avatar.erb
Normal file
11
app/views/application/_profile_avatar.erb
Normal file
@ -0,0 +1,11 @@
|
||||
<a
|
||||
href="<%= user_path(user) %>"
|
||||
class="profile-avatar placeholder<%= klass.nil? ? "" : klass%>"
|
||||
data-id="<%= post_id %>"
|
||||
data-name="<%= user.name %>"
|
||||
>
|
||||
<span
|
||||
class="avatar-image"
|
||||
data-initial="<%= user.name[0].capitalize%>"
|
||||
></span>
|
||||
</a>
|
@ -3,6 +3,6 @@
|
||||
<%= f.input :url_matches, label: "URL", as: :string %>
|
||||
<%= f.user :creator %>
|
||||
<%= f.input :has_tag, label: "Has tag?", collection: [["Yes", true], ["No", false]], include_blank: true %>
|
||||
<%= f.input :is_linked, label: "Linked Only", as: :boolean %>
|
||||
<%= f.input :is_linked, label: "Linked?", collection: [["Yes", true], ["No", false]], include_blank: true %>
|
||||
<%= f.input :order, collection: [["Recently created", "created_at"], ["Last updated", "updated_at"], ["Name", "name"], ["Post count", "post_count"]] %>
|
||||
<% end %>
|
||||
|
@ -1,3 +1,9 @@
|
||||
<% if CurrentUser.is_anonymous? %>
|
||||
<%= decorated_nav_link_to("Log In", :log_in, new_session_path, class: "nav-hidden") %>
|
||||
<% else %>
|
||||
<%= decorated_nav_link_to("Profile", :user, user_path(CurrentUser.user), class: "nav-hidden") %>
|
||||
<% end %>
|
||||
<%= 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) %>
|
||||
|
@ -20,11 +20,11 @@
|
||||
</a>
|
||||
<% if CurrentUser.is_anonymous? %>
|
||||
<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">
|
||||
<span class="avatar-button sign-in">
|
||||
<span class="avatar-name">
|
||||
Sign In
|
||||
</span>
|
||||
<span class="simple-avatar-image">
|
||||
<span class="avatar-image">
|
||||
<%= svg_icon(:log_in) %>
|
||||
</span>
|
||||
</span>
|
||||
|
@ -8,10 +8,12 @@
|
||||
"th-sheader": localStorage.getItem("theme-sheader") || false,
|
||||
"th-forumnotif": localStorage.getItem("theme-forumnotif") || false,
|
||||
"th-palette": localStorage.getItem("theme-palette") || "default",
|
||||
"th-font": localStorage.getItem("theme-font") || "Verdana",
|
||||
"th-nav": localStorage.getItem("theme-nav") || "top",
|
||||
|
||||
// Settings
|
||||
"st-fullscreen": localStorage.getItem("e6.posts.fusk") || false,
|
||||
"st-ssearch": localStorage.getItem("e6.posts.ssearch") || false,
|
||||
};
|
||||
|
||||
var b = document.body;
|
||||
|
@ -24,6 +24,7 @@
|
||||
<div class="content">
|
||||
<%= render "ads/leaderboard", tag_string: @post_set.ad_tag_string %>
|
||||
<%= render "posts/partials/index/edit" %>
|
||||
<%= render "posts/partials/index/stats", :post_set => @post_set %>
|
||||
<%= render "posts/partials/index/posts", :post_set => @post_set %>
|
||||
</div>
|
||||
|
||||
|
@ -10,6 +10,6 @@
|
||||
<% end %>
|
||||
|
||||
<%= text_area_tag("tags", tags, placeholder: "Search posts by tag (title:\"video name\")", rows: 1, data: { shortcut: "q", autocomplete: "tag-query" }) %>
|
||||
<%= tag.button(tag.i(class: "fa-solid fa-magnifying-glass"), type: "submit", title: "Search") %>
|
||||
<%= tag.button(svg_icon(:search), type: "submit", title: "Search") %>
|
||||
<% end %>
|
||||
</section>
|
||||
|
@ -1,6 +1,8 @@
|
||||
<div class="search-controls">
|
||||
<button id="search-fullscreen" class="st-button w100 stealth">
|
||||
<button id="search-fullscreen" class="st-button" title="Fullscreen mode">
|
||||
<%= svg_icon(:fullscreen) %>
|
||||
<span>Fullscreen</span>
|
||||
</button>
|
||||
<button id="search-sticky" class="st-button" title="Sticky searchbar">
|
||||
<%= svg_icon(:anchor) %>
|
||||
</button>
|
||||
</div>
|
||||
|
3
app/views/posts/partials/index/_stats.html.erb
Normal file
3
app/views/posts/partials/index/_stats.html.erb
Normal file
@ -0,0 +1,3 @@
|
||||
<div class="posts-index-stats">
|
||||
<%= approximate_count(post_set.posts) %>
|
||||
</div>
|
@ -1,15 +1,12 @@
|
||||
<% if CurrentUser.can_view_staff_notes? %>
|
||||
<div class="staff-notes-section styled-dtext">
|
||||
<details>
|
||||
<summary>Staff Notes (<%= user.staff_notes.count %>)</summary>
|
||||
<div>
|
||||
<h4><%= link_to "Staff Notes", staff_notes_path(search: { user_id: user.id }) %></h4>
|
||||
<%= render "staff_notes/partials/list_of_notes", staff_notes: user.staff_notes.limit(15), show_receiver_name: false %>
|
||||
<div class="new-staff-note">
|
||||
<p><%= link_to "Create »", new_staff_note_path(search: { user_id: user.id }), class: "expand-new-staff-note" %></p>
|
||||
<%= render "staff_notes/partials/new", user: user, staff_note: StaffNote.new(user_id: user.id), hidden: true %>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
<div class="profile-section hidden" name="StaffNotes">
|
||||
<div class="profile-section-header">Staff Notes (<%= user.staff_notes.count %>)</div>
|
||||
<div class="profile-section-body styled-dtext">
|
||||
<%= render "staff_notes/partials/list_of_notes", staff_notes: user.staff_notes.limit(15), show_receiver_name: false %>
|
||||
<div class="new-staff-note">
|
||||
<p><%= link_to "Create »", new_staff_note_path(search: { user_id: user.id }), class: "expand-new-staff-note" %></p>
|
||||
<%= render "staff_notes/partials/new", user: user, staff_note: StaffNote.new(user_id: user.id), hidden: true %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
@ -10,7 +10,7 @@
|
||||
<!-- 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") %>
|
||||
<%= tag.button(svg_icon(:search), type: "submit") %>
|
||||
</div>
|
||||
|
||||
<!-- Secondary search buttons -->
|
||||
|
@ -16,8 +16,8 @@
|
||||
This means that they will not persist across multiple devices, or in incognito mode.
|
||||
</p>
|
||||
|
||||
<label for="theme_main">Theme</label>
|
||||
<select id="theme_main">
|
||||
<label for="Theme_Main">Theme</label>
|
||||
<select id="Theme_Main">
|
||||
<option value="hexagon">Hexagon</option>
|
||||
<option value="bloodlust">Bloodlust</option>
|
||||
<option value="pony">Pony</option>
|
||||
@ -25,8 +25,8 @@
|
||||
<option value="hotdog">Hotdog</option>
|
||||
</select>
|
||||
|
||||
<label for="theme_extra">Embellishments</label>
|
||||
<select id="theme_extra">
|
||||
<label for="Theme_Extra">Embellishments</label>
|
||||
<select id="Theme_Extra">
|
||||
<option value="none">(None)</option>
|
||||
<option value="aurora">Aurora</option>
|
||||
<option value="autumn">Autumn</option>
|
||||
@ -37,42 +37,68 @@
|
||||
<option value="winter">Eternal Winter</option>
|
||||
</select>
|
||||
|
||||
<label for="theme_stickyheader">Sticky Header</label>
|
||||
<select id="theme_stickyheader">
|
||||
<option value="false">Disabled</option>
|
||||
<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">
|
||||
<label for="Theme_Palette">Palette</label>
|
||||
<select id="Theme_Palette">
|
||||
<option value="default">Default</option>
|
||||
<option value="deut">Protanopia & Deuteranopia</option>
|
||||
<option value="trit">Tritanopia</option>
|
||||
</select>
|
||||
|
||||
<label for="Theme_Font">Font</label>
|
||||
<select id="Theme_Font">
|
||||
<option value="Verdana">Verdana</option>
|
||||
<option value="Lato">Lato</option>
|
||||
<option value="Lexend">Lexend</option>
|
||||
<option value="Monospace">Monospace</option>
|
||||
<option value="OpenDyslexic">Open Dyslexic</option>
|
||||
<option value="OpenSans">Open Sans</option>
|
||||
<option value="ComicSans">Comic Sans</option>
|
||||
</select>
|
||||
|
||||
|
||||
<h3>Features</h3>
|
||||
<label for="Theme_ForumNotif">Forum Activity Dot</label>
|
||||
<select id="Theme_ForumNotif">
|
||||
<option value="false">Disabled</option>
|
||||
<option value="true">Enabled</option>
|
||||
</select>
|
||||
|
||||
<label for="Posts_WikiExcerpt">Wiki Excerpt</label>
|
||||
<select id="Posts_WikiExcerpt">
|
||||
<option value="0">Collapsed</option>
|
||||
<option value="1">Expanded</option>
|
||||
<option value="2">Disabled</option>
|
||||
</select>
|
||||
|
||||
|
||||
<h3>Navigation</h3>
|
||||
<label for="theme_navbar">Navbar location</label>
|
||||
<select id="theme_navbar">
|
||||
<label for="Theme_StickyHeader">Sticky Header</label>
|
||||
<select id="Theme_StickyHeader">
|
||||
<option value="false">Disabled</option>
|
||||
<option value="true">Enabled</option>
|
||||
</select>
|
||||
|
||||
<label for="Posts_StickySearch">Sticky Searchbar</label>
|
||||
<select id="Posts_StickySearch">
|
||||
<option value="false">Disabled</option>
|
||||
<option value="true">Enabled</option>
|
||||
</select>
|
||||
|
||||
<label for="Theme_Navbar">Navbar location</label>
|
||||
<select id="Theme_Navbar">
|
||||
<option value="top">Top (default)</option>
|
||||
<option value="bottom">Bottom</option>
|
||||
<option value="both">Both</option>
|
||||
<option value="none">Off (not recommended)</option>
|
||||
</select>
|
||||
|
||||
<label for="theme_gestures">Mobile Gestures</label>
|
||||
<select id="theme_gestures">
|
||||
<label for="Theme_Gestures">Mobile Gestures</label>
|
||||
<select id="Theme_Gestures">
|
||||
<option value="false">Disabled</option>
|
||||
<option value="true">Enabled</option>
|
||||
</select>
|
||||
<div class="hint">Swipe left for next page/image. Swipe right for previous page/image.</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@ -85,14 +111,6 @@
|
||||
<%= svg_icon(:reset) %>
|
||||
Reset
|
||||
</button>
|
||||
|
||||
<label for="wiki-excerpt-reset">Wiki Excerpt</label>
|
||||
<span id="wiki-excerpt-value"></span>
|
||||
<button class="st-button" id="wiki-excerpt-reset">
|
||||
<%= svg_icon(:reset) %>
|
||||
Reset
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
<% content_for(:page_title) do %>
|
||||
|
@ -1,14 +0,0 @@
|
||||
<div class="about-section">
|
||||
<% if user.profile_about.present? %>
|
||||
<div class="profile-about-entry" id="about-info">
|
||||
<h3>About</h3>
|
||||
<div class="content dtext-container"><%= format_text(user.profile_about, allow_color: true) %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if user.profile_artinfo.present? %>
|
||||
<div class="profile-about-entry" id="about-artinfo">
|
||||
<h3>Artist Information</h3>
|
||||
<div class="content dtext-container"><%= format_text(user.profile_artinfo, allow_color: true) %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
@ -1,156 +0,0 @@
|
||||
<div class="stats-section">
|
||||
<div class="profile-avatar">
|
||||
<%= user_avatar @user %>
|
||||
</div>
|
||||
<div class="profile-stats">
|
||||
<h1><%= link_to_user @user %></h1>
|
||||
<div class="user-statistics">
|
||||
<div class="column">
|
||||
<span>Join Date</span>
|
||||
<span><%= compact_time @user.created_at %></span>
|
||||
|
||||
<span>Level</span>
|
||||
<span><%= "(Unactivated)" unless user.is_verified? %> <%= presenter.level %></span>
|
||||
|
||||
<% if user.is_banned? && user.recent_ban %>
|
||||
<span>Ban reason</span>
|
||||
<span class="dtext-container"><%= format_text presenter.ban_reason %></span>
|
||||
<% end %>
|
||||
|
||||
<span>Posts</span>
|
||||
<span>
|
||||
<%= presenter.active_upload_count(self) %>
|
||||
[<%= link_to "pending", posts_path(tags: "user:#{user.name} status:pending") %>]
|
||||
(<%= link_to "comments on", comments_path(group_by: :comment, search: {poster_id: user.id}) %>)
|
||||
<% if CurrentUser.is_moderator? %>
|
||||
(<%= link_to "votes", action: "index", controller: "post_votes", search: { user_name: user.name } %>)
|
||||
<% end %>
|
||||
</span>
|
||||
|
||||
<span>Deleted</span>
|
||||
<span>
|
||||
<%= presenter.deleted_upload_count(self) %>
|
||||
</span>
|
||||
|
||||
<span>Replaced</span>
|
||||
<span>
|
||||
<%= presenter.replaced_upload_count(self) %>
|
||||
[<%= link_to "pending", post_replacements_path(search: { creator_name: user.name }) %>]
|
||||
</span>
|
||||
|
||||
<span>Rejected</span>
|
||||
<span><%= presenter.rejected_replacements_count(self) %></span>
|
||||
|
||||
<span>Favorites</span>
|
||||
<span>
|
||||
<%= presenter.favorite_count(self) %>
|
||||
</span>
|
||||
|
||||
<span>Forum Posts</span>
|
||||
<span>
|
||||
<%= presenter.forum_post_count(self) %>
|
||||
(<%= link_to "mentions", forum_posts_path(search: { body_matches: user.name }) %>)
|
||||
</span>
|
||||
|
||||
<span>Comments</span>
|
||||
<span>
|
||||
<%= presenter.comment_count(self) %> on <%= presenter.commented_posts_count(self) %> posts
|
||||
(<%= link_to "mentions", comments_path(group_by: :comment, search:{ body_matches: user.name }) %>)
|
||||
<% if CurrentUser.is_moderator? %>
|
||||
(<%= link_to "votes", action: "index", controller: "comment_votes", search: { user_name: user.name } %>)
|
||||
<% end %>
|
||||
</span>
|
||||
|
||||
<% if user.can_approve_posts? || Post.where(approver: user).exists? %>
|
||||
<span>Approvals</span>
|
||||
<span><%= presenter.approval_count(self) %></span>
|
||||
<% end %>
|
||||
|
||||
<% if CurrentUser.user.id == user.id || CurrentUser.is_janitor? %>
|
||||
<% if presenter.previous_names(self).present? %>
|
||||
<span>Previous Names</span>
|
||||
<span><%= presenter.previous_names(self) %> -> <%= user.name %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if CurrentUser.is_admin? %>
|
||||
<span>Email</span>
|
||||
<span>
|
||||
<%= user.email %>
|
||||
<%= email_domain_search(user.email) %>
|
||||
</span>
|
||||
<span>Last IP</span>
|
||||
<span><%= link_to_ip(user.last_ip_addr) %></span>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<span>Feedback</span>
|
||||
<span>
|
||||
<%= presenter.feedbacks %>
|
||||
<%= link_to("List", user_feedbacks_path(search: { user_id: @user.id })) %>
|
||||
<% if CurrentUser.is_moderator? && @user.feedback.active.count == 0 %>
|
||||
| <%= link_to("Create", new_user_feedback_path(user_feedback: { user_id: @user.id, category: "neutral" })) %>
|
||||
<% end %>
|
||||
</span>
|
||||
|
||||
<span>Permissions</span>
|
||||
<span><%= presenter.permissions %></span>
|
||||
|
||||
<span>Upload Limit</span>
|
||||
<span>
|
||||
<%= presenter.upload_limit(self) %>
|
||||
<% if CurrentUser.user.id == user.id %>
|
||||
(<%= link_to "help", upload_limit_users_path %>)
|
||||
<% else %>
|
||||
(<%= link_to "help", wiki_page_path(id: "upload_limit") %>)
|
||||
<% end %>
|
||||
</span>
|
||||
|
||||
<span>Post Changes</span>
|
||||
<span>
|
||||
<%= presenter.post_version_count(self) %>
|
||||
<% if CurrentUser.is_moderator? && UserRevert.can_revert?(user) %>
|
||||
[<%= link_to "revert all", new_user_revert_path(user_id: user.id) %>]
|
||||
<% end %>
|
||||
</span>
|
||||
|
||||
<span>Wiki Changes</span>
|
||||
<span><%= presenter.wiki_page_version_count(self) %></span>
|
||||
|
||||
<span>Note Changes</span>
|
||||
<span><%= presenter.note_version_count(self) %> on <%= presenter.noted_posts_count(self) %> posts</span>
|
||||
|
||||
<span>Artist Changes</span>
|
||||
<span><%= presenter.artist_version_count(self) %></span>
|
||||
|
||||
<span>Pool Changes</span>
|
||||
<span><%= presenter.pool_version_count(self) %></span>
|
||||
|
||||
<% if CurrentUser.user.id == user.id || CurrentUser.is_janitor? %>
|
||||
<span>Flags</span>
|
||||
<span><%= presenter.flag_count(self) %></span>
|
||||
<% end %>
|
||||
|
||||
<% if CurrentUser.user.id == user.id || CurrentUser.is_moderator? %>
|
||||
<span>Tickets</span>
|
||||
<span>
|
||||
<%= presenter.ticket_count(self) %>
|
||||
<% if CurrentUser.is_moderator? %>
|
||||
[<%= link_to "pending", tickets_path(search: { creator_id: user.id, status: "pending" }) %>]
|
||||
[<%= link_to "accused", tickets_path(search: { accused_id: user.id }) %>]
|
||||
<% end %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<% if CurrentUser.id == user.id %>
|
||||
<span>API Key</span>
|
||||
<span>
|
||||
<%= link_to (CurrentUser.api_key ? "View" : "Generate"), user_api_key_path(CurrentUser.user) %>
|
||||
(<%= link_to "help", help_page_path(id: "api") %>)
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,137 +1,36 @@
|
||||
<div id="c-users">
|
||||
<div id="a-edit">
|
||||
<h1>Settings</h1>
|
||||
<div id="c-users"><div id="a-edit">
|
||||
<h1>Settings</h1>
|
||||
|
||||
<%= custom_form_for @user do |f| %>
|
||||
<h2 id="edit-options">
|
||||
<%= link_to "Basic", "#basic-settings", :class => "active" %>
|
||||
| <%= link_to "Advanced", "#advanced-settings" %>
|
||||
<% if CurrentUser.user.id == @user.id %>
|
||||
| <%= link_to "Change password", edit_user_password_path(:user_id => @user.id), :id => "change-password" %>
|
||||
| <%= link_to "Delete account", maintenance_user_deletion_path, :id => "delete-account" %>
|
||||
<% end %>
|
||||
</h2>
|
||||
<tabs-menu id="settings-tabs">
|
||||
<button role="tab" name="basic">Basic</button>
|
||||
<button role="tab" name="advanced">Advanced</button>
|
||||
<button role="tab" name="blacklist">Blacklist</button>
|
||||
<span class="spacer"></span>
|
||||
<input type="text" name="search" placeholder="Search Settings" />
|
||||
</tabs-menu>
|
||||
|
||||
<fieldset id="basic-settings-section">
|
||||
<div class="input">
|
||||
<label>Name</label>
|
||||
<%= custom_form_for @user do |form| %>
|
||||
<tabs-content for="settings-tabs">
|
||||
<%= render "users/partials/edit/basic", form: form %>
|
||||
<%= render "users/partials/edit/advanced", form: form %>
|
||||
<%= render "users/partials/edit/blacklist", form: form %>
|
||||
<tab-submit>
|
||||
<%= form.button :submit, "Save Settings" %>
|
||||
</tab-submit>
|
||||
</tabs-content>
|
||||
<% end %>
|
||||
</div></div>
|
||||
|
||||
<p><%= link_to "Request a name change", new_user_name_change_request_path %></p>
|
||||
</div>
|
||||
|
||||
<div class="input">
|
||||
<label>Email</label>
|
||||
<p>
|
||||
<% if CurrentUser.user.email.present? %>
|
||||
<%= CurrentUser.user.email %>
|
||||
<% else %>
|
||||
<em>blank</em>
|
||||
<% end %>
|
||||
–
|
||||
<%= link_to "Change your email", new_maintenance_user_email_change_path %>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<%= f.input :avatar_id, as: :string, label: "Avatar Post ID" %>
|
||||
|
||||
<%= f.input :profile_about, as: :dtext, label: "About Me", limit: Danbooru.config.user_about_max_size, allow_color: true %>
|
||||
|
||||
<%= f.input :profile_artinfo, as: :dtext, label: "Commission Info", limit: Danbooru.config.user_about_max_size, allow_color: true %>
|
||||
|
||||
<%= f.input :time_zone, :include_blank => false %>
|
||||
|
||||
<%= f.input :receive_email_notifications, :as => :select, :include_blank => false, :collection => [["Yes", "true"], ["No", "false"]] %>
|
||||
|
||||
<%= f.input :comment_threshold, :hint => "Comments below this score will be hidden by default." %>
|
||||
|
||||
<%= f.input :default_image_size, :hint => "Show original image size, scaled to fit, scaled to fit vertically, or show resized #{Danbooru.config.large_image_width} pixel sample version.", :label => "Default image width", :collection => [["Original", "original"], ["Fit (Horizontal)", "fit"], ["Fit (Vertical)", "fitv"], ["Sample (#{Danbooru.config.large_image_width}px)", "large"]], :include_blank => false %>
|
||||
|
||||
<%= f.input :per_page, :label => "Posts per page", :as => :select, :collection => (25..250), :include_blank => false %>
|
||||
|
||||
<%= f.input :enable_safe_mode, :label => "Safe mode", :hint => "Show only safe images. Hide questionable and explicit images.", :as => :select, :include_blank => false, :collection => [["Yes", "true"], ["No", "false"]] %>
|
||||
|
||||
<%= f.input :blacklisted_tags, :hint => "Put any tag combinations you never want to see here. Each combination should go on a separate line. <a href='/help/blacklist'>View help.</a>".html_safe, autocomplete: "tag-query", input_html: { size: "40x5" } %>
|
||||
|
||||
<%= f.input :blacklist_users, hint: "Hide comments, blips and forum posts from users that have been blacklisted, in addition to posts.", as: :select, include_blank: false, collection: [["Yes", "true"], ["No", "false"]] %>
|
||||
</fieldset>
|
||||
|
||||
<fieldset id="advanced-settings-section">
|
||||
<%= f.input :style_usernames, :as => :select, :label => "Colored usernames",
|
||||
:hint => raw("Color each user's name depending on their level. See #{link_to 'the legend', wiki_page_path(id: 'e621:colored_usernames')} for what the colors are."),
|
||||
:include_blank => false, :collection => [["Yes", "true"], ["No", "false"]] %>
|
||||
|
||||
<%= f.input :enable_keyboard_navigation, :as => :select, :include_blank => false, :label => "Enable keyboard shortcuts", :collection => [["Yes", "true"], ["No", "false"]],
|
||||
hint: raw("Enables the use of keyboard shortcuts for a majority of site actions related to posts. A list of keyboard shortcuts is available #{link_to 'here', keyboard_shortcuts_path}.")%>
|
||||
|
||||
<%= f.input :enable_auto_complete, :as => :select, :collection => [["Yes", "true"], ["No", "false"]], :include_blank => false,
|
||||
hint: "Enables auto-completion on most tag and user entry fields." %>
|
||||
|
||||
<%= f.input :enable_privacy_mode, :as => :select, :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false,
|
||||
hint: "Prevent showing your favorites to others users (except staff)." %>
|
||||
|
||||
<%= f.input :show_post_statistics, as: :select, collection: [["No", "false"],["Yes", "true"]], include_blank: false,
|
||||
hint: "Show post statistics below posts on search pages." %>
|
||||
|
||||
<%= f.input :description_collapsed_initially, as: :select, collection: [["No", "false"],["Yes", "true"]], include_blank: false,
|
||||
hint: "Don't expand post descriptions on page load." %>
|
||||
|
||||
<%= f.input :hide_comments, as: :select, collection: [["No", "false"],["Yes", "true"]], include_blank: false,
|
||||
hint: "Do not show the comments section on post pages." %>
|
||||
|
||||
<% unless CurrentUser.is_janitor? %>
|
||||
<%= f.input :disable_user_dmails, label: "Disable DMails", hint: "Prevent other users from sending you DMails. You will be prevented from sending DMails to non-staff members while this option is enabled. Staff are always allowed to send you DMails.",
|
||||
:as => :select, :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false %>
|
||||
<% end %>
|
||||
|
||||
<%= f.input :disable_cropped_thumbnails, :as => :select, :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false,
|
||||
hint: "Disables displaying cropped thumbnails on the mobile layout of the site in favor of scaled thumbnails. Has no effect on the desktop site." %>
|
||||
|
||||
<%= f.input :show_hidden_comments, label: "Show Own Hidden Comments", :as => :select, :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false,
|
||||
hint: "Show your own hidden comments on comment pages." %>
|
||||
|
||||
<% if @user.post_upload_count >= 10 %>
|
||||
<%= f.input :enable_compact_uploader, label: "Enable Compact Uploader", as: :select,
|
||||
collection: [["No", "false"], ["Yes", "true"]], include_blank: false,
|
||||
hint: "Enables a more compact and less guided post uploader." %>
|
||||
<% end %>
|
||||
|
||||
<div class="input text optional field_with_hint">
|
||||
<label class="text optional" for="user_dmail_filter_attributes_words">Dmail filter</label>
|
||||
<%= hidden_field_tag "user[dmail_filter_attributes][id]", @user.dmail_filter.try(:id) %>
|
||||
<%= text_field_tag "user[dmail_filter_attributes][words]", @user.dmail_filter.try(:words), :id => "user_dmail_filter_attributes_words", :class => "text optional", :size => 40 %>
|
||||
<span class="hint">A list of banned words (space delimited). Any dmail you receive with a banned word will automatically be deleted.</span>
|
||||
</div>
|
||||
|
||||
<%= f.input :favorite_tags, :label => "Frequent tags", :hint => "A list of tags that you use often. They will appear when using the list of Related Tags.", autocomplete: "tag-query", input_html: { rows: 5 } %>
|
||||
|
||||
<%= f.input :disable_responsive_mode, :as => :select, :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false, :hint => "Disable alternative layout for mobile and tablet." %>
|
||||
|
||||
<%= f.input :custom_style, :label => "Custom <a href='https://en.wikipedia.org/wiki/Cascading_Style_Sheets'>CSS</a> style".html_safe, :hint => "Style to apply to the whole site.", :input_html => {:size => "40x5"} %>
|
||||
</fieldset>
|
||||
|
||||
<%= f.button :submit, "Submit" %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<noscript>
|
||||
<style>
|
||||
tabs-menu { display: none !important; }
|
||||
tab-group { display: flex !important; }
|
||||
tab-entry { display: grid !important; }
|
||||
</style>
|
||||
</noscript>
|
||||
|
||||
<% content_for(:page_title) do %>
|
||||
Settings
|
||||
<% end %>
|
||||
|
||||
<% content_for(:html_header) do %>
|
||||
<%= javascript_tag nonce: true do -%>
|
||||
$(function() {
|
||||
$("#advanced-settings-section").hide();
|
||||
$("#edit-options a:not(#delete-account):not(#change-password)").on("click", function(e) {
|
||||
var $target = $(e.target);
|
||||
$("h2 a").removeClass("active");
|
||||
$("#basic-settings-section,#advanced-settings-section").hide();
|
||||
$target.addClass("active");
|
||||
$($target.attr("href") + "-section").show();
|
||||
e.preventDefault();
|
||||
});
|
||||
});
|
||||
<% end -%>
|
||||
<% end %>
|
||||
|
||||
<%= render "secondary_links" %>
|
||||
|
166
app/views/users/partials/edit/_advanced.html.erb
Normal file
166
app/views/users/partials/edit/_advanced.html.erb
Normal file
@ -0,0 +1,166 @@
|
||||
<% tab_name = "advanced" %>
|
||||
|
||||
<!-- Accessibility -->
|
||||
<tab-group name="accessibility">Accessibility</tab-group>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="accessibility" class="inline" search="keyboard hotkeys shortcut navigation enable disable">
|
||||
<tab-head>Enable Keyboard Shortcuts</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :enable_keyboard_navigation, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :enable_keyboard_navigation, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
The full list of shortcuts is available <%= link_to "here", keyboard_shortcuts_path %>.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="accessibility" class="inline" search="auto complete autocomplete suggestions enable disable">
|
||||
<tab-head>Enable Auto Complete</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :enable_auto_complete, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :enable_auto_complete, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Tag and user name suggestions.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="accessibility" class="inline" search="users colored usernames level rank">
|
||||
<tab-head>Colored Usernames</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :style_usernames, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :style_usernames, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Color names depending on the user's level.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
|
||||
<!-- Privacy & Messaging -->
|
||||
<tab-group name="privacy">Privacy & Messaging</tab-group>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="privacy" class="inline" search="posts favorites hide disable private privacy">
|
||||
<tab-head>Hide Favorites</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :enable_privacy_mode, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :enable_privacy_mode, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Prevent your favorites from being publicly visible.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="privacy" class="inline" search="dmails filter banned block enable disable toggle">
|
||||
<tab-head>Disable DMails</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :disable_user_dmails, as: :boolean, class: "st-toggle", disabled: CurrentUser.is_staff? %>
|
||||
<%= form.label :disable_user_dmails, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Prevent other users from sending you DMails.
|
||||
<% if CurrentUser.is_staff? %>
|
||||
<br />Staff members are not allowed to disable DMails.
|
||||
<% end %>
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="privacy" search="dmails filter banned block">
|
||||
<tab-head>DMail Filters</tab-head>
|
||||
<tab-body>
|
||||
<%= hidden_field_tag "user[dmail_filter_attributes][id]", @user.dmail_filter.try(:id) %>
|
||||
<%= text_field_tag "user[dmail_filter_attributes][words]", @user.dmail_filter.try(:words), id: "user_dmail_filter_attributes_words", class: "text optional", size: 40 %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
A list of banned words (space delimited). Any dmail you receive with a banned word will automatically be deleted.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
|
||||
<!-- Posts -->
|
||||
<tab-group name="tags">Posts & Tags</tab-group>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="tags" class="inline" search="show hide posts thumbnails statistics stats search">
|
||||
<tab-head>Show Statistics</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :show_post_statistics, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :show_post_statistics, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Show post stats below posts on search pages.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="tags" class="inline" search="show hide collapse expand posts descriptions">
|
||||
<tab-head>Collapse Descriptions</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :description_collapsed_initially, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :description_collapsed_initially, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Do not expand post descriptions on page load.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="tags" class="bigtext" search="posts tags frequent favorite related">
|
||||
<tab-head>Frequent Tags</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :favorite_tags, label: false, autocomplete: "tag-query", rows: 5 %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
A list of tags that you use often.<br />They will appear when using the list of Related Tags.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<% if @user.post_upload_count >= 10 %>
|
||||
<tab-entry tab="<%= tab_name %>" group="tags" class="inline" search="show hide compact uploader posts">
|
||||
<tab-head>Compact Uploader</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :enable_compact_uploader, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :enable_compact_uploader, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
A more compact and less guided post uploader.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
<% end %>
|
||||
|
||||
|
||||
<!-- Mobile -->
|
||||
<tab-group name="mobile">Mobile / Tablet</tab-group>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="mobile" class="inline" search="enable disable responsive mode mobile tablet">
|
||||
<tab-head>Disable Responsive Mode</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :disable_responsive_mode, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :disable_responsive_mode, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Disable alternative layout for mobile and tablet.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="mobile" class="inline" search="enable disable cropped thumbnails mobile tablet">
|
||||
<tab-head>Disable Cropped Thumbnails</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :disable_cropped_thumbnails, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :disable_cropped_thumbnails, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
No effect on the desktop site.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
|
||||
<!-- Customization -->
|
||||
<tab-group name="customization">Customization</tab-group>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="customization" class="bigtext" search="customize css styles">
|
||||
<tab-head>Custom CSS</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :custom_style, label: false, rows: 8 %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Apply <a href="https://en.wikipedia.org/wiki/Cascading_Style_Sheets">CSS Styles</a> to the whole website.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
155
app/views/users/partials/edit/_basic.html.erb
Normal file
155
app/views/users/partials/edit/_basic.html.erb
Normal file
@ -0,0 +1,155 @@
|
||||
<% tab_name = "basic" %>
|
||||
|
||||
<!-- Account -->
|
||||
<tab-group name="account">Account</tab-group>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="account" class="buttony" search="update change user profile account name username">
|
||||
<tab-head>Username</tab-head>
|
||||
<tab-body>
|
||||
<input type="text" value="<%= CurrentUser.user.pretty_name %>" disabled><%= link_to "Edit", new_user_name_change_request_path, class: "st-button" %>
|
||||
</tab-body>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="account" class="buttony" search="update change user profile account email e-mail address">
|
||||
<tab-head>Email</tab-head>
|
||||
<tab-body>
|
||||
<input type="text" value="<%= CurrentUser.user.email.presence || "blank" %>" disabled><%= link_to "Edit", new_maintenance_user_email_change_path, class: "st-button" %>
|
||||
</tab-body>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="account" class="" id="settings-account-buttons" search="update change user profile account delete password">
|
||||
<tab-head></tab-head>
|
||||
<tab-body>
|
||||
<%= link_to "Change password", edit_user_password_path(user_id: @user.id), class: "st-button" %>
|
||||
<%= link_to "Delete account", maintenance_user_deletion_path, class: "st-button danger" %>
|
||||
</tab-body>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="account" search="user account timezone">
|
||||
<tab-head>Time Zone</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :time_zone,
|
||||
label: false,
|
||||
include_blank: false
|
||||
%>
|
||||
</tab-body>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="account" class="inline" search="user account email notify notifications">
|
||||
<tab-head>Email Notifications</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :receive_email_notifications, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :receive_email_notifications, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
</tab-entry>
|
||||
|
||||
|
||||
<!-- General -->
|
||||
|
||||
|
||||
<!-- Profile -->
|
||||
<tab-group name="profile">Profile</tab-group>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="profile" search="update change user avatar profile image pfp">
|
||||
<tab-head><%= form.label :avatar_id, "Avatar Post ID" %></tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :avatar_id, as: :string, label: false %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
The image with this ID will be set as your avatar.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="profile" class="bigtext" search="user profile about me">
|
||||
<tab-head><%= form.label :profile_about, "About Me" %></tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :profile_about,
|
||||
as: :dtext,
|
||||
label: false,
|
||||
rows: 8,
|
||||
limit: Danbooru.config.user_about_max_size,
|
||||
allow_color: true
|
||||
%>
|
||||
</tab-body>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="profile" class="bigtext" search="user profile commission info">
|
||||
<tab-head><%= form.label :profile_artinfo, "Commission Info" %></tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :profile_artinfo,
|
||||
as: :dtext,
|
||||
label: false,
|
||||
rows: 8,
|
||||
limit: Danbooru.config.user_about_max_size,
|
||||
allow_color: true
|
||||
%>
|
||||
</tab-body>
|
||||
</tab-entry>
|
||||
|
||||
|
||||
<!-- Posts -->
|
||||
<tab-group name="posts">Posts</tab-group>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="posts" search="default images width fit horizontal vertical sample large original display show scale posts">
|
||||
<tab-head><%= form.label :default_image_size, "Default image width" %></tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :default_image_size,
|
||||
label: false,
|
||||
collection: [["Original", "original"], ["Fit (Horizontal)", "fit"], ["Fit (Vertical)", "fitv"], ["Sample (#{Danbooru.config.large_image_width}px)", "large"]],
|
||||
include_blank: false
|
||||
%>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Show original image size, scaled to fit, scaled to fit vertically, or show resized 850 pixel sample version.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="posts" search="posts number page display show">
|
||||
<tab-head><%= form.label :per_page, "Posts per page" %></tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :per_page, label: false, as: :select, collection: (25..250).step(25), include_blank: false %>
|
||||
</tab-body>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="posts" search="comments score rating upvotes downvotes display show hide">
|
||||
<tab-head><%= form.label :comment_threshold %></tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :comment_threshold, label: false %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Comments below this score will be hidden by default.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="posts" class="inline" search="posts comments show hide display hidden">
|
||||
<tab-head><%= form.label :hide_comments %></tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :hide_comments, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :hide_comments, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Do not show the comments section on post pages.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="posts" class="inline" search="posts comments show hide display own hidden">
|
||||
<tab-head><%= form.label :show_hidden_comments, "Show own hidden comments" %></tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :show_hidden_comments, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :show_hidden_comments, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Show your hidden comments on comment pages.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="posts" class="inline" search="posts display show hide mode explicit questionable safe rated rating">
|
||||
<tab-head><%= form.label :enable_safe_mode, "Safe mode" %></tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :enable_safe_mode, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :enable_safe_mode, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Only show images rated safe.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
25
app/views/users/partials/edit/_blacklist.html.erb
Normal file
25
app/views/users/partials/edit/_blacklist.html.erb
Normal file
@ -0,0 +1,25 @@
|
||||
<% tab_name = "blacklist" %>
|
||||
|
||||
<!-- Accessibility -->
|
||||
<tab-group name="blacklisting">Blacklist</tab-group>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="blacklisting" class="bigtext" search="posts blacklisted filtered tags blocked">
|
||||
<tab-head>Blacklisted Tags</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :blacklisted_tags, label: false, autocomplete: "tag-query", rows: 8 %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Put any tag combinations you never want to see here. Each combination should go on a separate line. <a href='/help/blacklist'>View help.</a>
|
||||
</tab-hint>
|
||||
</tab-entry>
|
||||
|
||||
<tab-entry tab="<%= tab_name %>" group="blacklisting" class="inline" search="posts blacklisted filter users comments blips forum">
|
||||
<tab-head>Blacklist Users</tab-head>
|
||||
<tab-body>
|
||||
<%= form.input_field :blacklist_users, as: :boolean, class: "st-toggle" %>
|
||||
<%= form.label :blacklist_users, "!", class: "st-toggle" %>
|
||||
</tab-body>
|
||||
<tab-hint>
|
||||
Hide comments, blips and forum posts from users that have been blacklisted, in addition to posts.
|
||||
</tab-hint>
|
||||
</tab-entry>
|
17
app/views/users/partials/show/_about.html.erb
Normal file
17
app/views/users/partials/show/_about.html.erb
Normal file
@ -0,0 +1,17 @@
|
||||
<% if has_about %>
|
||||
<tab-entry tab="about" class="profile-about-section flex">
|
||||
<tab-head>About</tab-head>
|
||||
<tab-body class="content dtext-container">
|
||||
<%= format_text(user.profile_about, allow_color: true) %>
|
||||
</tab-body>
|
||||
</tab-entry>
|
||||
<% end %>
|
||||
|
||||
<% if has_artinfo %>
|
||||
<tab-entry tab="artinfo" class="profile-artinfo-section flex">
|
||||
<tab-head>Artist Information</tab-head>
|
||||
<tab-body class="content dtext-container">
|
||||
<%= format_text(user.profile_artinfo, allow_color: true) %>
|
||||
</tab-body>
|
||||
</tab-entry>
|
||||
<% end %>
|
5
app/views/users/partials/show/_ban_banner.html.erb
Normal file
5
app/views/users/partials/show/_ban_banner.html.erb
Normal file
@ -0,0 +1,5 @@
|
||||
<% if user.is_banned? && user.recent_ban %>
|
||||
<div class="profile-ban dtext-container">
|
||||
<%= format_text presenter.ban_reason %>
|
||||
</div>
|
||||
<% end %>
|
20
app/views/users/partials/show/_card.html.erb
Normal file
20
app/views/users/partials/show/_card.html.erb
Normal file
@ -0,0 +1,20 @@
|
||||
<div class="profile-card">
|
||||
<div class="profile-avatar">
|
||||
<%= profile_avatar(@user) %>
|
||||
</div>
|
||||
<div class="profile-info">
|
||||
<span class="profile-name">
|
||||
<%= link_to_user(@user) %>
|
||||
<%= user_feedback_badge(@user) %>
|
||||
</span>
|
||||
<span class="profile-joined">
|
||||
Joined <%= compact_date @user.created_at %>
|
||||
</span>
|
||||
<span class="profile-rank">
|
||||
<%= user_level_badge(@user) %>
|
||||
<% unless @user.is_verified? %>
|
||||
<span class="level-badge level-unactivated">UNACTIVATED</span>
|
||||
<% end %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
0
app/views/users/partials/show/_mentions.html.erb
Normal file
0
app/views/users/partials/show/_mentions.html.erb
Normal file
@ -4,7 +4,7 @@
|
||||
<div class="profile-sample profile-uploads">
|
||||
|
||||
<div class="profile-sample-header">
|
||||
<%= link_to "Uploads", posts_path(:tags => "user:#{user.name}"), class: "title" %>
|
||||
<%= link_to "Uploads", posts_path(tags: "user:#{user.name}"), class: "title" %>
|
||||
</div>
|
||||
|
||||
<div class="profile-sample-links">
|
||||
@ -29,11 +29,11 @@
|
||||
<div class="profile-sample profile-favorites">
|
||||
|
||||
<div class="profile-sample-header">
|
||||
<%= link_to "Favorites", favorites_path(:user_id => user.id), class: "title" %>
|
||||
<%= link_to "Favorites", favorites_path(user_id: user.id), class: "title" %>
|
||||
</div>
|
||||
|
||||
<div class="profile-sample-links">
|
||||
<%= link_to(sanitize("<b>#{user.favorite_count}</b> total"), favorites_path(:user_id => user.id)) %>
|
||||
<%= link_to(sanitize("<b>#{user.favorite_count}</b> total"), favorites_path(user_id: user.id)) %>
|
||||
<% if user.enable_privacy_mode? || user.is_blocked? %>
|
||||
<span>[hidden]</span>
|
||||
<% end %>
|
34
app/views/users/partials/show/_staff_info.html.erb
Normal file
34
app/views/users/partials/show/_staff_info.html.erb
Normal file
@ -0,0 +1,34 @@
|
||||
<div class="profile-section hidden" name="StaffStats">
|
||||
<div class="profile-section-header">Staff Info</div>
|
||||
<div class="profile-section-body profile-staff-info">
|
||||
<% if presenter.previous_names(self).present? %>
|
||||
<h4 class="block">Previous Names</h4>
|
||||
<span class="block"><%= presenter.previous_names(self) %> -> <%= user.name %></span>
|
||||
<% end %>
|
||||
|
||||
<% if CurrentUser.is_admin? %>
|
||||
<h4>Email</h4>
|
||||
<span>
|
||||
<%= user.email %>
|
||||
<%= email_domain_search(user.email) %>
|
||||
</span>
|
||||
|
||||
<h4>Last IP</h4>
|
||||
<span><%= link_to_ip(user.last_ip_addr) %></span>
|
||||
<% end %>
|
||||
|
||||
<% if CurrentUser.is_moderator? %>
|
||||
<h4>Votes</h4>
|
||||
<span>
|
||||
<%= link_to "Posts", action: "index", controller: "post_votes", search: { user_name: user.name } %>
|
||||
| <%= link_to "Comments", action: "index", controller: "comment_votes", search: { user_name: user.name } %>
|
||||
</span>
|
||||
<% end %>
|
||||
|
||||
<h4>Pending</h4>
|
||||
<span>
|
||||
<%= link_to "Posts", posts_path(tags: "user:#{user.name} status:pending") %>
|
||||
| <%= link_to "Replacements", post_replacements_path(search: { creator_name: user.name }) %>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
129
app/views/users/partials/show/_user_info.html.erb
Normal file
129
app/views/users/partials/show/_user_info.html.erb
Normal file
@ -0,0 +1,129 @@
|
||||
<tab-entry tab="stats" class="profile-user-info">
|
||||
|
||||
<div class="profile-line">
|
||||
<h4><%= svg_icon(:message_square) %> Comments</h4>
|
||||
<span class="profile-line-number">
|
||||
<%= presenter.comment_count(self) %>
|
||||
</span>
|
||||
<span class="profile-line-extra">
|
||||
<%= link_to "[mentions]", comments_path(group_by: :comment, search: { body_matches: user.name }) %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="profile-line">
|
||||
<h4><%= svg_icon(:lectern) %> Forum posts</h4>
|
||||
<span class="profile-line-number">
|
||||
<%= presenter.forum_post_count(self) %>
|
||||
</span>
|
||||
<span class="profile-line-extra">
|
||||
<%= link_to "[mentions]", forum_posts_path(search: { body_matches: user.name }) %>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<% if user.can_approve_posts? || Post.where(approver: user).exists? %>
|
||||
<div class="profile-line">
|
||||
<h4><%= svg_icon(:stamp) %> Approvals</h4>
|
||||
<span class="profile-line-number">
|
||||
<%= presenter.approval_count(self) %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div class="profile-line">
|
||||
<h4><%= svg_icon(:upload) %> Upload Limit</h4>
|
||||
<span class="profile-line-number">
|
||||
<% if CurrentUser.user.id == user.id %>
|
||||
<%= link_to presenter.upload_limit_short, upload_limit_users_path %>
|
||||
<% else %>
|
||||
<%= link_to presenter.upload_limit_short, wiki_page_path(id: "upload_limit") %>
|
||||
<% end %>
|
||||
</span>
|
||||
<span class="profile-line-extra">
|
||||
Max number of unapproved posts at a time.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="profile-line">
|
||||
<h4><%= svg_icon(:replace) %> Changes</h4>
|
||||
<span class="profile-line-extra profile-line-show">
|
||||
|
||||
<% if user.post_update_count != 0 %>
|
||||
<a href="<%= post_versions_path(lr: user.id, search: { updater_id: user.id }) %>" class="entry">
|
||||
<h5><%= user.post_update_count %></h5>
|
||||
<span>Post</span>
|
||||
</a>
|
||||
<% end %>
|
||||
|
||||
<% if user.pool_version_count != 0 %>
|
||||
<a href="<%= pool_versions_path(search: { updater_id: user.id }) %>" class="entry">
|
||||
<h5><%= user.pool_version_count %></h5>
|
||||
<span>Pool</span>
|
||||
</a>
|
||||
<% end %>
|
||||
|
||||
<% if user.artist_version_count != 0 %>
|
||||
<a href="<%= artist_versions_path(search: { updater_id: user.id }) %>" class="entry">
|
||||
<h5><%= user.artist_version_count %></h5>
|
||||
<span>Artist</span>
|
||||
</a>
|
||||
<% end %>
|
||||
|
||||
<% if user.wiki_page_version_count != 0 %>
|
||||
<a href="<%= wiki_page_versions_path(search: { updater_id: user.id }) %>" class="entry">
|
||||
<h5><%= user.wiki_page_version_count %></h5>
|
||||
<span>Wiki</span>
|
||||
</a>
|
||||
<% end %>
|
||||
|
||||
<% if user.note_version_count != 0 %>
|
||||
<a href="<%= note_versions_path(search: { updater_id: user.id }) %>" class="entry">
|
||||
<h5><%= user.note_version_count %></h5>
|
||||
<span>Note</span>
|
||||
</a>
|
||||
<% end %>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<% if CurrentUser.user.id == user.id || CurrentUser.is_approver? %>
|
||||
<div class="profile-line">
|
||||
<h4><%= svg_icon(:flag_left) %> Flags</h4>
|
||||
<span class="profile-line-number"><%= presenter.flag_count(self) %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if CurrentUser.user.id == user.id || CurrentUser.is_moderator? %>
|
||||
<div class="profile-line">
|
||||
<h4><%= svg_icon(:ticket) %> Tickets</h4>
|
||||
<span class="profile-line-number"><%= presenter.ticket_count(self) %></span>
|
||||
<% if CurrentUser.is_moderator? %>
|
||||
<span class="profile-line-extra">
|
||||
[<%= link_to "pending", tickets_path(search: { creator_id: user.id, status: "pending" }) %>]
|
||||
[<%= link_to "accused", tickets_path(search: { accused_id: user.id }) %>]
|
||||
</span>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if CurrentUser.user.id == user.id %>
|
||||
<div class="profile-line">
|
||||
<h4><%= svg_icon(:key_square) %> API Key</h4>
|
||||
<span class="profile-line-number">
|
||||
<%= link_to (CurrentUser.api_key ? "View" : "Generate"), user_api_key_path(CurrentUser.user) %>
|
||||
</span>
|
||||
<span class="profile-line-extra">
|
||||
(<%= link_to "help", help_page_path(id: "api") %>)
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<% permissions = presenter.permissions %>
|
||||
<% unless permissions.empty? %>
|
||||
<div class="profile-line">
|
||||
<h4><%= svg_icon(:power) %> Permissions</h4>
|
||||
<span class="profile-line-extra">
|
||||
<%= permissions %>
|
||||
</span>
|
||||
</div>
|
||||
<% end %>
|
||||
</tab-entry>
|
@ -1,10 +1,41 @@
|
||||
<div id="c-users">
|
||||
<div id="a-show">
|
||||
<%= render "statistics", :presenter => @presenter, :user => @user %>
|
||||
<%= render "staff_notes/partials/for_user", user: @user %>
|
||||
|
||||
<!-- Header -->
|
||||
<%= render "/users/partials/show/card", :presenter => @presenter, :user => @user %>
|
||||
<%= render "/users/partials/show/ban_banner", :presenter => @presenter, :user => @user %>
|
||||
|
||||
<% if CurrentUser.is_staff? %>
|
||||
<!-- Staff Info -->
|
||||
<%= render "/users/partials/show/staff_info", :presenter => @presenter, :user => @user %>
|
||||
<%= render "staff_notes/partials/for_user", user: @user %>
|
||||
<% end %>
|
||||
|
||||
<!-- Blacklist -->
|
||||
<%= render "posts/partials/common/inline_blacklist" %>
|
||||
<%= render "post_summary", presenter: @presenter, user: @user %>
|
||||
<%= render "about", presenter: @presenter, user: @user %>
|
||||
|
||||
<!-- Central panel -->
|
||||
<% has_about = @user.profile_about.present? %>
|
||||
<% has_artinfo = @user.profile_artinfo.present? %>
|
||||
<tabs-menu
|
||||
id="profile-tabs"
|
||||
data-has-about="<%= has_about %>"
|
||||
data-has-artinfo="<%= has_artinfo %>"
|
||||
>
|
||||
<% if has_about %>
|
||||
<button role="tab" name="about">About</button>
|
||||
<% end %>
|
||||
<% if has_artinfo %>
|
||||
<button role="tab" name="artinfo">Commission Info</button>
|
||||
<% end %>
|
||||
<button role="tab" name="stats">Stats</button>
|
||||
</tabs-menu>
|
||||
|
||||
<tabs-content for="profile-tabs">
|
||||
<%= render "/users/partials/show/user_info", :presenter => @presenter, :user => @user %>
|
||||
<%= render "/users/partials/show/about", presenter: @presenter, user: @user, has_about: has_about, has_artinfo: has_artinfo %>
|
||||
<%= render "/users/partials/show/post_summary", presenter: @presenter, user: @user %>
|
||||
</tabs-content>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -2,23 +2,19 @@
|
||||
<div id="a-diff">
|
||||
<h1>Wiki Page: <%= @thispage.title %></h1>
|
||||
|
||||
<% if @thispage.visible? %>
|
||||
<p>Showing differences between <%= compact_time @thispage.updated_at %> (<%= link_to_user @thispage.updater %>) and <%= compact_time @otherpage.updated_at %> (<%= link_to_user @otherpage.updater %>)</p>
|
||||
<p>Showing differences between <%= compact_time @thispage.updated_at %> (<%= link_to_user @thispage.updater %>) and <%= compact_time @otherpage.updated_at %> (<%= link_to_user @otherpage.updater %>)</p>
|
||||
|
||||
<% if @thispage.parent != @otherpage.parent %>
|
||||
<div class="wiki-redirect-history">
|
||||
Page redirect changed
|
||||
from <%= @thispage.parent.blank? ? "none" : link_to(@thispage.parent, show_or_new_wiki_pages_path(title: @thispage.parent)) %>
|
||||
to <%= @otherpage.parent.blank? ? "none" : link_to(@otherpage.parent, show_or_new_wiki_pages_path(title: @otherpage.parent)) %>.
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<div>
|
||||
<%= text_diff(@thispage.body, @otherpage.body) %>
|
||||
<% if @thispage.parent != @otherpage.parent %>
|
||||
<div class="wiki-redirect-history">
|
||||
Page redirect changed
|
||||
from <%= @thispage.parent.blank? ? "none" : link_to(@thispage.parent, show_or_new_wiki_pages_path(title: @thispage.parent)) %>
|
||||
to <%= @otherpage.parent.blank? ? "none" : link_to(@otherpage.parent, show_or_new_wiki_pages_path(title: @otherpage.parent)) %>.
|
||||
</div>
|
||||
<% else %>
|
||||
<p>The artist requested removal of this page.</p>
|
||||
<% end %>
|
||||
|
||||
<div>
|
||||
<%= text_diff(@thispage.body, @otherpage.body) %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -10,11 +10,7 @@
|
||||
<% end %>
|
||||
|
||||
<div id="wiki-page-body" class="dtext dtext-container">
|
||||
<% if @wiki_page_version.visible? %>
|
||||
<%= format_text(@wiki_page_version.body) %>
|
||||
<% else %>
|
||||
<p>The artist has requested removal of this page.</p>
|
||||
<% end %>
|
||||
<%= format_text(@wiki_page_version.body) %>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
@ -12,22 +12,28 @@
|
||||
|
||||
<%= f.input :body, as: :dtext, limit: Danbooru.config.wiki_page_max_size, allow_color: true %>
|
||||
|
||||
<%= f.input :category_id,
|
||||
label: "Tag Category",
|
||||
collection: TagCategory::CANONICAL_MAPPING.to_a,
|
||||
include_blank: true,
|
||||
disabled: @wiki_page.category_is_locked && !CurrentUser.is_admin? %>
|
||||
|
||||
<% if CurrentUser.is_admin? %>
|
||||
<%= f.input :category_is_locked, label: "Lock Category", as: :boolean %>
|
||||
<% end %>
|
||||
|
||||
<%= f.input :parent, label: "Redirects to", autocomplete: "wiki-page", input_html: { disabled: !CurrentUser.is_privileged? } %>
|
||||
|
||||
<% if CurrentUser.is_janitor? && @wiki_page.is_deleted? %>
|
||||
<%= f.input :is_deleted, :label => "Deleted", :hint => "Uncheck to restore this wiki page" %>
|
||||
<% end %>
|
||||
|
||||
<% if CurrentUser.is_janitor? %>
|
||||
<%= f.input :is_locked, :label => "Locked" %>
|
||||
<%= f.input :is_locked, :label => "Lock Page" %>
|
||||
<% end %>
|
||||
|
||||
<%= f.input :edit_reason, label: "Edit Reason" %>
|
||||
|
||||
<% if CurrentUser.is_janitor? && @wiki_page.errors[:title]&.any? { |error| error.include?("Move the posts and update any wikis linking to this page first.") } %>
|
||||
<%= f.input :skip_secondary_validations, as: :boolean, label: "Force rename", hint: "Ignore the renaming requirements" %>
|
||||
<% end %>
|
||||
|
||||
<%= f.input :edit_reason, label: "Edit Reason" %>
|
||||
|
||||
<%= f.button :submit, "Submit" %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
@ -17,11 +17,8 @@
|
||||
<% if @wiki_page.tag.present? %>
|
||||
<%= subnav_link_to "Posts (#{@wiki_page.tag.post_count})", posts_path(tags: @wiki_page.title) %>
|
||||
|
||||
<% if CurrentUser.is_member? %>
|
||||
<%= subnav_link_to "Edit Tag Type", edit_tag_path(@wiki_page.tag) %>
|
||||
<% if CurrentUser.is_janitor? %>
|
||||
<%= subnav_link_to "Fix Tag Count", new_tag_correction_path(tag_id: @wiki_page.tag.id) %>
|
||||
<% end %>
|
||||
<% if CurrentUser.is_janitor?%>
|
||||
<%= subnav_link_to "Fix Tag Count", new_tag_correction_path(tag_id: @wiki_page.tag.id) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
@ -40,6 +37,8 @@
|
||||
<%= subnav_link_to "Report", new_ticket_path(disp_id: @wiki_page.id, qtype: "wiki") %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
|
||||
<% elsif @wiki_page_version %>
|
||||
<li class="divider"></li>
|
||||
|
||||
|
@ -5,11 +5,7 @@
|
||||
<section id="content">
|
||||
<h1>Edit Wiki</h1>
|
||||
|
||||
<% if @wiki_page.visible? %>
|
||||
<%= render "form" %>
|
||||
<% else %>
|
||||
<p>The artist requested removal of this page.</p>
|
||||
<% end %>
|
||||
<%= render "form" %>
|
||||
|
||||
<%= wiki_page_alias_and_implication_list(@wiki_page)%>
|
||||
<%= wiki_page_post_previews(@wiki_page) %>
|
||||
|
@ -21,17 +21,13 @@
|
||||
<% end %>
|
||||
|
||||
<div id="wiki-page-body" class="dtext-container">
|
||||
<% if wiki_content.visible? %>
|
||||
<%= format_text(wiki_content.body, allow_color: true, max_thumbs: 75) %>
|
||||
<%= format_text(wiki_content.body, allow_color: true, max_thumbs: 75) %>
|
||||
|
||||
<% if wiki_content.artist %>
|
||||
<p><%= link_to "View artist", wiki_content.artist %></p>
|
||||
<% end %>
|
||||
|
||||
<%= wiki_page_alias_and_implication_list(wiki_content) %>
|
||||
<% else %>
|
||||
<p>This artist has requested removal of their information.</p>
|
||||
<% if wiki_content.artist %>
|
||||
<p><%= link_to "View artist", wiki_content.artist %></p>
|
||||
<% end %>
|
||||
|
||||
<%= wiki_page_alias_and_implication_list(wiki_content) %>
|
||||
</div>
|
||||
|
||||
<%= wiki_page_post_previews(wiki_content) %>
|
||||
|
@ -8,23 +8,26 @@ 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.
|
||||
# We only restore feedback that was destroyed before this date.
|
||||
# Any entries after this are intentional 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
|
||||
feedback_data = batch.filter_map do |mod_action|
|
||||
record_id = mod_action.values["record_id"]
|
||||
category = mod_action.values["type"]
|
||||
body = mod_action.values["reason"]
|
||||
|
||||
# Old mod actions do not contain the necessary information. Skip them.
|
||||
next if record_id.nil? || category.nil? || body.nil?
|
||||
|
||||
destroyed_feedback_ids << record_id
|
||||
|
||||
# old mod actions do not contain the necessary information. we skip them.
|
||||
next if mod_action.values["type"].nil? || mod_action.values["reason"].nil?
|
||||
|
||||
{
|
||||
id: record_id,
|
||||
id: record_id.to_i,
|
||||
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,
|
||||
category: category,
|
||||
body: body.strip,
|
||||
created_at: Date.new(1970, 1, 1), # placeholder
|
||||
updated_at: mod_action.created_at,
|
||||
updater_id: mod_action.creator_id,
|
||||
|
BIN
public/fonts/Lato/Lato-Bold.woff
Normal file
BIN
public/fonts/Lato/Lato-Bold.woff
Normal file
Binary file not shown.
BIN
public/fonts/Lato/Lato-Bold.woff2
Normal file
BIN
public/fonts/Lato/Lato-Bold.woff2
Normal file
Binary file not shown.
BIN
public/fonts/Lato/Lato-BoldItalic.woff
Normal file
BIN
public/fonts/Lato/Lato-BoldItalic.woff
Normal file
Binary file not shown.
BIN
public/fonts/Lato/Lato-BoldItalic.woff2
Normal file
BIN
public/fonts/Lato/Lato-BoldItalic.woff2
Normal file
Binary file not shown.
BIN
public/fonts/Lato/Lato-Italic.woff
Normal file
BIN
public/fonts/Lato/Lato-Italic.woff
Normal file
Binary file not shown.
BIN
public/fonts/Lato/Lato-Italic.woff2
Normal file
BIN
public/fonts/Lato/Lato-Italic.woff2
Normal file
Binary file not shown.
BIN
public/fonts/Lato/Lato-Regular.woff
Normal file
BIN
public/fonts/Lato/Lato-Regular.woff
Normal file
Binary file not shown.
BIN
public/fonts/Lato/Lato-Regular.woff2
Normal file
BIN
public/fonts/Lato/Lato-Regular.woff2
Normal file
Binary file not shown.
BIN
public/fonts/Lexend/Lexend-Bold.woff
Normal file
BIN
public/fonts/Lexend/Lexend-Bold.woff
Normal file
Binary file not shown.
BIN
public/fonts/Lexend/Lexend-Bold.woff2
Normal file
BIN
public/fonts/Lexend/Lexend-Bold.woff2
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user