diff --git a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java index 4b5a202c0..6a6ee8453 100644 --- a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java +++ b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java @@ -505,10 +505,19 @@ public class ApplicationProperties { public static class Ui { private String appNameNavbar; private List languages; + private String logoStyle = "classic"; // Options: "classic" (default) or "modern" public String getAppNameNavbar() { return appNameNavbar != null && !appNameNavbar.trim().isEmpty() ? appNameNavbar : null; } + + public String getLogoStyle() { + // Validate and return either "modern" or "classic" + if ("modern".equalsIgnoreCase(logoStyle)) { + return "modern"; + } + return "classic"; // default + } } @Data diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java index 42ee1c9a7..6bb67d5b8 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/misc/ConfigController.java @@ -61,6 +61,7 @@ public class ConfigController { // Extract values from ApplicationProperties configData.put("appNameNavbar", applicationProperties.getUi().getAppNameNavbar()); configData.put("languages", applicationProperties.getUi().getLanguages()); + configData.put("logoStyle", applicationProperties.getUi().getLogoStyle()); // Security settings // enableLogin requires both the config flag AND proprietary features to be loaded diff --git a/app/core/src/main/resources/settings.yml.template b/app/core/src/main/resources/settings.yml.template index 5f8ca51be..139260872 100644 --- a/app/core/src/main/resources/settings.yml.template +++ b/app/core/src/main/resources/settings.yml.template @@ -176,6 +176,7 @@ system: ui: appNameNavbar: '' # name displayed on the navigation bar + logoStyle: classic # Options: 'classic' (default - classic S icon) or 'modern' (minimalist logo) languages: [] # If empty, all languages are enabled. To display only German and Polish ["de_DE", "pl_PL"]. British English is always enabled. endpoints: diff --git a/frontend/public/branding/old/favicon.ico b/frontend/public/branding/old/favicon.ico new file mode 100644 index 000000000..8ad57cac7 Binary files /dev/null and b/frontend/public/branding/old/favicon.ico differ diff --git a/frontend/public/branding/old/favicon.png b/frontend/public/branding/old/favicon.png new file mode 100644 index 000000000..5edc6eae2 Binary files /dev/null and b/frontend/public/branding/old/favicon.png differ diff --git a/frontend/public/branding/old/favicon.svg b/frontend/public/branding/old/favicon.svg new file mode 100644 index 000000000..0fef4393a --- /dev/null +++ b/frontend/public/branding/old/favicon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/core/components/shared/LandingPage.tsx b/frontend/src/core/components/shared/LandingPage.tsx index f25aaedfc..9ee11cbd2 100644 --- a/frontend/src/core/components/shared/LandingPage.tsx +++ b/frontend/src/core/components/shared/LandingPage.tsx @@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next'; import { useFileHandler } from '@app/hooks/useFileHandler'; import { useFilesModalContext } from '@app/contexts/FilesModalContext'; import { BASE_PATH } from '@app/constants/app'; +import { useLogoPath } from '@app/hooks/useLogoPath'; const LandingPage = () => { const { addFiles } = useFileHandler(); @@ -14,6 +15,7 @@ const LandingPage = () => { const { t } = useTranslation(); const { openFilesModal } = useFilesModalContext(); const [isUploadHover, setIsUploadHover] = React.useState(false); + const logoPath = useLogoPath(); const handleFileDrop = async (files: File[]) => { await addFiles(files); @@ -72,7 +74,7 @@ const LandingPage = () => { }} > Stirling PDF Logo { + const logoStyle = config?.logoStyle || 'classic'; + + if (logoStyle === 'classic') { + // Classic logo (old favicon) - same for both light and dark modes + return `${BASE_PATH}/branding/old/favicon.svg`; + } + + // Modern logo - different for light and dark modes + const themeSuffix = colorScheme === 'dark' ? 'Dark' : 'Light'; + return `${BASE_PATH}/branding/StirlingPDFLogoNoText${themeSuffix}.svg`; + }, [config?.logoStyle, colorScheme]); +} diff --git a/frontend/src/core/pages/HomePage.tsx b/frontend/src/core/pages/HomePage.tsx index 7c4d3a6c2..5b04c1c7a 100644 --- a/frontend/src/core/pages/HomePage.tsx +++ b/frontend/src/core/pages/HomePage.tsx @@ -8,6 +8,7 @@ import { BASE_PATH } from "@app/constants/app"; import { useBaseUrl } from "@app/hooks/useBaseUrl"; import { useMediaQuery } from "@mantine/hooks"; import { useAppConfig } from "@app/contexts/AppConfigContext"; +import { useLogoPath } from "@app/hooks/useLogoPath"; import AppsIcon from '@mui/icons-material/AppsRounded'; import ToolPanel from "@app/components/tools/ToolPanel"; @@ -60,9 +61,7 @@ export default function HomePage() { }, [config]); const brandAltText = t("home.mobile.brandAlt", "Stirling PDF logo"); - const brandIconSrc = `${BASE_PATH}/branding/StirlingPDFLogoNoText${ - colorScheme === "dark" ? "Dark" : "Light" - }.svg`; + const brandIconSrc = useLogoPath(); const brandTextSrc = `${BASE_PATH}/branding/StirlingPDFLogo${ colorScheme === "dark" ? "White" : "Black" }Text.svg`; diff --git a/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx b/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx index 4777b90c3..0e00415bf 100644 --- a/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx +++ b/frontend/src/proprietary/components/shared/config/configSections/AdminGeneralSection.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react'; import { useTranslation } from 'react-i18next'; -import { TextInput, Switch, Button, Stack, Paper, Text, Loader, Group, MultiSelect, Badge } from '@mantine/core'; +import { TextInput, Switch, Button, Stack, Paper, Text, Loader, Group, MultiSelect, Badge, SegmentedControl } from '@mantine/core'; import { alert } from '@app/components/toast'; import RestartConfirmationModal from '@app/components/shared/config/RestartConfirmationModal'; import { useRestartServer } from '@app/components/shared/config/useRestartServer'; @@ -14,6 +14,7 @@ interface GeneralSettingsData { ui: { appNameNavbar?: string; languages?: string[]; + logoStyle?: 'modern' | 'classic'; }; system: { defaultLocale?: string; @@ -113,6 +114,7 @@ export default function AdminGeneralSection() { // UI settings 'ui.appNameNavbar': settings.ui?.appNameNavbar, 'ui.languages': settings.ui?.languages, + 'ui.logoStyle': settings.ui?.logoStyle, // System settings 'system.defaultLocale': settings.system?.defaultLocale, 'system.showUpdate': settings.system?.showUpdate, @@ -209,6 +211,51 @@ export default function AdminGeneralSection() { /> +
+ + + {t('admin.settings.general.logoStyle.label', 'Logo Style')} + + + + + {t('admin.settings.general.logoStyle.description', 'Choose between the modern minimalist logo or the classic S icon')} + + setSettings({ ...settings, ui: { ...settings.ui, logoStyle: value as 'modern' | 'classic' } })} + data={[ + { + value: 'classic', + label: ( +
+ Classic logo + {t('admin.settings.general.logoStyle.classic', 'Classic')} +
+ ) + }, + { + value: 'modern', + label: ( +
+ Modern logo + {t('admin.settings.general.logoStyle.modern', 'Modern')} +
+ ) + }, + ]} + disabled={!loginEnabled} + /> +
+
- Logo Stirling PDF

{title}