mirror of
https://github.com/discourse/discourse.git
synced 2025-05-25 09:57:25 +08:00
FEATURE: fonts section for branding page (#32031)
New configure fonts section was added. Because now we have two sections completed (logos and fonts), new /branding page was introduced and old /logo and /font pages was removed. When text size is changed, modal is displayed to ask if preferences of existing users should be retrospectively updated. https://github.com/user-attachments/assets/f6b0c92a-117f-4064-bd76-30fa05acc6d3 --------- Co-authored-by: Ella <ella.estigoy@gmail.com> Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
This commit is contained in:

committed by
GitHub

parent
637a221517
commit
928f9175f0
@ -0,0 +1,63 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { tracked } from "@glimmer/tracking";
|
||||
import { concat, fn } from "@ember/helper";
|
||||
import { action } from "@ember/object";
|
||||
import { dasherize } from "@ember/string";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import { MAIN_FONTS, MORE_FONTS } from "admin/lib/constants";
|
||||
import eq from "truth-helpers/helpers/eq";
|
||||
|
||||
export default class AdminBrandingFontChooser extends Component {
|
||||
@tracked showMoreFonts = MORE_FONTS.map((font) => font.key).includes(
|
||||
this.args.selectedFont
|
||||
);
|
||||
|
||||
@action
|
||||
setButtonValue(fieldSet, value) {
|
||||
fieldSet(value);
|
||||
}
|
||||
|
||||
@action
|
||||
toggleMoreFonts() {
|
||||
this.showMoreFonts = !this.showMoreFonts;
|
||||
}
|
||||
|
||||
<template>
|
||||
<@field.Custom>
|
||||
{{#each MAIN_FONTS as |font|}}
|
||||
<DButton
|
||||
@action={{fn this.setButtonValue @field.set font.key}}
|
||||
class={{concatClass
|
||||
"admin-fonts-form__button-option font btn-flat"
|
||||
(concat "body-font-" (dasherize font.key))
|
||||
(if (eq @selectedFont font.key) "active")
|
||||
}}
|
||||
>{{font.name}}</DButton>
|
||||
{{/each}}
|
||||
{{#if this.showMoreFonts}}
|
||||
{{#each MORE_FONTS as |font|}}
|
||||
<DButton
|
||||
@action={{fn this.setButtonValue @field.set font.key}}
|
||||
class={{concatClass
|
||||
"admin-fonts-form__button-option font btn-flat"
|
||||
(concat "body-font-" (dasherize font.key))
|
||||
(if (eq @selectedFont font.key) "active")
|
||||
}}
|
||||
>{{font.name}}</DButton>
|
||||
{{/each}}
|
||||
{{/if}}
|
||||
<DButton
|
||||
@action={{this.toggleMoreFonts}}
|
||||
class="admin-fonts-form__more font"
|
||||
>
|
||||
{{#if this.showMoreFonts}}
|
||||
{{i18n "admin.config.branding.fonts.form.less_fonts"}}
|
||||
{{else}}
|
||||
{{i18n "admin.config.branding.fonts.form.more_fonts"}}
|
||||
{{/if}}
|
||||
</DButton>
|
||||
</@field.Custom>
|
||||
</template>
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { fn } from "@ember/helper";
|
||||
import { action } from "@ember/object";
|
||||
import { service } from "@ember/service";
|
||||
import { decamelize, underscore } from "@ember/string";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import Form from "discourse/components/form";
|
||||
import UpdateDefaultTextSize from "discourse/components/modal/update-default-text-size";
|
||||
import concatClass from "discourse/helpers/concat-class";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { bind } from "discourse/lib/decorators";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminBrandingFontChooser from "admin/components/admin-branding-font-chooser";
|
||||
import { DEFAULT_TEXT_SIZES } from "admin/lib/constants";
|
||||
import eq from "truth-helpers/helpers/eq";
|
||||
|
||||
export default class AdminBrandingFontsForm extends Component {
|
||||
@service siteSettings;
|
||||
@service siteSettingChangeTracker;
|
||||
@service toasts;
|
||||
@service modal;
|
||||
@service router;
|
||||
|
||||
updateExistingUsers = null;
|
||||
|
||||
@bind
|
||||
setUpdateExistingUsers(value) {
|
||||
this.updateExistingUsers = value;
|
||||
}
|
||||
|
||||
@action
|
||||
setButtonValue(fieldSet, value) {
|
||||
fieldSet(decamelize(underscore(value)));
|
||||
}
|
||||
|
||||
@action
|
||||
async update(data) {
|
||||
if (this.siteSettings.default_text_size === data.default_text_size) {
|
||||
await this.#save(data);
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await ajax(
|
||||
`/admin/site_settings/default_text_size/user_count.json`,
|
||||
{
|
||||
type: "PUT",
|
||||
data: {
|
||||
default_text_size: data.default_text_size,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const count = result.user_count;
|
||||
if (count > 0) {
|
||||
await this.modal.show(UpdateDefaultTextSize, {
|
||||
model: {
|
||||
setUpdateExistingUsers: this.setUpdateExistingUsers,
|
||||
count,
|
||||
},
|
||||
});
|
||||
await this.#save(data);
|
||||
} else {
|
||||
await this.#save(data);
|
||||
}
|
||||
}
|
||||
|
||||
@action
|
||||
async #save(data) {
|
||||
try {
|
||||
await ajax("/admin/config/branding/fonts.json", {
|
||||
type: "PUT",
|
||||
data: {
|
||||
base_font: data.base_font,
|
||||
heading_font: data.heading_font,
|
||||
default_text_size: data.default_text_size,
|
||||
update_existing_users: this.updateExistingUsers,
|
||||
},
|
||||
});
|
||||
this.toasts.success({
|
||||
duration: 3000,
|
||||
data: {
|
||||
message: i18n("admin.config.branding.fonts.form.saved"),
|
||||
},
|
||||
});
|
||||
this.siteSettingChangeTracker.refreshPage();
|
||||
} catch (err) {
|
||||
this.toasts.error({
|
||||
duration: 3000,
|
||||
data: {
|
||||
message: err.jqXHR.responseJSON.errors[0],
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
get formData() {
|
||||
return {
|
||||
base_font: this.siteSettings.base_font,
|
||||
heading_font: this.siteSettings.heading_font,
|
||||
default_text_size: this.siteSettings.default_text_size,
|
||||
};
|
||||
}
|
||||
|
||||
<template>
|
||||
<Form
|
||||
@onSubmit={{this.update}}
|
||||
@data={{this.formData}}
|
||||
class="admin-fonts-form"
|
||||
as |form transientData|
|
||||
>
|
||||
<form.Field
|
||||
@name="base_font"
|
||||
@title={{i18n "admin.config.branding.fonts.form.base_font.title"}}
|
||||
@validation="required"
|
||||
@format="full"
|
||||
as |field|
|
||||
>
|
||||
<AdminBrandingFontChooser
|
||||
@field={{field}}
|
||||
@selectedFont={{transientData.base_font}}
|
||||
/>
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="heading_font"
|
||||
@title={{i18n "admin.config.branding.fonts.form.heading_font.title"}}
|
||||
@validation="required"
|
||||
@format="full"
|
||||
as |field|
|
||||
>
|
||||
<AdminBrandingFontChooser
|
||||
@field={{field}}
|
||||
@selectedFont={{transientData.heading_font}}
|
||||
/>
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="default_text_size"
|
||||
@title={{i18n
|
||||
"admin.config.branding.fonts.form.default_text_size.title"
|
||||
}}
|
||||
@description={{i18n
|
||||
"admin.config.branding.fonts.form.default_text_size.description"
|
||||
}}
|
||||
@validation="required"
|
||||
@format="full"
|
||||
as |field|
|
||||
>
|
||||
<field.Custom>
|
||||
{{#each DEFAULT_TEXT_SIZES as |textSize|}}
|
||||
<DButton
|
||||
@action={{fn this.setButtonValue field.set textSize}}
|
||||
class={{concatClass
|
||||
"admin-fonts-form__button-option text-size btn-flat"
|
||||
textSize
|
||||
(if (eq transientData.default_text_size textSize) "active")
|
||||
}}
|
||||
>{{textSize}}</DButton>
|
||||
{{/each}}
|
||||
</field.Custom>
|
||||
</form.Field>
|
||||
<form.Submit />
|
||||
</Form>
|
||||
</template>
|
||||
}
|
@ -14,6 +14,7 @@ import SimpleList from "admin/components/simple-list";
|
||||
|
||||
export default class AdminBrandingLogoForm extends Component {
|
||||
@service siteSettings;
|
||||
@service siteSettingChangeTracker;
|
||||
@service toasts;
|
||||
|
||||
@tracked placeholders = {};
|
||||
@ -81,6 +82,7 @@ export default class AdminBrandingLogoForm extends Component {
|
||||
message: i18n("admin.config.branding.logo.form.saved"),
|
||||
},
|
||||
});
|
||||
this.siteSettingChangeTracker.refreshPage();
|
||||
} catch (err) {
|
||||
this.toasts.error({
|
||||
duration: 3000,
|
||||
|
@ -1,3 +0,0 @@
|
||||
import AdminAreaSettingsBaseController from "admin/controllers/admin-area-settings-base";
|
||||
|
||||
export default class AdminConfigFontsSettingsController extends AdminAreaSettingsBaseController {}
|
@ -82,3 +82,43 @@ export const DEFAULT_USER_PREFERENCES = [
|
||||
"default_sidebar_link_to_filtered_list",
|
||||
"default_sidebar_show_count_of_new_items",
|
||||
];
|
||||
|
||||
export const MAIN_FONTS = [
|
||||
{ key: "open_sans", name: "Open Sans" },
|
||||
{ key: "roboto", name: "Roboto" },
|
||||
{ key: "lato", name: "Lato" },
|
||||
{ key: "inter", name: "Inter" },
|
||||
{ key: "montserrat", name: "Montserrat" },
|
||||
{ key: "poppins", name: "Poppins" },
|
||||
{ key: "merriweather", name: "Merriweather" },
|
||||
{ key: "mukta", name: "Mukta" },
|
||||
{ key: "helvetica", name: "Helvetica" },
|
||||
];
|
||||
|
||||
export const MORE_FONTS = [
|
||||
{ key: "arial", name: "Arial" },
|
||||
{ key: "system", name: "System" },
|
||||
{ key: "oxanium", name: "Oxanium" },
|
||||
{ key: "noto_sans_jp", name: "NotoSansJP" },
|
||||
{ key: "roboto_condensed", name: "RobotoCondensed" },
|
||||
{ key: "source_sans_pro", name: "SourceSansPro" },
|
||||
{ key: "oswald", name: "Oswald" },
|
||||
{ key: "raleway", name: "Raleway" },
|
||||
{ key: "roboto_mono", name: "RobotoMono" },
|
||||
{ key: "noto_sans", name: "NotoSans" },
|
||||
{ key: "roboto_slab", name: "RobotoSlab" },
|
||||
{ key: "ubuntu", name: "Ubuntu" },
|
||||
{ key: "pt_sans", name: "PTSans" },
|
||||
{ key: "playfair_display", name: "PlayfairDisplay" },
|
||||
{ key: "nunito", name: "Nunito" },
|
||||
{ key: "lora", name: "Lora" },
|
||||
{ key: "jet_brains_mono", name: "JetBrains Mono" },
|
||||
];
|
||||
|
||||
export const DEFAULT_TEXT_SIZES = [
|
||||
"smallest",
|
||||
"smaller",
|
||||
"normal",
|
||||
"larger",
|
||||
"largest",
|
||||
];
|
||||
|
@ -209,8 +209,9 @@ export default Mixin.create({
|
||||
|
||||
this.setting.validationMessage = null;
|
||||
this.buffered.applyChanges();
|
||||
|
||||
if (this.setting.requiresReload) {
|
||||
this.afterSave();
|
||||
this.siteSettingChangeTracker.refreshPage();
|
||||
}
|
||||
} catch (e) {
|
||||
const json = e.jqXHR?.responseJSON;
|
||||
|
@ -11,7 +11,13 @@ import {
|
||||
} from "admin/lib/constants";
|
||||
import SettingObjectHelper from "admin/lib/setting-object-helper";
|
||||
|
||||
const AUTO_REFRESH_ON_SAVE = ["logo", "logo_small", "large_icon"];
|
||||
const AUTO_REFRESH_ON_SAVE = [
|
||||
"logo",
|
||||
"mobile_logo",
|
||||
"base_font",
|
||||
"heading_font",
|
||||
"default_text_size",
|
||||
];
|
||||
|
||||
export default class SiteSetting extends EmberObject {
|
||||
static findAll(params = {}) {
|
||||
|
@ -0,0 +1,8 @@
|
||||
import DiscourseRoute from "discourse/routes/discourse";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class AdminConfigBrandingRoute extends DiscourseRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.branding.title");
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminConfigWithSettingsRoute from "./admin-config-with-settings-route";
|
||||
|
||||
export default class AdminConfigFontsRoute extends AdminConfigWithSettingsRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.font_style.title");
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminConfigWithSettingsRoute from "./admin-config-with-settings-route";
|
||||
|
||||
export default class AdminConfigLogoRoute extends AdminConfigWithSettingsRoute {
|
||||
titleToken() {
|
||||
return i18n("admin.config.logo.title");
|
||||
}
|
||||
}
|
@ -311,12 +311,6 @@ export default function () {
|
||||
this.route("developer", function () {
|
||||
this.route("settings", { path: "/" });
|
||||
});
|
||||
this.route("fonts", function () {
|
||||
this.route("settings", { path: "/" });
|
||||
});
|
||||
this.route("logo", function () {
|
||||
this.route("settings", { path: "/" });
|
||||
});
|
||||
this.route("branding");
|
||||
this.route("navigation", function () {
|
||||
this.route("settings", { path: "/" });
|
||||
|
@ -4,12 +4,16 @@ import { TrackedSet } from "@ember-compat/tracked-built-ins";
|
||||
import { ajax } from "discourse/lib/ajax";
|
||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import { DEFAULT_TEXT_SIZES } from "admin/lib/constants";
|
||||
import SiteSetting from "admin/models/site-setting";
|
||||
import SiteSettingDefaultCategoriesModal from "../components/modal/site-setting-default-categories";
|
||||
|
||||
export default class SiteSettingChangeTracker extends Service {
|
||||
@service dialog;
|
||||
@service modal;
|
||||
@service session;
|
||||
@service site;
|
||||
@service siteSettings;
|
||||
|
||||
@tracked dirtySiteSettings = new TrackedSet();
|
||||
|
||||
@ -181,6 +185,53 @@ export default class SiteSettingChangeTracker extends Service {
|
||||
});
|
||||
}
|
||||
|
||||
refreshPage() {
|
||||
document.documentElement.style.setProperty(
|
||||
"--font-family",
|
||||
this.siteSettings.base_font
|
||||
);
|
||||
document.documentElement.style.setProperty(
|
||||
"--heading-font-family",
|
||||
this.siteSettings.heading_font
|
||||
);
|
||||
DEFAULT_TEXT_SIZES.forEach((size) => {
|
||||
document.documentElement.classList.remove(`text-size-${size}`);
|
||||
});
|
||||
document.documentElement.classList.add(
|
||||
`text-size-${this.siteSettings.default_text_size}`
|
||||
);
|
||||
let logo;
|
||||
|
||||
if (this.site.mobileView) {
|
||||
if (
|
||||
this.session.defaultColorSchemeIsDark ||
|
||||
this.session.darkModeAvailable
|
||||
) {
|
||||
logo = this.siteSettings.mobile_logo_dark;
|
||||
} else {
|
||||
logo = this.siteSettings.mobile_logo;
|
||||
}
|
||||
}
|
||||
|
||||
if (!logo && this.session.defaultColorSchemeIsDark) {
|
||||
logo = this.siteSettings.logo_dark;
|
||||
}
|
||||
|
||||
if (!logo) {
|
||||
logo = this.siteSettings.logo;
|
||||
}
|
||||
|
||||
// Force reload when switching from text logo to image logo and vice versa
|
||||
if (
|
||||
(!this.siteSettings.logo && document.getElementById("site-logo")) ||
|
||||
(this.siteSettings.logo && !document.getElementById("site-logo"))
|
||||
) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
document.getElementById("site-logo").setAttribute("src", logo);
|
||||
}
|
||||
}
|
||||
|
||||
get count() {
|
||||
return this.dirtySiteSettings.size;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ import RouteTemplate from "ember-route-template";
|
||||
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
|
||||
import DPageHeader from "discourse/components/d-page-header";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminBrandingFontsForm from "admin/components/admin-branding-fonts-form";
|
||||
import AdminBrandingLogoForm from "admin/components/admin-branding-logo-form";
|
||||
import AdminConfigAreaCard from "admin/components/admin-config-area-card";
|
||||
|
||||
@ -33,6 +34,19 @@ export default RouteTemplate(
|
||||
</AdminConfigAreaCard>
|
||||
</div>
|
||||
</div>
|
||||
<div class="admin-config-area">
|
||||
<div class="admin-config-area__primary-content">
|
||||
<AdminConfigAreaCard
|
||||
@heading="admin.config.branding.fonts.title"
|
||||
@collapsable={{true}}
|
||||
class="admin-config-area-branding__fonts"
|
||||
>
|
||||
<:content>
|
||||
<AdminBrandingFontsForm />
|
||||
</:content>
|
||||
</AdminConfigAreaCard>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
);
|
||||
|
@ -1,33 +0,0 @@
|
||||
import RouteTemplate from "ember-route-template";
|
||||
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
|
||||
import DPageHeader from "discourse/components/d-page-header";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminAreaSettings from "admin/components/admin-area-settings";
|
||||
|
||||
export default RouteTemplate(
|
||||
<template>
|
||||
<DPageHeader
|
||||
@hideTabs={{true}}
|
||||
@titleLabel={{i18n "admin.config.font_style.title"}}
|
||||
@descriptionLabel={{i18n "admin.config.font_style.header_description"}}
|
||||
>
|
||||
<:breadcrumbs>
|
||||
<DBreadcrumbsItem @path="/admin" @label={{i18n "admin_title"}} />
|
||||
<DBreadcrumbsItem
|
||||
@path="/admin/config/fonts"
|
||||
@label={{i18n "admin.config.font_style.title"}}
|
||||
/>
|
||||
</:breadcrumbs>
|
||||
</DPageHeader>
|
||||
|
||||
<div class="admin-config-page__main-area">
|
||||
<AdminAreaSettings
|
||||
@showBreadcrumb={{false}}
|
||||
@area="fonts"
|
||||
@path="/admin/config/fonts"
|
||||
@filter={{@controller.filter}}
|
||||
@adminSettingsFilterChangedCallback={{@controller.adminSettingsFilterChangedCallback}}
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
);
|
@ -1,34 +0,0 @@
|
||||
import RouteTemplate from "ember-route-template";
|
||||
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
|
||||
import DPageHeader from "discourse/components/d-page-header";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import AdminBrandingLogoForm from "admin/components/admin-branding-logo-form";
|
||||
import AdminConfigAreaCard from "admin/components/admin-config-area-card";
|
||||
|
||||
export default RouteTemplate(
|
||||
<template>
|
||||
<DPageHeader
|
||||
@hideTabs={{true}}
|
||||
@titleLabel={{i18n "admin.config.logo.title"}}
|
||||
@descriptionLabel={{i18n "admin.config.logo.header_description"}}
|
||||
>
|
||||
<:breadcrumbs>
|
||||
<DBreadcrumbsItem @path="/admin" @label={{i18n "admin_title"}} />
|
||||
<DBreadcrumbsItem
|
||||
@path="/admin/config/logo"
|
||||
@label={{i18n "admin.config.logo.title"}}
|
||||
/>
|
||||
</:breadcrumbs>
|
||||
</DPageHeader>
|
||||
|
||||
<AdminConfigAreaCard
|
||||
@heading="admin.config.branding.logo.title"
|
||||
@collapsable={{true}}
|
||||
class="admin-config-area-branding__logo"
|
||||
>
|
||||
<:content>
|
||||
<AdminBrandingLogoForm />
|
||||
</:content>
|
||||
</AdminConfigAreaCard>
|
||||
</template>
|
||||
);
|
@ -1,5 +1,4 @@
|
||||
import RouteTemplate from "ember-route-template";
|
||||
import routeAction from "discourse/helpers/route-action";
|
||||
import { i18n } from "discourse-i18n";
|
||||
import SiteSetting from "admin/components/site-setting";
|
||||
|
||||
@ -8,10 +7,7 @@ export default RouteTemplate(
|
||||
{{#if @controller.filteredContent}}
|
||||
<section class="form-horizontal settings">
|
||||
{{#each @controller.filteredContent as |setting|}}
|
||||
<SiteSetting
|
||||
@setting={{setting}}
|
||||
@afterSave={{routeAction "refreshAll"}}
|
||||
/>
|
||||
<SiteSetting @setting={{setting}} />
|
||||
{{/each}}
|
||||
{{#if @controller.category.hasMore}}
|
||||
<p class="warning">{{i18n
|
||||
|
@ -0,0 +1,44 @@
|
||||
import Component from "@glimmer/component";
|
||||
import { action } from "@ember/object";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import DModal from "discourse/components/d-modal";
|
||||
import { i18n } from "discourse-i18n";
|
||||
|
||||
export default class UpdateDefaultTextSize extends Component {
|
||||
@action
|
||||
updateExistingUsers() {
|
||||
this.args.model.setUpdateExistingUsers(true);
|
||||
this.args.closeModal();
|
||||
}
|
||||
|
||||
@action
|
||||
cancel() {
|
||||
this.args.model.setUpdateExistingUsers(null);
|
||||
this.args.closeModal();
|
||||
}
|
||||
|
||||
<template>
|
||||
<DModal
|
||||
@title={{i18n "admin.config.branding.fonts.backfill_modal.title"}}
|
||||
@closeModal={{@closeModal}}
|
||||
>
|
||||
<:body>
|
||||
{{i18n
|
||||
"admin.config.branding.fonts.backfill_modal.description"
|
||||
count=@model.count
|
||||
}}
|
||||
</:body>
|
||||
<:footer>
|
||||
<DButton
|
||||
@action={{this.updateExistingUsers}}
|
||||
@label="admin.config.branding.fonts.backfill_modal.modal_yes"
|
||||
class="btn-primary"
|
||||
/>
|
||||
<DButton
|
||||
@action={{this.cancel}}
|
||||
@label="admin.config.branding.fonts.backfill_modal.modal_no"
|
||||
/>
|
||||
</:footer>
|
||||
</DModal>
|
||||
</template>
|
||||
}
|
@ -90,3 +90,13 @@ export const TOPIC_VISIBILITY_REASONS = {
|
||||
export const MAX_UNOPTIMIZED_CATEGORIES = 1000;
|
||||
|
||||
export const REVIEWABLE_UNKNOWN_TYPE_SOURCE = "unknown";
|
||||
|
||||
export const ADMIN_SEARCH_RESULT_TYPES = [
|
||||
"page",
|
||||
"setting",
|
||||
"theme",
|
||||
"component",
|
||||
"report",
|
||||
];
|
||||
|
||||
export const API_KEY_SCOPE_MODES = ["global", "read_only", "granular"];
|
||||
|
@ -200,18 +200,10 @@ export const ADMIN_NAV_MAP = [
|
||||
label: "admin.config_sections.appearance.title",
|
||||
links: [
|
||||
{
|
||||
name: "admin_font_style",
|
||||
route: "adminConfig.fonts.settings",
|
||||
label: "admin.config.font_style.title",
|
||||
description: "admin.config.font_style.header_description",
|
||||
icon: "italic",
|
||||
settings_area: "fonts",
|
||||
},
|
||||
{
|
||||
name: "admin_site_logo",
|
||||
route: "adminConfig.logo.settings",
|
||||
label: "admin.config.logo.title",
|
||||
description: "admin.config.logo.header_description",
|
||||
name: "admin_branding",
|
||||
route: "adminConfig.branding",
|
||||
label: "admin.config.branding.title",
|
||||
description: "admin.config.branding.header_description",
|
||||
icon: "fab-discourse",
|
||||
settings_category: "branding",
|
||||
},
|
||||
|
@ -175,3 +175,103 @@
|
||||
width: var(--form-kit-small-input) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-fonts-form {
|
||||
&__more {
|
||||
font-size: var(--font-down-1-rem);
|
||||
}
|
||||
|
||||
.form-kit__field-custom {
|
||||
width: 100% !important;
|
||||
|
||||
.form-kit__control-custom {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
.admin-fonts-form__button-option {
|
||||
border: 1px solid var(--primary-low);
|
||||
font-size: var(--font-down-1-rem);
|
||||
max-height: 4em;
|
||||
height: 50px;
|
||||
margin-bottom: 1em;
|
||||
padding: 0 0.65em;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--primary-low-mid);
|
||||
}
|
||||
|
||||
&.active {
|
||||
position: relative;
|
||||
border: 2px solid var(--tertiary);
|
||||
|
||||
&::after {
|
||||
position: absolute;
|
||||
top: 35%;
|
||||
left: 0.5rem;
|
||||
font-family: "Segoe UI", Arial, sans-serif;
|
||||
content: "\2714"; // ✔
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 1rem;
|
||||
height: 1rem;
|
||||
background-color: var(--tertiary);
|
||||
color: var(--secondary);
|
||||
border-radius: 9999px;
|
||||
font-size: 0.5rem;
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
border-color: var(--tertiary);
|
||||
}
|
||||
}
|
||||
|
||||
&.font {
|
||||
flex: 0 0 32%;
|
||||
max-width: 32%;
|
||||
|
||||
@media (max-width: $mobile-breakpoint) {
|
||||
flex: 0 0 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.text-size {
|
||||
flex: 0 0 19%;
|
||||
max-width: 19%;
|
||||
|
||||
@media (max-width: $mobile-breakpoint) {
|
||||
flex: 0 0 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
// px muse be used because there is different font size inside each button
|
||||
height: 45px;
|
||||
|
||||
&.smallest {
|
||||
font-size: var(--base-font-size-smallest);
|
||||
}
|
||||
|
||||
&.smaller {
|
||||
font-size: var(--base-font-size-smaller);
|
||||
}
|
||||
|
||||
&.normal {
|
||||
font-size: var(--base-font-size-normal);
|
||||
}
|
||||
|
||||
&.larger {
|
||||
font-size: var(--base-font-size-larger);
|
||||
}
|
||||
|
||||
&.largest {
|
||||
font-size: var(--base-font-size-largest);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -38,4 +38,36 @@ class Admin::Config::BrandingController < Admin::AdminController
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def fonts
|
||||
previous_default_text_size = SiteSetting.default_text_size
|
||||
SiteSetting::Update.call(
|
||||
guardian:,
|
||||
params: {
|
||||
settings: [
|
||||
{ setting_name: "base_font", value: params[:base_font] },
|
||||
{ setting_name: "heading_font", value: params[:heading_font] },
|
||||
{
|
||||
setting_name: "default_text_size",
|
||||
value: params[:default_text_size],
|
||||
backfill: params[:update_existing_users] == "true",
|
||||
},
|
||||
],
|
||||
},
|
||||
) do
|
||||
on_success { render json: success_json }
|
||||
on_failed_policy(:settings_are_visible) do |policy|
|
||||
raise Discourse::InvalidParameters, policy.reason
|
||||
end
|
||||
on_failed_policy(:settings_are_unshadowed_globally) do |policy|
|
||||
raise Discourse::InvalidParameters, policy.reason
|
||||
end
|
||||
on_failed_policy(:settings_are_configurable) do |policy|
|
||||
raise Discourse::InvalidParameters, policy.reason
|
||||
end
|
||||
on_failed_policy(:values_are_valid) do |policy|
|
||||
raise Discourse::InvalidParameters, policy.reason
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
15
app/models/default_text_size_setting.rb
Normal file
15
app/models/default_text_size_setting.rb
Normal file
@ -0,0 +1,15 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "enum_site_setting"
|
||||
|
||||
class DefaultTextSizeSetting < EnumSiteSetting
|
||||
DEFAULT_TEXT_SIZES = UserOption.text_sizes.keys.map(&:to_s)
|
||||
|
||||
def self.valid_value?(val)
|
||||
values.any? { |v| v[:value].to_s == val.to_s }
|
||||
end
|
||||
|
||||
def self.values
|
||||
@values ||= DEFAULT_TEXT_SIZES
|
||||
end
|
||||
end
|
@ -48,7 +48,7 @@ class UserOption < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def self.text_sizes
|
||||
@text_sizes ||= Enum.new(normal: 0, larger: 1, largest: 2, smaller: 3, smallest: 4)
|
||||
@text_sizes ||= Enum.new(smallest: 4, smaller: 3, normal: 0, larger: 1, largest: 2)
|
||||
end
|
||||
|
||||
def self.title_count_modes
|
||||
|
@ -5241,9 +5241,6 @@ en:
|
||||
title: "Moderation"
|
||||
header_description: "The flagging system in Discourse helps you and your moderator team manage content and user behavior, keeping your community respectful and healthy. The defaults are suitable for most communities and you don’t have to change them. However, if your site has particular requirements you can disable flags you don’t need and add your own custom flags."
|
||||
keywords: "flag|review|spam|illegal"
|
||||
font_style:
|
||||
title: "Font style"
|
||||
header_description: "Customize the font styles used by your themes"
|
||||
files:
|
||||
title: "Files"
|
||||
header_description: "Settings that control file size and type limits, avatar sizes and sources, file storage, image quality and compression, and more"
|
||||
@ -5257,11 +5254,9 @@ en:
|
||||
login_and_authentication:
|
||||
title: "Login & authentication"
|
||||
header_description: "Configure how users log in and authenticate, secrets and keys, OAuth2 providers, and more"
|
||||
logo:
|
||||
title: "Site logo"
|
||||
header_description: "Customize the variations of your site logo"
|
||||
branding:
|
||||
title: "Branding"
|
||||
header_description: "Customize the variations of your site logo and fonts"
|
||||
logo:
|
||||
title: "Logo"
|
||||
form:
|
||||
@ -5326,6 +5321,27 @@ en:
|
||||
title: "X summary large image"
|
||||
description: "X card 'summary large image'. If left blank, regular card metadata is generated using the OpenGraph_image, as long as that is not also a .svg."
|
||||
help_text: "recommended size is at least 280 x 150 pixels. Don't use an SVG image."
|
||||
fonts:
|
||||
title: "Fonts"
|
||||
form:
|
||||
more_fonts: "More fonts"
|
||||
less_fonts: "Less fonts"
|
||||
saved: "Font settings are saved."
|
||||
base_font:
|
||||
title: "Base font"
|
||||
heading_font:
|
||||
title: "Heading font"
|
||||
default_text_size:
|
||||
title: "Default text size"
|
||||
description: "This size can be subsequently adjusted by each user according to their preferences."
|
||||
backfill_modal:
|
||||
title: "Apply new default text settings?"
|
||||
description:
|
||||
one: "You’ve updated the default text size. Would you like to apply this change to %{count} existing user?"
|
||||
other: "You’ve updated the default text size. Would you like to apply this change to %{count} existing users?"
|
||||
modal_yes: "Yes"
|
||||
modal_no: "No, only apply going forward"
|
||||
|
||||
navigation:
|
||||
title: "Navigation"
|
||||
header_description: "Configure the navigation links and menu items for your site. This includes the location and behavior of the primary navigation menu, the quick links at the top of the homepage, as well as the admin sidebar"
|
||||
|
@ -394,12 +394,10 @@ Discourse::Application.routes.draw do
|
||||
namespace :config, constraints: StaffConstraint.new do
|
||||
resources :site_settings, only: %i[index]
|
||||
get "developer" => "site_settings#index"
|
||||
get "fonts" => "site_settings#index"
|
||||
get "files" => "site_settings#index"
|
||||
get "legal" => "site_settings#index"
|
||||
get "localization" => "site_settings#index"
|
||||
get "login-and-authentication" => "site_settings#index"
|
||||
get "logo" => "site_settings#index"
|
||||
get "navigation" => "site_settings#index"
|
||||
get "notifications" => "site_settings#index"
|
||||
get "rate-limits" => "site_settings#index"
|
||||
@ -414,6 +412,7 @@ Discourse::Application.routes.draw do
|
||||
get "group-permissions" => "site_settings#index"
|
||||
get "branding" => "branding#index"
|
||||
put "branding/logo" => "branding#logo"
|
||||
put "branding/fonts" => "branding#fonts"
|
||||
get "colors/:id" => "color_palettes#show"
|
||||
|
||||
resources :flags, only: %i[index new create update destroy] do
|
||||
|
@ -439,6 +439,7 @@ basic:
|
||||
list_type: font
|
||||
area: "fonts"
|
||||
allow_any: false
|
||||
client: true
|
||||
heading_font:
|
||||
default: "inter"
|
||||
choices: "BaseFontSetting.values"
|
||||
@ -447,6 +448,7 @@ basic:
|
||||
list_type: font
|
||||
area: "fonts"
|
||||
allow_any: false
|
||||
client: true
|
||||
enable_sitemap:
|
||||
default: true
|
||||
sitemap_page_size:
|
||||
@ -3283,11 +3285,8 @@ user_preferences:
|
||||
default_text_size:
|
||||
type: enum
|
||||
default: normal
|
||||
choices:
|
||||
- smaller
|
||||
- normal
|
||||
- larger
|
||||
- largest
|
||||
client: true
|
||||
choices: "DefaultTextSizeSetting.values"
|
||||
area: "fonts"
|
||||
|
||||
default_title_count_mode:
|
||||
|
@ -137,6 +137,8 @@ task "javascript:update_constants" => :environment do
|
||||
)
|
||||
end
|
||||
|
||||
MAIN_FONT_KEYS = %w[helvetica inter lato montserrat open_sans poppins roboto merriweather mukta]
|
||||
|
||||
write_template("admin/addon/lib/constants.js", task_name, <<~JS)
|
||||
export const ADMIN_SEARCH_RESULT_TYPES = #{Admin::SearchController::RESULT_TYPES.to_json};
|
||||
|
||||
@ -151,6 +153,12 @@ task "javascript:update_constants" => :environment do
|
||||
export const USER_FIELD_FLAGS = #{UserField::FLAG_ATTRIBUTES};
|
||||
|
||||
export const DEFAULT_USER_PREFERENCES = #{SiteSetting::DEFAULT_USER_PREFERENCES.to_json};
|
||||
|
||||
export const MAIN_FONTS = #{DiscourseFonts.fonts.filter { |font| MAIN_FONT_KEYS.include?(font[:key]) }.map { |font| { key: font[:key], name: font[:name] } }.to_json}
|
||||
|
||||
export const MORE_FONTS = #{DiscourseFonts.fonts.reject { |font| MAIN_FONT_KEYS.include?(font[:key]) }.map { |font| { key: font[:key], name: font[:name] } }.to_json}
|
||||
|
||||
export const DEFAULT_TEXT_SIZES = #{DefaultTextSizeSetting::DEFAULT_TEXT_SIZES}
|
||||
JS
|
||||
|
||||
write_template("discourse/app/lib/constants.js", task_name, <<~JS)
|
||||
@ -183,6 +191,10 @@ task "javascript:update_constants" => :environment do
|
||||
export const MAX_UNOPTIMIZED_CATEGORIES = #{CategoryList::MAX_UNOPTIMIZED_CATEGORIES};
|
||||
|
||||
export const REVIEWABLE_UNKNOWN_TYPE_SOURCE = "#{Reviewable::UNKNOWN_TYPE_SOURCE}";
|
||||
|
||||
export const ADMIN_SEARCH_RESULT_TYPES = #{Admin::SearchController::RESULT_TYPES.to_json};
|
||||
|
||||
export const API_KEY_SCOPE_MODES = #{ApiKey.scope_modes.keys.to_json}
|
||||
JS
|
||||
|
||||
pretty_notifications = Notification.types.map { |n| " #{n[0]}: #{n[1]}," }.join("\n")
|
||||
|
73
spec/requests/admin/config/branding_controller_spec.rb
Normal file
73
spec/requests/admin/config/branding_controller_spec.rb
Normal file
@ -0,0 +1,73 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe Admin::Config::BrandingController do
|
||||
fab!(:admin)
|
||||
fab!(:moderator)
|
||||
fab!(:user)
|
||||
|
||||
describe "#fonts" do
|
||||
context "when logged in as an admin" do
|
||||
before { sign_in(admin) }
|
||||
it "updates the fonts and text size" do
|
||||
put "/admin/config/branding/fonts.json",
|
||||
params: {
|
||||
base_font: "helvetica",
|
||||
heading_font: "roboto",
|
||||
default_text_size: "largest",
|
||||
}
|
||||
expect(response.status).to eq(200)
|
||||
|
||||
expect(SiteSetting.base_font).to eq("helvetica")
|
||||
expect(SiteSetting.heading_font).to eq("roboto")
|
||||
expect(SiteSetting.default_text_size).to eq("largest")
|
||||
end
|
||||
|
||||
it "validates values" do
|
||||
put "/admin/config/branding/fonts.json",
|
||||
params: {
|
||||
base_font: "invalid_font",
|
||||
heading_font: "invalid_font",
|
||||
default_text_size: "invalid_size",
|
||||
}
|
||||
expect(response.status).to eq(400)
|
||||
expect(SiteSetting.base_font).to eq("inter")
|
||||
expect(SiteSetting.heading_font).to eq("inter")
|
||||
expect(SiteSetting.default_text_size).to eq("normal")
|
||||
end
|
||||
end
|
||||
|
||||
context "when logged in as a moderator" do
|
||||
before { sign_in(moderator) }
|
||||
it "denies access with a 403 response" do
|
||||
put "/admin/config/branding/fonts.json",
|
||||
params: {
|
||||
base_font: "helvetica",
|
||||
heading_font: "roboto",
|
||||
default_text_size: "largest",
|
||||
}
|
||||
expect(response.status).to eq(403)
|
||||
expect(SiteSetting.base_font).to eq("inter")
|
||||
expect(SiteSetting.heading_font).to eq("inter")
|
||||
expect(SiteSetting.default_text_size).to eq("normal")
|
||||
end
|
||||
end
|
||||
|
||||
context "when logged in as a non-staff user" do
|
||||
before { sign_in(user) }
|
||||
|
||||
it "denies access with a 404 response" do
|
||||
put "/admin/config/branding/fonts.json",
|
||||
params: {
|
||||
base_font: "helvetica",
|
||||
heading_font: "roboto",
|
||||
default_text_size: "largest",
|
||||
}
|
||||
|
||||
expect(response.status).to eq(404)
|
||||
expect(SiteSetting.base_font).to eq("inter")
|
||||
expect(SiteSetting.heading_font).to eq("inter")
|
||||
expect(SiteSetting.default_text_size).to eq("normal")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -6,206 +6,267 @@ describe "Admin Branding Page", type: :system do
|
||||
|
||||
let(:branding_page) { PageObjects::Pages::AdminBranding.new }
|
||||
let(:image_file) { file_from_fixtures("logo.png", "images") }
|
||||
let(:modal) { PageObjects::Modals::Base.new }
|
||||
|
||||
before { sign_in(admin) }
|
||||
|
||||
describe "primary section" do
|
||||
let(:primary_section_logos) { %i[logo logo_dark large_icon favicon logo_small logo_small_dark] }
|
||||
it "can upload images and dark versions" do
|
||||
branding_page.visit
|
||||
describe "logo" do
|
||||
describe "primary section" do
|
||||
let(:primary_section_logos) do
|
||||
%i[logo logo_dark large_icon favicon logo_small logo_small_dark]
|
||||
end
|
||||
it "can upload images and dark versions" do
|
||||
branding_page.visit
|
||||
|
||||
expect(branding_page.logo_form).to have_no_form_field(:logo_dark)
|
||||
branding_page.logo_form.toggle_dark_mode(:logo_dark_required)
|
||||
expect(branding_page.logo_form).to have_form_field(:logo_dark)
|
||||
expect(branding_page.logo_form).to have_no_form_field(:logo_dark)
|
||||
branding_page.logo_form.toggle_dark_mode(:logo_dark_required)
|
||||
expect(branding_page.logo_form).to have_form_field(:logo_dark)
|
||||
|
||||
expect(branding_page.logo_form).to have_no_form_field(:logo_small_dark)
|
||||
branding_page.logo_form.toggle_dark_mode(:logo_small_dark_required)
|
||||
expect(branding_page.logo_form).to have_form_field(:logo_small_dark)
|
||||
expect(branding_page.logo_form).to have_no_form_field(:logo_small_dark)
|
||||
branding_page.logo_form.toggle_dark_mode(:logo_small_dark_required)
|
||||
expect(branding_page.logo_form).to have_form_field(:logo_small_dark)
|
||||
|
||||
primary_section_logos.each do |image_type|
|
||||
branding_page.logo_form.upload_image(image_type, image_file)
|
||||
primary_section_logos.each do |image_type|
|
||||
branding_page.logo_form.upload_image(image_type, image_file)
|
||||
end
|
||||
|
||||
primary_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
visit("/")
|
||||
branding_page.visit
|
||||
|
||||
expect(branding_page.logo_form).to have_form_field(:logo_dark)
|
||||
expect(branding_page.logo_form).to have_form_field(:logo_small_dark)
|
||||
|
||||
primary_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
end
|
||||
|
||||
primary_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
it "can remove images" do
|
||||
primary_section_logos.each { |image_type| SiteSetting.send("#{image_type}=", image_upload) }
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
branding_page.visit
|
||||
|
||||
visit("/")
|
||||
branding_page.visit
|
||||
primary_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
expect(branding_page.logo_form).to have_form_field(:logo_dark)
|
||||
expect(branding_page.logo_form).to have_form_field(:logo_small_dark)
|
||||
primary_section_logos.each { |image_type| branding_page.logo_form.remove_image(image_type) }
|
||||
|
||||
primary_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
branding_page.logo_form.submit
|
||||
expect(page).to have_css("#site-text-logo")
|
||||
|
||||
primary_section_logos.each { |image_type| expect(SiteSetting.send(image_type)).to eq(nil) }
|
||||
end
|
||||
end
|
||||
|
||||
it "can remove images" do
|
||||
primary_section_logos.each { |image_type| SiteSetting.send("#{image_type}=", image_upload) }
|
||||
describe "mobile section" do
|
||||
let(:mobile_section_logos) { %i[mobile_logo mobile_logo_dark manifest_icon apple_touch_icon] }
|
||||
it "can upload images and dark versions" do
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_mobile_section
|
||||
|
||||
branding_page.visit
|
||||
expect(branding_page.logo_form).to have_no_form_field(:mobile_logo_dark)
|
||||
branding_page.logo_form.toggle_dark_mode(:mobile_logo_dark_required)
|
||||
expect(branding_page.logo_form).to have_form_field(:mobile_logo_dark)
|
||||
|
||||
primary_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
mobile_section_logos.each do |image_type|
|
||||
branding_page.logo_form.upload_image(image_type, image_file)
|
||||
end
|
||||
|
||||
mobile_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
visit("/")
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_mobile_section
|
||||
|
||||
expect(branding_page.logo_form).to have_form_field(:mobile_logo_dark)
|
||||
|
||||
mobile_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
end
|
||||
|
||||
primary_section_logos.each { |image_type| branding_page.logo_form.remove_image(image_type) }
|
||||
it "can remove images" do
|
||||
mobile_section_logos.each { |image_type| SiteSetting.send("#{image_type}=", image_upload) }
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_mobile_section
|
||||
|
||||
primary_section_logos.each { |image_type| expect(SiteSetting.send(image_type)).to eq(nil) }
|
||||
mobile_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
mobile_section_logos.each { |image_type| branding_page.logo_form.remove_image(image_type) }
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
mobile_section_logos.each { |image_type| expect(SiteSetting.send(image_type)).to eq(nil) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "email section" do
|
||||
let(:email_section_logos) { %i[digest_logo] }
|
||||
it "can upload images" do
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_email_section
|
||||
|
||||
email_section_logos.each do |image_type|
|
||||
branding_page.logo_form.upload_image(image_type, image_file)
|
||||
end
|
||||
|
||||
email_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
visit("/")
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_email_section
|
||||
|
||||
email_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
end
|
||||
|
||||
it "can remove images" do
|
||||
email_section_logos.each { |image_type| SiteSetting.send("#{image_type}=", image_upload) }
|
||||
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_email_section
|
||||
|
||||
email_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
email_section_logos.each { |image_type| branding_page.logo_form.remove_image(image_type) }
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
email_section_logos.each { |image_type| expect(SiteSetting.send(image_type)).to eq(nil) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "social media section" do
|
||||
let(:social_media_section_logos) { %i[opengraph_image] }
|
||||
it "can upload images" do
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_social_media_section
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
branding_page.logo_form.upload_image(image_type, image_file)
|
||||
end
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
visit("/")
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_social_media_section
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
end
|
||||
|
||||
it "can remove images" do
|
||||
social_media_section_logos.each do |image_type|
|
||||
SiteSetting.send("#{image_type}=", image_upload)
|
||||
end
|
||||
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_social_media_section
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
branding_page.logo_form.remove_image(image_type)
|
||||
end
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
expect(SiteSetting.send(image_type)).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "mobile section" do
|
||||
let(:mobile_section_logos) { %i[mobile_logo mobile_logo_dark manifest_icon apple_touch_icon] }
|
||||
it "can upload images and dark versions" do
|
||||
describe "fonts" do
|
||||
it "allows an admin to change the site's base font and heading font" do
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_mobile_section
|
||||
branding_page.fonts_form.select_font("base", "helvetica")
|
||||
|
||||
expect(branding_page.logo_form).to have_no_form_field(:mobile_logo_dark)
|
||||
branding_page.logo_form.toggle_dark_mode(:mobile_logo_dark_required)
|
||||
expect(branding_page.logo_form).to have_form_field(:mobile_logo_dark)
|
||||
expect(branding_page.fonts_form).to have_no_font("heading", "Oswald")
|
||||
branding_page.fonts_form.show_more_fonts("heading")
|
||||
branding_page.fonts_form.select_font("heading", "oswald")
|
||||
|
||||
mobile_section_logos.each do |image_type|
|
||||
branding_page.logo_form.upload_image(image_type, image_file)
|
||||
end
|
||||
branding_page.fonts_form.submit
|
||||
expect(branding_page.fonts_form).to have_saved_successfully
|
||||
|
||||
mobile_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
visit("/")
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_mobile_section
|
||||
|
||||
expect(branding_page.logo_form).to have_form_field(:mobile_logo_dark)
|
||||
|
||||
mobile_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
expect(branding_page.fonts_form.active_font("base")).to eq("Helvetica")
|
||||
expect(branding_page.fonts_form.active_font("heading")).to eq("Oswald")
|
||||
end
|
||||
|
||||
it "can remove images" do
|
||||
mobile_section_logos.each { |image_type| SiteSetting.send("#{image_type}=", image_upload) }
|
||||
|
||||
it "allows an admin to change default text size and does not update existing users preferences" do
|
||||
Jobs.run_immediately!
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_mobile_section
|
||||
expect(page).to have_css("html.text-size-normal")
|
||||
branding_page.fonts_form.select_default_text_size("larger")
|
||||
|
||||
mobile_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
branding_page.fonts_form.submit
|
||||
expect(modal).to be_open
|
||||
expect(modal.header).to have_content(
|
||||
I18n.t("admin_js.admin.config.branding.fonts.backfill_modal.title"),
|
||||
)
|
||||
modal.close
|
||||
expect(modal).to be_closed
|
||||
expect(branding_page.fonts_form).to have_saved_successfully
|
||||
|
||||
mobile_section_logos.each { |image_type| branding_page.logo_form.remove_image(image_type) }
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
mobile_section_logos.each { |image_type| expect(SiteSetting.send(image_type)).to eq(nil) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "email section" do
|
||||
let(:email_section_logos) { %i[digest_logo] }
|
||||
it "can upload images" do
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_email_section
|
||||
|
||||
email_section_logos.each do |image_type|
|
||||
branding_page.logo_form.upload_image(image_type, image_file)
|
||||
end
|
||||
|
||||
email_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
visit("/")
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_email_section
|
||||
|
||||
email_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
visit "/"
|
||||
expect(page).to have_css("html.text-size-normal")
|
||||
end
|
||||
|
||||
it "can remove images" do
|
||||
email_section_logos.each { |image_type| SiteSetting.send("#{image_type}=", image_upload) }
|
||||
|
||||
it "allows an admin to change default text size and updates existing users preferences" do
|
||||
Jobs.run_immediately!
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_email_section
|
||||
expect(page).to have_css("html.text-size-normal")
|
||||
branding_page.fonts_form.select_default_text_size("larger")
|
||||
|
||||
email_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
branding_page.fonts_form.submit
|
||||
expect(modal).to be_open
|
||||
expect(modal.header).to have_content(
|
||||
I18n.t("admin_js.admin.config.branding.fonts.backfill_modal.title"),
|
||||
)
|
||||
modal.click_primary_button
|
||||
expect(modal).to be_closed
|
||||
expect(branding_page.fonts_form).to have_saved_successfully
|
||||
|
||||
email_section_logos.each { |image_type| branding_page.logo_form.remove_image(image_type) }
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
email_section_logos.each { |image_type| expect(SiteSetting.send(image_type)).to eq(nil) }
|
||||
end
|
||||
end
|
||||
|
||||
describe "social media section" do
|
||||
let(:social_media_section_logos) { %i[opengraph_image] }
|
||||
it "can upload images" do
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_social_media_section
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
branding_page.logo_form.upload_image(image_type, image_file)
|
||||
end
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
visit("/")
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_social_media_section
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
end
|
||||
|
||||
it "can remove images" do
|
||||
social_media_section_logos.each do |image_type|
|
||||
SiteSetting.send("#{image_type}=", image_upload)
|
||||
end
|
||||
|
||||
branding_page.visit
|
||||
branding_page.logo_form.expand_social_media_section
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
expect(branding_page.logo_form.image_uploader(image_type)).to have_uploaded_image
|
||||
end
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
branding_page.logo_form.remove_image(image_type)
|
||||
end
|
||||
|
||||
branding_page.logo_form.submit
|
||||
expect(branding_page.logo_form).to have_saved_successfully
|
||||
|
||||
social_media_section_logos.each do |image_type|
|
||||
expect(SiteSetting.send(image_type)).to eq(nil)
|
||||
end
|
||||
visit "/"
|
||||
expect(page).to have_css("html.text-size-larger")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -0,0 +1,49 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module PageObjects
|
||||
module Components
|
||||
class AdminBrandingFontsForm < PageObjects::Components::Base
|
||||
def select_font(section, font)
|
||||
find(
|
||||
"[data-name='#{section}_font'] .admin-fonts-form__button-option.body-font-#{font}",
|
||||
).click
|
||||
end
|
||||
|
||||
def select_default_text_size(size)
|
||||
find(".admin-fonts-form__button-option.#{size}").click
|
||||
end
|
||||
|
||||
def active_font(section)
|
||||
find("[data-name='#{section}_font'] .admin-fonts-form__button-option.active").text
|
||||
end
|
||||
|
||||
def has_no_font?(section, font)
|
||||
page.has_no_css?(
|
||||
"[data-name='#{section}_font'] .admin-fonts-form__button-option.body-font-#{font}",
|
||||
)
|
||||
end
|
||||
|
||||
def show_more_fonts(section)
|
||||
find("[data-name='#{section}_font'] .admin-fonts-form__more").click
|
||||
end
|
||||
|
||||
def has_form_field?(field)
|
||||
page.has_css?("#control-#{field}")
|
||||
end
|
||||
|
||||
def submit
|
||||
form.submit
|
||||
end
|
||||
|
||||
def has_saved_successfully?
|
||||
PageObjects::Components::Toasts.new.has_success?(
|
||||
I18n.t("admin_js.admin.config.branding.fonts.form.saved"),
|
||||
)
|
||||
end
|
||||
|
||||
def form
|
||||
@form ||= PageObjects::Components::FormKit.new(".admin-fonts-form")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -10,6 +10,10 @@ module PageObjects
|
||||
def logo_form
|
||||
@logo_form ||= PageObjects::Components::AdminBrandingLogoForm.new
|
||||
end
|
||||
|
||||
def fonts_form
|
||||
@fonts_form ||= PageObjects::Components::AdminBrandingFontsForm.new
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
Reference in New Issue
Block a user