feat: customize site banners and login notices
This commit is contained in:
@@ -26,6 +26,11 @@ const SELECTS: Record<string, Option[]> = {
|
||||
requests_data_source: [{ value: 'always_js', label: 'Read directly from Seerr' }, { value: 'prefer_cache', label: 'Use saved requests' }],
|
||||
}
|
||||
|
||||
const COLOR_DEFAULTS: Record<string, string> = {
|
||||
site_banner_background_color: '#332814',
|
||||
site_banner_border_color: '#a27b32',
|
||||
}
|
||||
|
||||
export default function SettingField(props: Props) {
|
||||
const { setting, label, value, help, placeholder, onChange } = props
|
||||
const id = `setting-${setting.key}`
|
||||
@@ -36,13 +41,15 @@ export default function SettingField(props: Props) {
|
||||
const zeroAllowed = setting.key === 'log_file_backup_count'
|
||||
const minimum = zeroAllowed ? 0 : 1
|
||||
const maximum = setting.key === 'issue_confirmation_interval_value' ? 365 : setting.key.endsWith('_port') ? 65535 : undefined
|
||||
const colorDefault = COLOR_DEFAULTS[setting.key]
|
||||
const pickerValue = /^#[0-9a-f]{6}$/i.test(value) ? value : colorDefault
|
||||
const aria = { id, name: setting.key, 'aria-describedby': help ? `${id}-help` : undefined }
|
||||
|
||||
if (props.boolean) {
|
||||
return (
|
||||
<div className="setting-field setting-switch">
|
||||
<div><label htmlFor={id}>{label}</label>{help && <p id={`${id}-help`}>{help}</p>}</div>
|
||||
<input {...aria} type="checkbox" role="switch" checked={value.toLowerCase() === 'true'} onChange={(event) => onChange(String(event.target.checked))} />
|
||||
<input {...aria} type="checkbox" role="switch" aria-checked={value.toLowerCase() === 'true'} checked={value.toLowerCase() === 'true'} onChange={(event) => onChange(String(event.target.checked))} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -52,6 +59,27 @@ export default function SettingField(props: Props) {
|
||||
<label htmlFor={id}>{label}{setting.sensitive && setting.isSet && <small>Saved</small>}</label>
|
||||
{props.optionsUnavailable ? (
|
||||
<select {...aria} disabled value={value}><option value={value}>Save the connection, then reload available options</option></select>
|
||||
) : colorDefault ? (
|
||||
<div className="setting-color-control">
|
||||
<input
|
||||
id={`${id}-picker`}
|
||||
type="color"
|
||||
aria-label={`Choose ${label.toLowerCase()}`}
|
||||
value={pickerValue}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
/>
|
||||
<input
|
||||
{...aria}
|
||||
type="text"
|
||||
value={value}
|
||||
pattern="#[0-9A-Fa-f]{6}"
|
||||
placeholder={colorDefault}
|
||||
autoComplete="off"
|
||||
spellCheck={false}
|
||||
onChange={(event) => onChange(event.target.value)}
|
||||
/>
|
||||
{value ? <button type="button" className="ghost-button" onClick={() => onChange('')}>Use tone default</button> : null}
|
||||
</div>
|
||||
) : selectedOptions ? (
|
||||
<select {...aria} value={value} onChange={(event) => onChange(event.target.value)}>
|
||||
{!value && <option value="">Choose an option</option>}
|
||||
|
||||
@@ -70,6 +70,7 @@ const BOOL_SETTINGS = new Set([
|
||||
])
|
||||
const TEXTAREA_SETTINGS = new Set([
|
||||
'site_banner_message',
|
||||
'site_login_message',
|
||||
'site_changelog',
|
||||
'magent_ssl_certificate_pem',
|
||||
'magent_ssl_private_key_pem',
|
||||
@@ -266,14 +267,21 @@ const SITE_SECTION_GROUPS: Array<{
|
||||
{
|
||||
key: 'site-banner',
|
||||
title: 'Site Banner',
|
||||
description: 'Control the sitewide banner message, tone, and visibility.',
|
||||
keys: ['site_banner_enabled', 'site_banner_tone', 'site_banner_message'],
|
||||
description: 'Control the sitewide banner message, preset tone, surrounding background and border colours, and visibility.',
|
||||
keys: [
|
||||
'site_banner_enabled',
|
||||
'site_banner_tone',
|
||||
'site_banner_background_color',
|
||||
'site_banner_border_color',
|
||||
'site_banner_message',
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'site-login',
|
||||
title: 'Login Page Behaviour',
|
||||
description: 'Control which sign-in and recovery options are shown on the logged-out login page.',
|
||||
keys: [
|
||||
'site_login_message',
|
||||
'site_login_show_jellyfin_login',
|
||||
'site_login_show_local_login',
|
||||
'site_login_show_forgot_password',
|
||||
@@ -517,6 +525,7 @@ const SETTING_LABEL_OVERRIDES: Record<string, string> = {
|
||||
log_level: 'Application log level',
|
||||
log_file: 'Active log file',
|
||||
site_login_show_jellyfin_login: 'Login page: Jellyfin sign-in',
|
||||
site_login_message: 'Logged-out login page message',
|
||||
site_login_show_local_login: 'Login page: local Magent sign-in',
|
||||
site_login_show_forgot_password: 'Login page: forgot password',
|
||||
site_login_show_signup_link: 'Login page: invite signup link',
|
||||
@@ -551,6 +560,9 @@ const labelFromKey = (key: string) =>
|
||||
.replace('site banner enabled', 'Sitewide banner enabled')
|
||||
.replace('site banner message', 'Sitewide banner message')
|
||||
.replace('site banner tone', 'Sitewide banner tone')
|
||||
.replace('site banner background color', 'Banner background colour')
|
||||
.replace('site banner border color', 'Banner border colour')
|
||||
.replace('site login message', 'Logged-out login page message')
|
||||
.replace('site nav show requests', 'Top navigation: New Requests')
|
||||
.replace('site changelog', 'Changelog text')
|
||||
|
||||
@@ -1051,7 +1063,10 @@ export default function SettingsPage({ section }: SettingsPageProps) {
|
||||
site_build_number: 'Build number shown in the account menu (auto-set from releases).',
|
||||
site_banner_enabled: 'Enable a sitewide banner for announcements.',
|
||||
site_banner_message: 'Short banner message for maintenance or updates.',
|
||||
site_banner_tone: 'Visual tone for the banner.',
|
||||
site_banner_tone: 'Preset visual tone used whenever custom colours are blank.',
|
||||
site_banner_background_color: 'Optional six-digit hex colour behind the banner message. Clear it to use the selected tone.',
|
||||
site_banner_border_color: 'Optional six-digit hex colour around the banner. Clear it to use the selected tone.',
|
||||
site_login_message: 'Optional message shown only on the logged-out login page. Leave blank to hide it.',
|
||||
site_login_show_jellyfin_login: 'Show the Jellyfin login button on the login page.',
|
||||
site_login_show_local_login: 'Show the local Magent login button on the login page.',
|
||||
site_login_show_forgot_password: 'Show the forgot-password link on the login page.',
|
||||
@@ -1097,6 +1112,7 @@ export default function SettingsPage({ section }: SettingsPageProps) {
|
||||
radarr_base_url: 'https://radarr.example.com or 10.30.1.81:7878',
|
||||
prowlarr_base_url: 'https://prowlarr.example.com or 10.30.1.81:9696',
|
||||
qbittorrent_base_url: 'https://qb.example.com or 10.30.1.81:8080',
|
||||
site_login_message: 'Sign-in information, an outage notice, or help for users…',
|
||||
}
|
||||
|
||||
const parseActionError = (err: unknown, fallback: string) => {
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
.config-subsection .setting-field p { margin: 0; color: var(--ops-muted); font: 400 12px/1.5 Inter, sans-serif; text-transform: none; }
|
||||
.config-subsection .setting-field input:not([type=checkbox]), .config-subsection .setting-field select, .config-subsection .setting-field textarea { margin: 0; width: 100%; min-width: 0; padding: 10px 12px; min-height: 42px; border: 1px solid var(--ops-line); background: var(--ops-bg-2); color: var(--ops-text); font: 400 13px/1.5 Inter, sans-serif; border-radius: 8px; }
|
||||
.config-subsection .setting-field input:focus-visible, .config-subsection .setting-field select:focus-visible, .config-subsection .setting-field textarea:focus-visible { outline: 2px solid var(--ops-primary-2); outline-offset: 2px; }
|
||||
.config-subsection .setting-color-control { display: grid; grid-template-columns: 52px minmax(140px, 1fr) auto; align-items: center; gap: 8px; }
|
||||
.config-subsection .setting-color-control input[type=color] { width: 52px; min-width: 52px; padding: 4px; cursor: pointer; }
|
||||
.config-subsection .setting-color-control .ghost-button { min-height: 42px; padding: 9px 12px; white-space: nowrap; }
|
||||
.config-subsection .setting-field.field-span-full { grid-column: 1 / -1; }
|
||||
.config-subsection .setting-switch { flex-direction: row; justify-content: space-between; align-items: center; padding: 12px 0; border-bottom: 1px solid var(--ops-line-soft); gap: 24px; }
|
||||
.setting-switch > div { display: grid; gap: 6px; }
|
||||
@@ -92,6 +95,8 @@
|
||||
@media (max-width: 680px) {
|
||||
.admin-form .admin-grid { grid-template-columns: 1fr; }
|
||||
.admin-form .config-subsection { padding: 16px !important; }
|
||||
.config-subsection .setting-color-control { grid-template-columns: 52px minmax(0, 1fr); }
|
||||
.config-subsection .setting-color-control .ghost-button { grid-column: 1 / -1; }
|
||||
.config-directory-link { flex-wrap: wrap; gap: 12px; padding: 14px; }
|
||||
.config-link-copy { flex-basis: calc(100% - 62px); }
|
||||
.config-directory-link .config-connection-badge { margin-left: 46px; }
|
||||
|
||||
Reference in New Issue
Block a user