This commit is contained in:
Linus Rath
2026-03-17 20:53:53 +01:00
12 changed files with 143 additions and 25 deletions
+30 -2
View File
@@ -67,6 +67,17 @@ JMAP_SERVER_URL=https://your-jmap-server.com
# For Docker, mount a persistent volume at this path. # For Docker, mount a persistent volume at this path.
# SETTINGS_DATA_DIR=./data/settings # SETTINGS_DATA_DIR=./data/settings
# =============================================================================
# Server Listen Address
# =============================================================================
# Hostname the server binds to (default: 0.0.0.0)
# Set to "::" for IPv6 or "[::]" for dual-stack support.
# HOSTNAME=0.0.0.0
# Port the server listens on (default: 3000)
# PORT=3000
# ============================================================================= # =============================================================================
# Logging # Logging
# ============================================================================= # =============================================================================
@@ -78,10 +89,27 @@ JMAP_SERVER_URL=https://your-jmap-server.com
# LOG_LEVEL=info # LOG_LEVEL=info
# ============================================================================= # =============================================================================
# Login Page Customization (all optional) # Branding (all optional)
# ============================================================================= # =============================================================================
# Custom logo images for the login page (PNG, SVG, etc.) # Custom favicon for the browser tab.
# Supported formats: SVG (recommended), PNG, ICO.
# Recommended size: 32×32px minimum, 512×512px maximum (or SVG for best scaling).
# Can be an absolute URL or a path relative to the public/ directory.
# Defaults to the Bulwark favicon if not set.
# FAVICON_URL=/branding/my-favicon.svg
# Custom logos for the sidebar (shown in the main app after login).
# Supported formats: SVG (recommended), PNG, WebP.
# Recommended size: min 24×24px, max 128×128px
# Can be absolute URLs or paths relative to the public/ directory.
# If not set, no logo is shown in the sidebar.
# APP_LOGO_LIGHT_URL=/branding/my-logo-color.svg
# APP_LOGO_DARK_URL=/branding/my-logo-white.svg
# Custom logo images for the login page.
# Supported formats: SVG (recommended), PNG, WebP.
# Recommended size: min 32×32px, max 512×512px
# Can be absolute URLs or paths relative to the public/ directory. # Can be absolute URLs or paths relative to the public/ directory.
# Light mode logo (shown on light backgrounds), defaults to Bulwark logo. # Light mode logo (shown on light backgrounds), defaults to Bulwark logo.
LOGIN_LOGO_LIGHT_URL=/branding/Bulwark_Logo_Color.svg LOGIN_LOGO_LIGHT_URL=/branding/Bulwark_Logo_Color.svg
+1 -1
View File
@@ -13,7 +13,7 @@ LABEL org.opencontainers.image.description="Modern webmail client built with Nex
LABEL org.opencontainers.image.source="https://github.com/bulwarkmail/webmail" LABEL org.opencontainers.image.source="https://github.com/bulwarkmail/webmail"
LABEL org.opencontainers.image.url="https://github.com/bulwarkmail/webmail" LABEL org.opencontainers.image.url="https://github.com/bulwarkmail/webmail"
LABEL org.opencontainers.image.licenses="AGPL-3.0-only" LABEL org.opencontainers.image.licenses="AGPL-3.0-only"
LABEL org.opencontainers.image.vendor="root.cloud" LABEL org.opencontainers.image.vendor="rbm.systems"
WORKDIR /app WORKDIR /app
ENV NODE_ENV=production ENV NODE_ENV=production
+10
View File
@@ -243,6 +243,16 @@ APP_NAME=My Webmail
All variables are **runtime** — Docker deployments can be configured without rebuilding. All variables are **runtime** — Docker deployments can be configured without rebuilding.
<details>
<summary>Server Listen Address</summary>
```env
HOSTNAME=0.0.0.0 # Default; use "::" for IPv6
PORT=3000 # Default listen port
```
</details>
<details> <details>
<summary>OAuth2/OIDC (SSO)</summary> <summary>OAuth2/OIDC (SSO)</summary>
+8 -6
View File
@@ -41,11 +41,13 @@ import { isFilePreviewable } from "@/lib/file-preview";
import { Search, Filter, ChevronDown, X, Paperclip, Star, Mail, MailOpen, RotateCcw, PenSquare, PenLine, CheckSquare, Square } from "lucide-react"; import { Search, Filter, ChevronDown, X, Paperclip, Star, Mail, MailOpen, RotateCcw, PenSquare, PenLine, CheckSquare, Square } from "lucide-react";
import { ResizeHandle } from "@/components/layout/resize-handle"; import { ResizeHandle } from "@/components/layout/resize-handle";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { useConfig } from "@/hooks/use-config";
export default function Home() { export default function Home() {
const router = useRouter(); const router = useRouter();
const t = useTranslations(); const t = useTranslations();
const tCommon = useTranslations('common'); const tCommon = useTranslations('common');
const { appName } = useConfig();
const [showComposer, setShowComposer] = useState(false); const [showComposer, setShowComposer] = useState(false);
const [composerMode, setComposerMode] = useState<'compose' | 'reply' | 'replyAll' | 'forward'>('compose'); const [composerMode, setComposerMode] = useState<'compose' | 'reply' | 'replyAll' | 'forward'>('compose');
const [composerDraftText, setComposerDraftText] = useState(""); const [composerDraftText, setComposerDraftText] = useState("");
@@ -224,7 +226,7 @@ export default function Home() {
// Update page title based on context // Update page title based on context
useEffect(() => { useEffect(() => {
let title = tCommon('app_title'); let title = appName;
if (showComposer) { if (showComposer) {
// Composing email // Composing email
@@ -234,11 +236,11 @@ export default function Home() {
replyAll: t('email_composer.reply_all'), replyAll: t('email_composer.reply_all'),
forward: t('email_composer.forward'), forward: t('email_composer.forward'),
}[composerMode] || t('email_composer.new_message'); }[composerMode] || t('email_composer.new_message');
title = `${modeText} - ${tCommon('app_title')}`; title = `${modeText} - ${appName}`;
} else if (selectedEmail) { } else if (selectedEmail) {
// Reading email // Reading email
const subject = selectedEmail.subject || t('email_viewer.no_subject'); const subject = selectedEmail.subject || t('email_viewer.no_subject');
title = `${subject} - ${tCommon('app_title')}`; title = `${subject} - ${appName}`;
} else if (selectedMailbox && mailboxes.length > 0) { } else if (selectedMailbox && mailboxes.length > 0) {
// Mailbox view // Mailbox view
const mailbox = mailboxes.find(mb => mb.id === selectedMailbox); const mailbox = mailboxes.find(mb => mb.id === selectedMailbox);
@@ -246,13 +248,13 @@ export default function Home() {
const mailboxName = mailbox.name; const mailboxName = mailbox.name;
const unreadCount = mailbox.unreadEmails || 0; const unreadCount = mailbox.unreadEmails || 0;
title = unreadCount > 0 title = unreadCount > 0
? `${mailboxName} (${unreadCount}) - ${tCommon('app_title')}` ? `${mailboxName} (${unreadCount}) - ${appName}`
: `${mailboxName} - ${tCommon('app_title')}`; : `${mailboxName} - ${appName}`;
} }
} }
document.title = title; document.title = title;
}, [showComposer, composerMode, selectedEmail, selectedMailbox, mailboxes, t, tCommon]); }, [showComposer, composerMode, selectedEmail, selectedMailbox, mailboxes, t, appName]);
// Check auth on mount // Check auth on mount
useEffect(() => { useEffect(() => {
+3
View File
@@ -26,6 +26,9 @@ export async function GET() {
settingsSyncEnabled: process.env.SETTINGS_SYNC_ENABLED === 'true' && !!process.env.SESSION_SECRET, settingsSyncEnabled: process.env.SETTINGS_SYNC_ENABLED === 'true' && !!process.env.SESSION_SECRET,
stalwartFeaturesEnabled: process.env.STALWART_FEATURES !== 'false', stalwartFeaturesEnabled: process.env.STALWART_FEATURES !== 'false',
devMode: process.env.DEV_MOCK_JMAP === 'true', devMode: process.env.DEV_MOCK_JMAP === 'true',
faviconUrl: process.env.FAVICON_URL || '/branding/Bulwark_Favicon.svg',
appLogoLightUrl: process.env.APP_LOGO_LIGHT_URL || '',
appLogoDarkUrl: process.env.APP_LOGO_DARK_URL || '',
loginLogoLightUrl: process.env.LOGIN_LOGO_LIGHT_URL || '/branding/Bulwark_Logo_Color.svg', loginLogoLightUrl: process.env.LOGIN_LOGO_LIGHT_URL || '/branding/Bulwark_Logo_Color.svg',
loginLogoDarkUrl: process.env.LOGIN_LOGO_DARK_URL || '/branding/Bulwark_Logo_White.svg', loginLogoDarkUrl: process.env.LOGIN_LOGO_DARK_URL || '/branding/Bulwark_Logo_White.svg',
loginCompanyName: process.env.LOGIN_COMPANY_NAME || '', loginCompanyName: process.env.LOGIN_COMPANY_NAME || '',
+7 -2
View File
@@ -14,10 +14,15 @@ const geistMono = Geist_Mono({
subsets: ["latin"], subsets: ["latin"],
}); });
export const metadata: Metadata = { export async function generateMetadata(): Promise<Metadata> {
title: "Bulwark Webmail", const faviconUrl = process.env.FAVICON_URL;
return {
title: process.env.APP_NAME || process.env.NEXT_PUBLIC_APP_NAME || "Webmail",
description: "Minimalist webmail client using JMAP protocol", description: "Minimalist webmail client using JMAP protocol",
...(faviconUrl ? { icons: { icon: faviconUrl } } : {}),
}; };
}
export default async function RootLayout({ export default async function RootLayout({
children, children,
+15
View File
@@ -37,6 +37,8 @@ import { useSettingsStore, KEYWORD_PALETTE, KeywordDefinition } from "@/stores/s
import { useEmailStore } from "@/stores/email-store"; import { useEmailStore } from "@/stores/email-store";
import { toast } from "@/stores/toast-store"; import { toast } from "@/stores/toast-store";
import { debug } from "@/lib/debug"; import { debug } from "@/lib/debug";
import { useConfig } from "@/hooks/use-config";
import { useThemeStore } from "@/stores/theme-store";
interface SidebarProps { interface SidebarProps {
mailboxes: Mailbox[]; mailboxes: Mailbox[];
@@ -361,6 +363,8 @@ export function Sidebar({
}: SidebarProps) { }: SidebarProps) {
const { sidebarCollapsed: isCollapsed, toggleSidebarCollapsed } = useUIStore(); const { sidebarCollapsed: isCollapsed, toggleSidebarCollapsed } = useUIStore();
const { primaryIdentity } = useAuthStore(); const { primaryIdentity } = useAuthStore();
const { appLogoLightUrl, appLogoDarkUrl } = useConfig();
const resolvedTheme = useThemeStore((s) => s.resolvedTheme);
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set()); const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set());
const [tagsExpanded, setTagsExpanded] = useState(() => { const [tagsExpanded, setTagsExpanded] = useState(() => {
try { try {
@@ -460,6 +464,17 @@ export function Sidebar({
<X className="w-5 h-5" /> <X className="w-5 h-5" />
</Button> </Button>
{(() => {
const logoUrl = resolvedTheme === 'dark' ? (appLogoDarkUrl || appLogoLightUrl) : (appLogoLightUrl || appLogoDarkUrl);
return logoUrl ? (
<img
src={logoUrl}
alt=""
className={cn("object-contain flex-shrink-0", isCollapsed ? "w-6 h-6" : "w-6 h-6")}
/>
) : null;
})()}
<Button <Button
variant="ghost" variant="ghost"
size="icon" size="icon"
+3
View File
@@ -3,6 +3,9 @@ services:
image: ghcr.io/bulwarkmail/webmail:latest image: ghcr.io/bulwarkmail/webmail:latest
ports: ports:
- "3000:3000" - "3000:3000"
environment:
- HOSTNAME=0.0.0.0 # Use "::" for IPv6
- PORT=3000
env_file: env_file:
- .env.local - .env.local
healthcheck: healthcheck:
+12
View File
@@ -13,6 +13,9 @@ interface ConfigData {
settingsSyncEnabled: boolean; settingsSyncEnabled: boolean;
stalwartFeaturesEnabled: boolean; stalwartFeaturesEnabled: boolean;
devMode: boolean; devMode: boolean;
faviconUrl: string;
appLogoLightUrl: string;
appLogoDarkUrl: string;
loginLogoLightUrl: string; loginLogoLightUrl: string;
loginLogoDarkUrl: string; loginLogoDarkUrl: string;
loginCompanyName: string; loginCompanyName: string;
@@ -79,6 +82,9 @@ export function useConfig(): AppConfig {
settingsSyncEnabled: configCache?.settingsSyncEnabled || false, settingsSyncEnabled: configCache?.settingsSyncEnabled || false,
stalwartFeaturesEnabled: configCache?.stalwartFeaturesEnabled ?? true, stalwartFeaturesEnabled: configCache?.stalwartFeaturesEnabled ?? true,
devMode: configCache?.devMode || false, devMode: configCache?.devMode || false,
faviconUrl: configCache?.faviconUrl || '/branding/Bulwark_Favicon.svg',
appLogoLightUrl: configCache?.appLogoLightUrl || '',
appLogoDarkUrl: configCache?.appLogoDarkUrl || '',
loginLogoLightUrl: configCache?.loginLogoLightUrl || '/branding/Bulwark_Logo_Color.svg', loginLogoLightUrl: configCache?.loginLogoLightUrl || '/branding/Bulwark_Logo_Color.svg',
loginLogoDarkUrl: configCache?.loginLogoDarkUrl || '/branding/Bulwark_Logo_White.svg', loginLogoDarkUrl: configCache?.loginLogoDarkUrl || '/branding/Bulwark_Logo_White.svg',
loginCompanyName: configCache?.loginCompanyName || '', loginCompanyName: configCache?.loginCompanyName || '',
@@ -103,6 +109,9 @@ export function useConfig(): AppConfig {
settingsSyncEnabled: configCache.settingsSyncEnabled, settingsSyncEnabled: configCache.settingsSyncEnabled,
stalwartFeaturesEnabled: configCache.stalwartFeaturesEnabled, stalwartFeaturesEnabled: configCache.stalwartFeaturesEnabled,
devMode: configCache.devMode, devMode: configCache.devMode,
faviconUrl: configCache.faviconUrl,
appLogoLightUrl: configCache.appLogoLightUrl,
appLogoDarkUrl: configCache.appLogoDarkUrl,
loginLogoLightUrl: configCache.loginLogoLightUrl, loginLogoLightUrl: configCache.loginLogoLightUrl,
loginLogoDarkUrl: configCache.loginLogoDarkUrl, loginLogoDarkUrl: configCache.loginLogoDarkUrl,
loginCompanyName: configCache.loginCompanyName, loginCompanyName: configCache.loginCompanyName,
@@ -128,6 +137,9 @@ export function useConfig(): AppConfig {
settingsSyncEnabled: data.settingsSyncEnabled, settingsSyncEnabled: data.settingsSyncEnabled,
stalwartFeaturesEnabled: data.stalwartFeaturesEnabled, stalwartFeaturesEnabled: data.stalwartFeaturesEnabled,
devMode: data.devMode, devMode: data.devMode,
faviconUrl: data.faviconUrl,
appLogoLightUrl: data.appLogoLightUrl,
appLogoDarkUrl: data.appLogoDarkUrl,
loginLogoLightUrl: data.loginLogoLightUrl, loginLogoLightUrl: data.loginLogoLightUrl,
loginLogoDarkUrl: data.loginLogoDarkUrl, loginLogoDarkUrl: data.loginLogoDarkUrl,
loginCompanyName: data.loginCompanyName, loginCompanyName: data.loginCompanyName,
+18
View File
@@ -27,6 +27,9 @@ describe('config API route', () => {
delete process.env.SETTINGS_SYNC_ENABLED; delete process.env.SETTINGS_SYNC_ENABLED;
delete process.env.STALWART_FEATURES; delete process.env.STALWART_FEATURES;
delete process.env.DEV_MOCK_JMAP; delete process.env.DEV_MOCK_JMAP;
delete process.env.FAVICON_URL;
delete process.env.APP_LOGO_LIGHT_URL;
delete process.env.APP_LOGO_DARK_URL;
delete process.env.LOGIN_COMPANY_NAME; delete process.env.LOGIN_COMPANY_NAME;
delete process.env.LOGIN_IMPRINT_URL; delete process.env.LOGIN_IMPRINT_URL;
delete process.env.LOGIN_PRIVACY_POLICY_URL; delete process.env.LOGIN_PRIVACY_POLICY_URL;
@@ -60,6 +63,9 @@ describe('config API route', () => {
expect(config.loginImprintUrl).toBe(''); expect(config.loginImprintUrl).toBe('');
expect(config.loginPrivacyPolicyUrl).toBe(''); expect(config.loginPrivacyPolicyUrl).toBe('');
expect(config.loginWebsiteUrl).toBe(''); expect(config.loginWebsiteUrl).toBe('');
expect(config.faviconUrl).toBe('/branding/Bulwark_Favicon.svg');
expect(config.appLogoLightUrl).toBe('');
expect(config.appLogoDarkUrl).toBe('');
}); });
it('should use runtime env vars over defaults', async () => { it('should use runtime env vars over defaults', async () => {
@@ -142,4 +148,16 @@ describe('config API route', () => {
expect(config.stalwartFeaturesEnabled).toBe(false); expect(config.stalwartFeaturesEnabled).toBe(false);
}); });
it('should return custom favicon and app logo URLs', async () => {
process.env.FAVICON_URL = '/branding/custom-favicon.svg';
process.env.APP_LOGO_LIGHT_URL = '/branding/my-logo.svg';
process.env.APP_LOGO_DARK_URL = '/branding/my-logo-white.svg';
const config = await getConfig();
expect(config.faviconUrl).toBe('/branding/custom-favicon.svg');
expect(config.appLogoLightUrl).toBe('/branding/my-logo.svg');
expect(config.appLogoDarkUrl).toBe('/branding/my-logo-white.svg');
});
}); });
+1 -1
View File
@@ -2,7 +2,7 @@
"name": "bulwark-webmail", "name": "bulwark-webmail",
"version": "1.3.0", "version": "1.3.0",
"description": "Bulwark Webmail — a modern webmail client built for Stalwart Mail Server", "description": "Bulwark Webmail — a modern webmail client built for Stalwart Mail Server",
"author": "Matthieu MALVACHE <matthieu@root.cloud>", "author": "Bulwark Webmail <bulwark@rbm.systems>",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"repository": { "repository": {
"type": "git", "type": "git",
+33 -11
View File
@@ -67,6 +67,9 @@ CFG_LOG_LEVEL="info"
CFG_LOGIN_COMPANY_NAME="" CFG_LOGIN_COMPANY_NAME=""
CFG_LOGIN_LOGO_LIGHT_URL="" CFG_LOGIN_LOGO_LIGHT_URL=""
CFG_LOGIN_LOGO_DARK_URL="" CFG_LOGIN_LOGO_DARK_URL=""
CFG_FAVICON_URL=""
CFG_APP_LOGO_LIGHT_URL=""
CFG_APP_LOGO_DARK_URL=""
CFG_LOGIN_IMPRINT_URL="" CFG_LOGIN_IMPRINT_URL=""
CFG_LOGIN_PRIVACY_POLICY_URL="" CFG_LOGIN_PRIVACY_POLICY_URL=""
CFG_LOGIN_WEBSITE_URL="" CFG_LOGIN_WEBSITE_URL=""
@@ -761,20 +764,30 @@ screen_login_customization() {
CURRENT_STEP=5 CURRENT_STEP=5
draw_header draw_header
section_header 5 "Login Page Branding" \ section_header 5 "Branding" \
"Add your company name and legal links to the login page." "Customize logos, favicon, and login page for your domain identity."
echo -e " All fields are ${BOLD}optional${RESET}. Press Enter to skip any field." echo -e " All fields are ${BOLD}optional${RESET}. Press Enter to skip any field."
echo "" echo ""
echo -e " ${DIM}Custom favicon for the browser tab (SVG recommended, 32×32 to 512×512px)${RESET}"
echo -e " ${DIM}Leave blank to use the default Bulwark favicon.${RESET}"
prompt_value "Favicon URL" "$CFG_FAVICON_URL" "CFG_FAVICON_URL"
echo ""
echo -e " ${DIM}App logo shown in the sidebar (SVG recommended, 24×24 to 128×128px)${RESET}"
echo -e " ${DIM}Leave blank for no sidebar logo.${RESET}"
prompt_value "App logo URL (light mode)" "$CFG_APP_LOGO_LIGHT_URL" "CFG_APP_LOGO_LIGHT_URL"
echo ""
prompt_value "App logo URL (dark mode)" "$CFG_APP_LOGO_DARK_URL" "CFG_APP_LOGO_DARK_URL"
echo ""
echo -e " ${DIM}Shown on the login page footer. Example: Acme Corp${RESET}" echo -e " ${DIM}Shown on the login page footer. Example: Acme Corp${RESET}"
prompt_value "Company / organization name" "$CFG_LOGIN_COMPANY_NAME" "CFG_LOGIN_COMPANY_NAME" prompt_value "Company / organization name" "$CFG_LOGIN_COMPANY_NAME" "CFG_LOGIN_COMPANY_NAME"
echo "" echo ""
echo -e " ${DIM}Custom logo URLs for the login page (PNG, SVG, etc.)${RESET}" echo -e " ${DIM}Custom logo URLs for the login page (SVG recommended, 32×32 to 512×512px)${RESET}"
echo -e " ${DIM}Leave blank to use the default Bulwark logo.${RESET}" echo -e " ${DIM}Leave blank to use the default Bulwark logo.${RESET}"
prompt_value "Logo URL (light mode)" "$CFG_LOGIN_LOGO_LIGHT_URL" "CFG_LOGIN_LOGO_LIGHT_URL" prompt_value "Login logo URL (light mode)" "$CFG_LOGIN_LOGO_LIGHT_URL" "CFG_LOGIN_LOGO_LIGHT_URL"
echo "" echo ""
prompt_value "Logo URL (dark mode)" "$CFG_LOGIN_LOGO_DARK_URL" "CFG_LOGIN_LOGO_DARK_URL" prompt_value "Login logo URL (dark mode)" "$CFG_LOGIN_LOGO_DARK_URL" "CFG_LOGIN_LOGO_DARK_URL"
echo "" echo ""
prompt_value "Website URL" "$CFG_LOGIN_WEBSITE_URL" "CFG_LOGIN_WEBSITE_URL" prompt_value "Website URL" "$CFG_LOGIN_WEBSITE_URL" "CFG_LOGIN_WEBSITE_URL"
echo "" echo ""
@@ -782,9 +795,9 @@ screen_login_customization() {
echo "" echo ""
prompt_value "Privacy policy URL" "$CFG_LOGIN_PRIVACY_POLICY_URL" "CFG_LOGIN_PRIVACY_POLICY_URL" prompt_value "Privacy policy URL" "$CFG_LOGIN_PRIVACY_POLICY_URL" "CFG_LOGIN_PRIVACY_POLICY_URL"
if [[ -z "$CFG_LOGIN_COMPANY_NAME" && -z "$CFG_LOGIN_LOGO_LIGHT_URL" && -z "$CFG_LOGIN_LOGO_DARK_URL" && -z "$CFG_LOGIN_WEBSITE_URL" && -z "$CFG_LOGIN_IMPRINT_URL" && -z "$CFG_LOGIN_PRIVACY_POLICY_URL" ]]; then if [[ -z "$CFG_LOGIN_COMPANY_NAME" && -z "$CFG_LOGIN_LOGO_LIGHT_URL" && -z "$CFG_LOGIN_LOGO_DARK_URL" && -z "$CFG_FAVICON_URL" && -z "$CFG_APP_LOGO_LIGHT_URL" && -z "$CFG_APP_LOGO_DARK_URL" && -z "$CFG_LOGIN_WEBSITE_URL" && -z "$CFG_LOGIN_IMPRINT_URL" && -z "$CFG_LOGIN_PRIVACY_POLICY_URL" ]]; then
echo "" echo ""
note "No branding configured. The login page will show defaults." note "No branding configured. The app will use defaults."
fi fi
draw_footer draw_footer
@@ -892,13 +905,19 @@ screen_summary() {
# Login page # Login page
echo -e " ${CYAN}${BOLD}BRANDING${RESET}" echo -e " ${CYAN}${BOLD}BRANDING${RESET}"
if [[ -n "$CFG_LOGIN_COMPANY_NAME" || -n "$CFG_LOGIN_LOGO_LIGHT_URL" || -n "$CFG_LOGIN_LOGO_DARK_URL" || -n "$CFG_LOGIN_WEBSITE_URL" || -n "$CFG_LOGIN_IMPRINT_URL" || -n "$CFG_LOGIN_PRIVACY_POLICY_URL" ]]; then if [[ -n "$CFG_LOGIN_COMPANY_NAME" || -n "$CFG_LOGIN_LOGO_LIGHT_URL" || -n "$CFG_LOGIN_LOGO_DARK_URL" || -n "$CFG_FAVICON_URL" || -n "$CFG_APP_LOGO_LIGHT_URL" || -n "$CFG_APP_LOGO_DARK_URL" || -n "$CFG_LOGIN_WEBSITE_URL" || -n "$CFG_LOGIN_IMPRINT_URL" || -n "$CFG_LOGIN_PRIVACY_POLICY_URL" ]]; then
[[ -n "$CFG_FAVICON_URL" ]] && \
echo -e " Favicon URL ........... ${BOLD}${CFG_FAVICON_URL}${RESET}"
[[ -n "$CFG_APP_LOGO_LIGHT_URL" ]] && \
echo -e " App Logo (light) ...... ${BOLD}${CFG_APP_LOGO_LIGHT_URL}${RESET}"
[[ -n "$CFG_APP_LOGO_DARK_URL" ]] && \
echo -e " App Logo (dark) ....... ${BOLD}${CFG_APP_LOGO_DARK_URL}${RESET}"
[[ -n "$CFG_LOGIN_COMPANY_NAME" ]] && \ [[ -n "$CFG_LOGIN_COMPANY_NAME" ]] && \
echo -e " Company Name .......... ${BOLD}${CFG_LOGIN_COMPANY_NAME}${RESET}" echo -e " Company Name .......... ${BOLD}${CFG_LOGIN_COMPANY_NAME}${RESET}"
[[ -n "$CFG_LOGIN_LOGO_LIGHT_URL" ]] && \ [[ -n "$CFG_LOGIN_LOGO_LIGHT_URL" ]] && \
echo -e " Logo (light mode) ..... ${BOLD}${CFG_LOGIN_LOGO_LIGHT_URL}${RESET}" echo -e " Login Logo (light) .... ${BOLD}${CFG_LOGIN_LOGO_LIGHT_URL}${RESET}"
[[ -n "$CFG_LOGIN_LOGO_DARK_URL" ]] && \ [[ -n "$CFG_LOGIN_LOGO_DARK_URL" ]] && \
echo -e " Logo (dark mode) ...... ${BOLD}${CFG_LOGIN_LOGO_DARK_URL}${RESET}" echo -e " Login Logo (dark) ..... ${BOLD}${CFG_LOGIN_LOGO_DARK_URL}${RESET}"
[[ -n "$CFG_LOGIN_WEBSITE_URL" ]] && \ [[ -n "$CFG_LOGIN_WEBSITE_URL" ]] && \
echo -e " Website URL ........... ${BOLD}${CFG_LOGIN_WEBSITE_URL}${RESET}" echo -e " Website URL ........... ${BOLD}${CFG_LOGIN_WEBSITE_URL}${RESET}"
[[ -n "$CFG_LOGIN_IMPRINT_URL" ]] && \ [[ -n "$CFG_LOGIN_IMPRINT_URL" ]] && \
@@ -1003,9 +1022,12 @@ ENVEOF
LOG_FORMAT=${CFG_LOG_FORMAT} LOG_FORMAT=${CFG_LOG_FORMAT}
LOG_LEVEL=${CFG_LOG_LEVEL} LOG_LEVEL=${CFG_LOG_LEVEL}
# -- Login Page Customization -------------------------------------------------- # -- Branding ------------------------------------------------------------------
ENVEOF ENVEOF
[[ -n "$CFG_FAVICON_URL" ]] && echo "FAVICON_URL=${CFG_FAVICON_URL}" >> "$ENV_FILE"
[[ -n "$CFG_APP_LOGO_LIGHT_URL" ]] && echo "APP_LOGO_LIGHT_URL=${CFG_APP_LOGO_LIGHT_URL}" >> "$ENV_FILE"
[[ -n "$CFG_APP_LOGO_DARK_URL" ]] && echo "APP_LOGO_DARK_URL=${CFG_APP_LOGO_DARK_URL}" >> "$ENV_FILE"
[[ -n "$CFG_LOGIN_COMPANY_NAME" ]] && echo "LOGIN_COMPANY_NAME=${CFG_LOGIN_COMPANY_NAME}" >> "$ENV_FILE" [[ -n "$CFG_LOGIN_COMPANY_NAME" ]] && echo "LOGIN_COMPANY_NAME=${CFG_LOGIN_COMPANY_NAME}" >> "$ENV_FILE"
[[ -n "$CFG_LOGIN_LOGO_LIGHT_URL" ]] && echo "LOGIN_LOGO_LIGHT_URL=${CFG_LOGIN_LOGO_LIGHT_URL}" >> "$ENV_FILE" [[ -n "$CFG_LOGIN_LOGO_LIGHT_URL" ]] && echo "LOGIN_LOGO_LIGHT_URL=${CFG_LOGIN_LOGO_LIGHT_URL}" >> "$ENV_FILE"
[[ -n "$CFG_LOGIN_LOGO_DARK_URL" ]] && echo "LOGIN_LOGO_DARK_URL=${CFG_LOGIN_LOGO_DARK_URL}" >> "$ENV_FILE" [[ -n "$CFG_LOGIN_LOGO_DARK_URL" ]] && echo "LOGIN_LOGO_DARK_URL=${CFG_LOGIN_LOGO_DARK_URL}" >> "$ENV_FILE"