mirror of
https://github.com/manyfold3d/manyfold.git
synced 2026-10-22 19:52:18 -05:00
299 lines
8.9 KiB
Ruby
299 lines
8.9 KiB
Ruby
module ApplicationHelper
|
|
def site_name(default: translate("application.title"))
|
|
SiteSettings.site_name.presence || default
|
|
end
|
|
|
|
def site_tagline
|
|
SiteSettings.site_tagline.presence || t("application.tagline")
|
|
end
|
|
|
|
def site_icon
|
|
SiteSettings.site_icon.presence || "roundel.svg"
|
|
end
|
|
|
|
def icon_for(klass)
|
|
case klass.name
|
|
when "Creator"
|
|
"person"
|
|
when "Collection"
|
|
"collection"
|
|
when "Library"
|
|
"boxes"
|
|
when "Model"
|
|
"box"
|
|
when "ModelFile"
|
|
"file"
|
|
when "User"
|
|
"person"
|
|
end
|
|
end
|
|
|
|
def markdownify(text)
|
|
Kramdown::Document.new(
|
|
sanitize(text),
|
|
header_offset: 2,
|
|
input: "GFM"
|
|
).to_html.html_safe # rubocop:disable Rails/OutputSafety
|
|
end
|
|
|
|
def card(style, title = nil, options = {}, &content)
|
|
id = options[:id] || "card-#{SecureRandom.hex(4)}"
|
|
card_class = ["card", "mb-4", options[:class]].join(" ")
|
|
if options[:skip_link]
|
|
skiplink = skip_link(options[:skip_link][:target], options[:skip_link][:text])
|
|
card_class += " skip-link-container"
|
|
end
|
|
tag.div class: card_class, data: options[:data], id: id do
|
|
safe_join([
|
|
if title.present?
|
|
tag.div(class: "card-header text-white bg-#{style}") do
|
|
options[:collapse] ?
|
|
safe_join([
|
|
title,
|
|
tag.span(Icon(icon: "arrows-expand", label: t("general.expand")), class: "float-end d-#{options[:collapse]}-none"),
|
|
tag.a(
|
|
nil,
|
|
class: "link-unstyled stretched-link d-#{options[:collapse]}-none",
|
|
"data-bs-toggle": "collapse",
|
|
"data-bs-target": "##{id}-collapse",
|
|
"aria-expanded": false,
|
|
"aria-controls": "#{id}-collapse"
|
|
)
|
|
]) :
|
|
title
|
|
end
|
|
end,
|
|
skiplink,
|
|
tag.div(class: "card-body #{"collapse d-#{options[:collapse]}-block" if options[:collapse]}", id: "#{id}-collapse") do
|
|
tag.div class: "card-text" do
|
|
yield
|
|
end
|
|
end
|
|
].compact)
|
|
end
|
|
end
|
|
|
|
def text_input_row(form, attribute, options = {})
|
|
TextInputRow(
|
|
form: form,
|
|
attribute: attribute,
|
|
label: options.delete(:label),
|
|
help: options.delete(:help),
|
|
options: options
|
|
)
|
|
end
|
|
|
|
def password_input_row(form, attribute, options = {})
|
|
PasswordInputRow(
|
|
form: form,
|
|
attribute: attribute,
|
|
strength_meter: options.delete(:strength_meter),
|
|
label: options.delete(:label),
|
|
help: options.delete(:help),
|
|
options: options
|
|
)
|
|
end
|
|
|
|
def url_input_row(form, attribute, options = {})
|
|
UrlInputRow(
|
|
form: form,
|
|
attribute: attribute,
|
|
label: options.delete(:label),
|
|
help: options.delete(:help),
|
|
options: options
|
|
)
|
|
end
|
|
|
|
def numeric_input_row(form, attribute, options = {})
|
|
NumericInputRow(
|
|
form: form,
|
|
attribute: attribute,
|
|
unit: options.delete(:unit),
|
|
label: options.delete(:label),
|
|
help: options.delete(:help),
|
|
options: options
|
|
)
|
|
end
|
|
|
|
def rich_text_input_row(form, attribute, options = {})
|
|
RichTextInputRow(
|
|
form: form,
|
|
attribute: attribute,
|
|
label: options.delete(:label),
|
|
help: options.delete(:help),
|
|
options: options
|
|
)
|
|
end
|
|
|
|
def checkbox_input_row(form, attribute, options = {})
|
|
CheckBoxInputRow(
|
|
form: form,
|
|
attribute: attribute,
|
|
label: options.delete(:label),
|
|
help: options.delete(:help),
|
|
options: options
|
|
)
|
|
end
|
|
|
|
def select_input_row(form, attribute, select_options, options = {})
|
|
SelectInputRow(
|
|
form: form,
|
|
attribute: attribute,
|
|
select_options: select_options,
|
|
label: options.delete(:label),
|
|
help: options.delete(:help),
|
|
options: options
|
|
)
|
|
end
|
|
|
|
def collection_select_input_row(form, attribute, collection, value_method, text_method, options = {})
|
|
CollectionSelectInputRow(
|
|
form: form,
|
|
attribute: attribute,
|
|
collection: collection,
|
|
value_method: value_method,
|
|
text_method: text_method,
|
|
label: options.delete(:label),
|
|
help: options.delete(:help),
|
|
options: options
|
|
)
|
|
end
|
|
|
|
def file_input_row(form, name, options = {})
|
|
safe_join([
|
|
content_tag(:div) do
|
|
form.label(name, options[:label], class: "col-form-label")
|
|
end,
|
|
content_tag(:div) do
|
|
safe_join [
|
|
content_tag(:div, class: "input-group") do
|
|
safe_join [
|
|
form.file_field(name, class: "form-control"),
|
|
options[:remove] ? form.check_box(:"remove_#{name}", class: "btn-check", autocomplete: "off") : nil,
|
|
options[:remove] ? form.label(:"remove_#{name}", Icon(icon: "trash", label: options[:remove_label]), class: "btn btn-outline-danger") : nil
|
|
].compact
|
|
end,
|
|
errors_for(form.object, name),
|
|
(options[:help] ? content_tag(:span, class: "form-text") { options[:help] } : nil)
|
|
].compact
|
|
end
|
|
])
|
|
end
|
|
|
|
def nav_link(ico, text, path, options = {})
|
|
link_to(
|
|
safe_join(
|
|
[
|
|
content_tag(:span, Icon(icon: ico, label: options[:title].presence || text), class: options[:icon_style]),
|
|
content_tag(:span, text, class: options[:text_style])
|
|
],
|
|
" "
|
|
),
|
|
path,
|
|
class: options[:style] || safe_join(["nav-link", (current_page?(path) ? "active" : "")], " "),
|
|
method: options[:method],
|
|
rel: options[:nofollow] ? "nofollow" : nil,
|
|
id: options[:id],
|
|
data: options[:data],
|
|
aria: {
|
|
label: options[:aria_label]
|
|
}
|
|
)
|
|
end
|
|
|
|
def errors_for(record, attribute)
|
|
return if record.nil? || attribute.nil?
|
|
return unless record.errors.include? attribute
|
|
content_tag(:div,
|
|
record.errors.full_messages_for(attribute).join("; "),
|
|
class: "invalid-feedback d-block")
|
|
end
|
|
|
|
def skip_link(target, text)
|
|
content_tag :div, class: "container-fluid skip-link text-bg-success p-2" do
|
|
link_to text, "##{target}", class: "text-reset", tabindex: 0
|
|
end
|
|
end
|
|
|
|
def translate_with_locale_wrapper(key, **options)
|
|
translate(key, **options) do |str, _key|
|
|
str&.locale ? content_tag(:span, lang: str.locale) { sanitize str } : str
|
|
end
|
|
end
|
|
alias_method :t, :translate_with_locale_wrapper
|
|
|
|
def pagination_settings
|
|
current_user&.pagination_settings || SiteSettings::UserDefaults::PAGINATION
|
|
end
|
|
|
|
def tag_cloud_settings
|
|
current_user&.tag_cloud_settings || SiteSettings::UserDefaults::TAG_CLOUD.merge(heatmap: false)
|
|
end
|
|
|
|
def renderer_settings
|
|
current_user&.renderer_settings || SiteSettings::UserDefaults::RENDERER
|
|
end
|
|
|
|
def file_list_settings
|
|
current_user&.file_list_settings || SiteSettings::UserDefaults::FILE_LIST
|
|
end
|
|
|
|
def problem_settings
|
|
current_user&.problem_settings || Problem::DEFAULT_SEVERITIES
|
|
end
|
|
|
|
def random_password
|
|
(SecureRandom.base64(32) + "!0aB").chars.shuffle.join
|
|
end
|
|
|
|
def server_indicator(object, full_address: false)
|
|
actor = object.respond_to?(:federails_actor) ? object.federails_actor : object
|
|
return if !SiteSettings.federation_enabled? || actor.local?
|
|
link_to sanitize(actor.profile_url), class: "link-primary link-underline-opacity-0 link-underline-opacity-100-hover" do
|
|
safe_join([
|
|
"⁂",
|
|
sanitize(full_address ? actor.at_address : actor.server)
|
|
], " ")
|
|
end
|
|
end
|
|
|
|
def oembed_params
|
|
params.permit(:maxwidth, :maxheight)
|
|
end
|
|
|
|
def indexable_select_options(object)
|
|
current = object.inherited_indexable? ? translate("application_helper.indexable_select_options.yes") : translate("application_helper.indexable_select_options.no")
|
|
options_for_select(
|
|
[
|
|
[translate("application_helper.indexable_select_options.inherit", inherited: current), "inherit"],
|
|
[translate("application_helper.indexable_select_options.always_no"), "no"],
|
|
[translate("application_helper.indexable_select_options.always_yes"), "yes"]
|
|
],
|
|
selected: object&.indexable || "inherit"
|
|
)
|
|
end
|
|
|
|
def ai_indexable_select_options(object)
|
|
current = object.inherited_ai_indexable? ? translate("application_helper.indexable_select_options.yes") : translate("application_helper.indexable_select_options.no")
|
|
options_for_select(
|
|
[
|
|
[translate("application_helper.ai_indexable_select_options.inherit", inherited: current), "inherit"],
|
|
[translate("application_helper.ai_indexable_select_options.always_no"), "no"],
|
|
[translate("application_helper.ai_indexable_select_options.always_yes"), "yes"]
|
|
],
|
|
selected: object&.ai_indexable || "inherit"
|
|
)
|
|
end
|
|
|
|
def tour_attributes(id:, title:, description:)
|
|
return {} if current_user.nil? || current_user.first_use?
|
|
tour_state = current_user.tour_state || User::DEFAULT_TOUR_STATE
|
|
{
|
|
"tour-id" => id,
|
|
"tour-id-completed" => (tour_state.dig("completed")&.include?(id) == true).to_s,
|
|
"tour-title" => title,
|
|
"tour-description" => description
|
|
}.compact
|
|
end
|
|
end
|