mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2026-03-04 02:20:19 +01:00
remove unused configs, add others
This commit is contained in:
@@ -9,6 +9,7 @@ import { SidebarProvider } from "./contexts/SidebarContext";
|
||||
import { PreferencesProvider } from "./contexts/PreferencesContext";
|
||||
import ErrorBoundary from "./components/shared/ErrorBoundary";
|
||||
import HomePage from "./pages/HomePage";
|
||||
import AppConfigLoader from "./components/shared/AppConfigLoader";
|
||||
|
||||
// Import global styles
|
||||
import "./styles/tailwind.css";
|
||||
@@ -43,6 +44,7 @@ export default function App() {
|
||||
<PreferencesProvider>
|
||||
<RainbowThemeProvider>
|
||||
<ErrorBoundary>
|
||||
<AppConfigLoader />
|
||||
<FileContextProvider enableUrlSync={true} enablePersistence={true}>
|
||||
<NavigationProvider>
|
||||
<FilesModalProvider>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useFileHandler } from '../../hooks/useFileHandler';
|
||||
import { useFileState } from '../../contexts/FileContext';
|
||||
import { useNavigationState, useNavigationActions } from '../../contexts/NavigationContext';
|
||||
import { useViewer } from '../../contexts/ViewerContext';
|
||||
import { useAppConfig } from '../../hooks/useAppConfig';
|
||||
import './Workbench.css';
|
||||
|
||||
import TopControls from '../shared/TopControls';
|
||||
@@ -20,6 +21,7 @@ import DismissAllErrorsButton from '../shared/DismissAllErrorsButton';
|
||||
// No props needed - component uses contexts directly
|
||||
export default function Workbench() {
|
||||
const { isRainbowMode } = useRainbowThemeContext();
|
||||
const { config } = useAppConfig();
|
||||
|
||||
// Use context-based hooks to eliminate all prop drilling
|
||||
const { selectors } = useFileState();
|
||||
@@ -180,7 +182,14 @@ export default function Workbench() {
|
||||
{renderMainContent()}
|
||||
</Box>
|
||||
|
||||
<Footer analyticsEnabled />
|
||||
<Footer
|
||||
analyticsEnabled={config?.enableAnalytics}
|
||||
termsAndConditions={config?.termsAndConditions}
|
||||
privacyPolicy={config?.privacyPolicy}
|
||||
cookiePolicy={config?.cookiePolicy}
|
||||
impressum={config?.impressum}
|
||||
accessibilityStatement={config?.accessibilityStatement}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
24
frontend/src/components/shared/AppConfigLoader.tsx
Normal file
24
frontend/src/components/shared/AppConfigLoader.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useAppConfig } from '../../hooks/useAppConfig';
|
||||
import { updateSupportedLanguages } from '../../i18n';
|
||||
|
||||
/**
|
||||
* Component that loads app configuration and applies it to the application.
|
||||
* This includes:
|
||||
* - Filtering available languages based on config.languages
|
||||
*
|
||||
* Place this component high in the component tree, after i18n has initialized.
|
||||
*/
|
||||
export default function AppConfigLoader() {
|
||||
const { config, loading } = useAppConfig();
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading && config) {
|
||||
// Update supported languages if config specifies a language filter
|
||||
updateSupportedLanguages(config.languages);
|
||||
}
|
||||
}, [config, loading]);
|
||||
|
||||
// This component doesn't render anything
|
||||
return null;
|
||||
}
|
||||
@@ -12,14 +12,19 @@ interface FooterProps {
|
||||
}
|
||||
|
||||
export default function Footer({
|
||||
privacyPolicy = '/privacy',
|
||||
termsAndConditions = '/terms',
|
||||
accessibilityStatement = 'accessibility',
|
||||
privacyPolicy,
|
||||
termsAndConditions,
|
||||
accessibilityStatement,
|
||||
cookiePolicy,
|
||||
impressum,
|
||||
analyticsEnabled = false
|
||||
}: FooterProps) {
|
||||
const { t } = useTranslation();
|
||||
const { showCookiePreferences } = useCookieConsent({ analyticsEnabled });
|
||||
|
||||
// Helper to check if a value is valid (not null/undefined/empty string)
|
||||
const isValidLink = (link?: string) => link && link.trim().length > 0;
|
||||
|
||||
return (
|
||||
<div style={{
|
||||
height: 'var(--footer-height)',
|
||||
@@ -43,7 +48,7 @@ export default function Footer({
|
||||
>
|
||||
{t('survey.nav', 'Survey')}
|
||||
</a>
|
||||
{privacyPolicy && (
|
||||
{isValidLink(privacyPolicy) && (
|
||||
<a
|
||||
className="footer-link px-3"
|
||||
target="_blank"
|
||||
@@ -53,7 +58,7 @@ export default function Footer({
|
||||
{t('legal.privacy', 'Privacy Policy')}
|
||||
</a>
|
||||
)}
|
||||
{termsAndConditions && (
|
||||
{isValidLink(termsAndConditions) && (
|
||||
<a
|
||||
className="footer-link px-3"
|
||||
target="_blank"
|
||||
@@ -63,7 +68,7 @@ export default function Footer({
|
||||
{t('legal.terms', 'Terms and Conditions')}
|
||||
</a>
|
||||
)}
|
||||
{accessibilityStatement && (
|
||||
{isValidLink(accessibilityStatement) && (
|
||||
<a
|
||||
className="footer-link px-3"
|
||||
target="_blank"
|
||||
@@ -73,6 +78,26 @@ export default function Footer({
|
||||
{t('legal.accessibility', 'Accessibility')}
|
||||
</a>
|
||||
)}
|
||||
{isValidLink(cookiePolicy) && (
|
||||
<a
|
||||
className="footer-link px-3"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={cookiePolicy}
|
||||
>
|
||||
{t('legal.cookiePolicy', 'Cookie Policy')}
|
||||
</a>
|
||||
)}
|
||||
{isValidLink(impressum) && (
|
||||
<a
|
||||
className="footer-link px-3"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={impressum}
|
||||
>
|
||||
{t('legal.impressum', 'Impressum')}
|
||||
</a>
|
||||
)}
|
||||
{analyticsEnabled && (
|
||||
<button
|
||||
className="footer-link px-3"
|
||||
|
||||
@@ -7,8 +7,6 @@ import { useRestartServer } from '../useRestartServer';
|
||||
|
||||
interface GeneralSettingsData {
|
||||
ui: {
|
||||
appName?: string;
|
||||
homeDescription?: string;
|
||||
appNameNavbar?: string;
|
||||
languages?: string[];
|
||||
};
|
||||
|
||||
@@ -34,7 +34,6 @@ const Overview: React.FC = () => {
|
||||
};
|
||||
|
||||
const basicConfig = config ? {
|
||||
appName: config.appName,
|
||||
appNameNavbar: config.appNameNavbar,
|
||||
baseUrl: config.baseUrl,
|
||||
contextPath: config.contextPath,
|
||||
|
||||
@@ -4,9 +4,7 @@ export interface AppConfig {
|
||||
baseUrl?: string;
|
||||
contextPath?: string;
|
||||
serverPort?: number;
|
||||
appName?: string;
|
||||
appNameNavbar?: string;
|
||||
homeDescription?: string;
|
||||
languages?: string[];
|
||||
enableLogin?: boolean;
|
||||
enableAlphaFunctionality?: boolean;
|
||||
|
||||
@@ -104,4 +104,34 @@ i18n.on('languageChanged', (lng) => {
|
||||
document.documentElement.lang = lng;
|
||||
});
|
||||
|
||||
/**
|
||||
* Updates the supported languages list dynamically based on config
|
||||
* If configLanguages is null/empty, all languages remain available
|
||||
* Otherwise, only specified languages plus 'en-GB' fallback are enabled
|
||||
*/
|
||||
export function updateSupportedLanguages(configLanguages?: string[] | null) {
|
||||
if (!configLanguages || configLanguages.length === 0) {
|
||||
// No filter specified - keep all languages
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure fallback language is always included
|
||||
const languagesToSupport = new Set(['en-GB', ...configLanguages]);
|
||||
|
||||
// Filter to only valid language codes that exist in our translations
|
||||
const validLanguages = Array.from(languagesToSupport).filter(
|
||||
lang => lang in supportedLanguages
|
||||
);
|
||||
|
||||
if (validLanguages.length > 0) {
|
||||
i18n.options.supportedLngs = validLanguages;
|
||||
|
||||
// If current language is not in the new supported list, switch to fallback
|
||||
const currentLang = i18n.language;
|
||||
if (currentLang && !validLanguages.includes(currentLang)) {
|
||||
i18n.changeLanguage('en-GB');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default i18n;
|
||||
|
||||
@@ -42,6 +42,7 @@ export default function HomePage() {
|
||||
|
||||
const { openFilesModal } = useFilesModalContext();
|
||||
const { colorScheme } = useMantineColorScheme();
|
||||
const { config } = useAppConfig();
|
||||
const isMobile = useMediaQuery("(max-width: 1024px)");
|
||||
const sliderRef = useRef<HTMLDivElement | null>(null);
|
||||
const [activeMobileView, setActiveMobileView] = useState<MobileView>("tools");
|
||||
@@ -138,10 +139,11 @@ export default function HomePage() {
|
||||
const baseUrl = getBaseUrl();
|
||||
|
||||
// Update document meta when tool changes
|
||||
const appName = config?.appNameNavbar || 'Stirling PDF';
|
||||
useDocumentMeta({
|
||||
title: selectedTool ? `${selectedTool.name} - Stirling PDF` : 'Stirling PDF',
|
||||
title: selectedTool ? `${selectedTool.name} - ${appName}` : appName,
|
||||
description: selectedTool?.description || t('app.description', 'The Free Adobe Acrobat alternative (10M+ Downloads)'),
|
||||
ogTitle: selectedTool ? `${selectedTool.name} - Stirling PDF` : 'Stirling PDF',
|
||||
ogTitle: selectedTool ? `${selectedTool.name} - ${appName}` : appName,
|
||||
ogDescription: selectedTool?.description || t('app.description', 'The Free Adobe Acrobat alternative (10M+ Downloads)'),
|
||||
ogImage: selectedToolKey ? `${baseUrl}/og_images/${selectedToolKey}.png` : `${baseUrl}/og_images/home.png`,
|
||||
ogUrl: selectedTool ? `${baseUrl}${window.location.pathname}` : baseUrl
|
||||
|
||||
Reference in New Issue
Block a user