Merge pull request #2388 from automatisch/introduce-customizable-footer

feat: introduce customizable footer
This commit is contained in:
Ali BARIN
2025-03-10 13:26:11 +01:00
committed by GitHub
18 changed files with 461 additions and 8 deletions

View File

@@ -11,6 +11,15 @@ export default async (request, response) => {
const configParams = (request) => { const configParams = (request) => {
const { const {
enableFooter,
footerBackgroundColor,
footerCopyrightText,
footerDocsUrl,
footerImprintUrl,
footerLogoSvgData,
footerPrivacyPolicyUrl,
footerTextColor,
footerTosUrl,
logoSvgData, logoSvgData,
palettePrimaryDark, palettePrimaryDark,
palettePrimaryLight, palettePrimaryLight,
@@ -19,6 +28,15 @@ const configParams = (request) => {
} = request.body; } = request.body;
return { return {
enableFooter,
footerBackgroundColor,
footerCopyrightText,
footerDocsUrl,
footerImprintUrl,
footerLogoSvgData,
footerPrivacyPolicyUrl,
footerTextColor,
footerTosUrl,
logoSvgData, logoSvgData,
palettePrimaryDark, palettePrimaryDark,
palettePrimaryLight, palettePrimaryLight,

View File

@@ -25,6 +25,18 @@ describe('PATCH /api/v1/admin/config', () => {
const palettePrimaryMain = '#00adef'; const palettePrimaryMain = '#00adef';
const palettePrimaryDark = '#222222'; const palettePrimaryDark = '#222222';
const palettePrimaryLight = '#f90707'; const palettePrimaryLight = '#f90707';
const enableFooter = true;
const footerCopyrightText = '© AB Software GmbH';
const footerBackgroundColor = '#FFFFFF';
const footerTextColor = '#000000';
const footerDocsUrl = 'https://automatisch.io/docs';
const footerTosUrl = 'https://automatisch.io/terms';
const footerPrivacyPolicyUrl = 'https://automatisch.io/privacy';
const footerImprintUrl = 'https://automatisch.io/imprint';
const footerLogoSvgData =
'<svg width="25" height="25" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100"><rect width="100%" height="100%" fill="white" /><text x="10" y="40" font-family="Arial" font-size="40" fill="black">Sample Footer Logo</text></svg>';
const logoSvgData = const logoSvgData =
'<svg width="25" height="25" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100"><rect width="100%" height="100%" fill="white" /><text x="10" y="40" font-family="Arial" font-size="40" fill="black">A</text></svg>'; '<svg width="25" height="25" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 100 100"><rect width="100%" height="100%" fill="white" /><text x="10" y="40" font-family="Arial" font-size="40" fill="black">A</text></svg>';
@@ -34,6 +46,15 @@ describe('PATCH /api/v1/admin/config', () => {
palettePrimaryDark: palettePrimaryDark, palettePrimaryDark: palettePrimaryDark,
palettePrimaryLight: palettePrimaryLight, palettePrimaryLight: palettePrimaryLight,
logoSvgData: logoSvgData, logoSvgData: logoSvgData,
enableFooter,
footerCopyrightText,
footerBackgroundColor,
footerTextColor,
footerDocsUrl,
footerTosUrl,
footerPrivacyPolicyUrl,
footerImprintUrl,
footerLogoSvgData,
}; };
await updateConfig(appConfig); await updateConfig(appConfig);

View File

@@ -28,6 +28,15 @@ describe('GET /api/v1/automatisch/config', () => {
palettePrimaryMain: '#0059F7', palettePrimaryMain: '#0059F7',
title: 'Sample Title', title: 'Sample Title',
enableTemplates: true, enableTemplates: true,
enableFooter: true,
footerLogoSvgData: '<svg>Sample Footer Logo</svg>',
footerCopyrightText: '© AB Software GmbH',
footerBackgroundColor: '#FFFFFF',
footerTextColor: '#000000',
footerDocsUrl: 'https://automatisch.io/docs',
footerTosUrl: 'https://automatisch.io/terms',
footerPrivacyPolicyUrl: 'https://automatisch.io/privacy',
footerImprintUrl: 'https://automatisch.io/imprint',
}); });
const response = await request(app) const response = await request(app)
@@ -41,6 +50,16 @@ describe('GET /api/v1/automatisch/config', () => {
additionalDrawerLink: 'link', additionalDrawerLink: 'link',
additionalDrawerLinkIcon: 'icon', additionalDrawerLinkIcon: 'icon',
additionalDrawerLinkText: 'text', additionalDrawerLinkText: 'text',
enableTemplates: true,
enableFooter: true,
footerLogoSvgData: '<svg>Sample Footer Logo</svg>',
footerCopyrightText: '© AB Software GmbH',
footerBackgroundColor: '#FFFFFF',
footerTextColor: '#000000',
footerDocsUrl: 'https://automatisch.io/docs',
footerTosUrl: 'https://automatisch.io/terms',
footerPrivacyPolicyUrl: 'https://automatisch.io/privacy',
footerImprintUrl: 'https://automatisch.io/imprint',
}); });
expect(response.body).toStrictEqual(expectedPayload); expect(response.body).toStrictEqual(expectedPayload);

View File

@@ -0,0 +1,27 @@
export async function up(knex) {
await knex.schema.table('config', (table) => {
table.boolean('enable_footer').defaultTo(false);
table.text('footer_logo_svg_data');
table.string('footer_copyright_text');
table.string('footer_background_color');
table.string('footer_text_color');
table.string('footer_docs_url');
table.string('footer_tos_url');
table.string('footer_privacy_policy_url');
table.string('footer_imprint_url');
});
}
export async function down(knex) {
await knex.schema.table('config', (table) => {
table.dropColumn('enable_footer');
table.dropColumn('footer_copyright_text');
table.dropColumn('footer_logo_svg_data');
table.dropColumn('footer_background_color');
table.dropColumn('footer_text_color');
table.dropColumn('footer_docs_url');
table.dropColumn('footer_tos_url');
table.dropColumn('footer_privacy_policy_url');
table.dropColumn('footer_imprint_url');
});
}

View File

@@ -6,12 +6,63 @@ exports[`Config model > jsonSchema should have correct validations 1`] = `
"createdAt": { "createdAt": {
"type": "string", "type": "string",
}, },
"enableFooter": {
"type": "boolean",
},
"enableTemplates": { "enableTemplates": {
"type": [ "type": [
"boolean", "boolean",
"null", "null",
], ],
}, },
"footerBackgroundColor": {
"type": [
"string",
"null",
],
},
"footerCopyrightText": {
"type": [
"string",
"null",
],
},
"footerDocsUrl": {
"type": [
"string",
"null",
],
},
"footerImprintUrl": {
"type": [
"string",
"null",
],
},
"footerLogoSvgData": {
"type": [
"string",
"null",
],
},
"footerPrivacyPolicyUrl": {
"type": [
"string",
"null",
],
},
"footerTextColor": {
"type": [
"string",
"null",
],
},
"footerTosUrl": {
"type": [
"string",
"null",
],
},
"id": { "id": {
"format": "uuid", "format": "uuid",
"type": "string", "type": "string",

View File

@@ -16,6 +16,15 @@ class Config extends Base {
palettePrimaryMain: { type: ['string', 'null'] }, palettePrimaryMain: { type: ['string', 'null'] },
title: { type: ['string', 'null'] }, title: { type: ['string', 'null'] },
enableTemplates: { type: ['boolean', 'null'] }, enableTemplates: { type: ['boolean', 'null'] },
enableFooter: { type: 'boolean' },
footerLogoSvgData: { type: ['string', 'null'] },
footerCopyrightText: { type: ['string', 'null'] },
footerBackgroundColor: { type: ['string', 'null'] },
footerTextColor: { type: ['string', 'null'] },
footerDocsUrl: { type: ['string', 'null'] },
footerTosUrl: { type: ['string', 'null'] },
footerPrivacyPolicyUrl: { type: ['string', 'null'] },
footerImprintUrl: { type: ['string', 'null'] },
createdAt: { type: 'string' }, createdAt: { type: 'string' },
updatedAt: { type: 'string' }, updatedAt: { type: 'string' },
}, },

View File

@@ -15,6 +15,15 @@ const configSerializer = (config) => {
palettePrimaryLight: config.palettePrimaryLight, palettePrimaryLight: config.palettePrimaryLight,
installationCompleted: config.installationCompleted, installationCompleted: config.installationCompleted,
title: config.title, title: config.title,
enableFooter: config.enableFooter,
footerLogoSvgData: config.footerLogoSvgData,
footerCopyrightText: config.footerCopyrightText,
footerBackgroundColor: config.footerBackgroundColor,
footerTextColor: config.footerTextColor,
footerDocsUrl: config.footerDocsUrl,
footerTosUrl: config.footerTosUrl,
footerPrivacyPolicyUrl: config.footerPrivacyPolicyUrl,
footerImprintUrl: config.footerImprintUrl,
}; };
}; };

View File

@@ -24,6 +24,15 @@ describe('configSerializer', () => {
additionalDrawerLink: config.additionalDrawerLink, additionalDrawerLink: config.additionalDrawerLink,
additionalDrawerLinkIcon: config.additionalDrawerLinkIcon, additionalDrawerLinkIcon: config.additionalDrawerLinkIcon,
additionalDrawerLinkText: config.additionalDrawerLinkText, additionalDrawerLinkText: config.additionalDrawerLinkText,
enableFooter: config.enableFooter,
footerBackgroundColor: config.footerBackgroundColor,
footerCopyrightText: config.footerCopyrightText,
footerDocsUrl: config.footerDocsUrl,
footerImprintUrl: config.footerImprintUrl,
footerLogoSvgData: config.footerLogoSvgData,
footerPrivacyPolicyUrl: config.footerPrivacyPolicyUrl,
footerTextColor: config.footerTextColor,
footerTosUrl: config.footerTosUrl,
createdAt: config.createdAt.getTime(), createdAt: config.createdAt.getTime(),
updatedAt: config.updatedAt.getTime(), updatedAt: config.updatedAt.getTime(),
}; };

View File

@@ -16,6 +16,15 @@ const configMock = (config) => {
installationCompleted: config.installationCompleted || false, installationCompleted: config.installationCompleted || false,
title: config.title, title: config.title,
enableTemplates: config.enableTemplates, enableTemplates: config.enableTemplates,
enableFooter: config.enableFooter || false,
footerLogoSvgData: config.footerLogoSvgData,
footerCopyrightText: config.footerCopyrightText,
footerBackgroundColor: config.footerBackgroundColor,
footerTextColor: config.footerTextColor,
footerDocsUrl: config.footerDocsUrl,
footerTosUrl: config.footerTosUrl,
footerPrivacyPolicyUrl: config.footerPrivacyPolicyUrl,
footerImprintUrl: config.footerImprintUrl,
}, },
meta: { meta: {
count: 1, count: 1,

View File

@@ -1,4 +1,4 @@
<!DOCTYPE html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
@@ -25,6 +25,7 @@
crossorigin crossorigin
type="font/ttf" type="font/ttf"
/> />
<link <link
rel="preload" rel="preload"
href="/fonts/Inter-Medium.ttf" href="/fonts/Inter-Medium.ttf"
@@ -32,6 +33,7 @@
crossorigin crossorigin
type="font/ttf" type="font/ttf"
/> />
<link <link
rel="preload" rel="preload"
href="/fonts/Inter-Bold.ttf" href="/fonts/Inter-Bold.ttf"
@@ -39,6 +41,7 @@
crossorigin crossorigin
type="font/ttf" type="font/ttf"
/> />
<style> <style>
@font-face { @font-face {
font-family: 'Inter'; font-family: 'Inter';
@@ -63,6 +66,10 @@
font-style: normal; font-style: normal;
font-display: swap; font-display: swap;
} }
.tsqd-parent-container .tsqd-open-btn-container {
transform: translateY(-40px);
}
</style> </style>
</head> </head>
<body> <body>

View File

@@ -5,13 +5,13 @@ import Typography from '@mui/material/Typography';
import useFormatMessage from 'hooks/useFormatMessage'; import useFormatMessage from 'hooks/useFormatMessage';
import useVersion from 'hooks/useVersion'; import useVersion from 'hooks/useVersion';
const Footer = () => { const AdminSettingsLayoutFooter = () => {
const version = useVersion(); const version = useVersion();
const formatMessage = useFormatMessage(); const formatMessage = useFormatMessage();
return ( return (
typeof version?.version === 'string' && ( typeof version?.version === 'string' && (
<Box mt="auto" position="sticky" bottom={0}> <Box mt="auto" position="sticky" bottom={0} zIndex={99}>
<Box bgcolor="common.white" mt={4}> <Box bgcolor="common.white" mt={4}>
<Divider /> <Divider />
<Typography <Typography
@@ -32,4 +32,4 @@ const Footer = () => {
); );
}; };
export default Footer; export default AdminSettingsLayoutFooter;

View File

@@ -1,4 +1,5 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
export const LogoImage = styled('img')(() => ({ export const LogoImage = styled('img')(() => ({
maxWidth: 200, maxWidth: 200,
maxHeight: 22, maxHeight: 22,

View File

@@ -0,0 +1,126 @@
import styled from '@emotion/styled';
import Box from '@mui/material/Box';
import Divider from '@mui/material/Divider';
import Link from '@mui/material/Link';
import Stack from '@mui/material/Stack';
import SvgIcon from '@mui/material/SvgIcon';
import Typography from '@mui/material/Typography';
import useAutomatischConfig from 'hooks/useAutomatischConfig';
import useFormatMessage from 'hooks/useFormatMessage';
import useVersion from 'hooks/useVersion';
const LogoImage = styled('img')(() => ({
maxWidth: 'auto',
height: 22,
}));
const LayoutFooter = () => {
const { data: config, isPending: isConfigPending } = useAutomatischConfig();
const formatMessage = useFormatMessage();
const links = [
{
key: 'docs',
show: !!config.data.footerDocsUrl,
href: config.data.footerDocsUrl,
text: formatMessage('footer.docsLinkText'),
},
{
key: 'terms-of-services',
show: !!config.data.footerTosUrl,
href: config.data.footerTosUrl,
text: formatMessage('footer.tosLinkText'),
},
{
key: 'privacy-policy',
show: !!config.data.footerPrivacyPolicyUrl,
href: config.data.footerPrivacyPolicyUrl,
text: formatMessage('footer.privacyPolicyLinkText'),
},
{
key: 'imprint',
show: !!config.data.footerImprintUrl,
href: config.data.footerImprintUrl,
text: formatMessage('footer.imprintLinkText'),
},
,
];
if (config.data.enableFooter !== true) return null;
return (
<Box mt="auto" position="sticky" bottom={0}>
<Box bgcolor="common.white" mt={4}>
<Divider />
<Box
sx={{
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
gap: 1,
justifyContent: 'space-between',
alignItems: 'center',
padding: '10px 20px',
bgcolor: (theme) => theme.palette.footer.main,
color: (theme) => theme.palette.footer.text,
}}
>
<div>
{config.data.footerLogoSvgData && (
<>
<LogoImage
data-test="footer-logo"
src={`data:image/svg+xml;utf8,${encodeURIComponent(config.data.footerLogoSvgData)}`}
/>
</>
)}
</div>
<div>
{config.data.footerCopyrightText && (
<Typography
variant="body1"
sx={{ flexGrow: 1, textAlign: 'center' }}
>
{config.data.footerCopyrightText}
</Typography>
)}
</div>
<Box
sx={{
display: 'flex',
gap: '15px',
flexWrap: { xs: 'wrap', sm: 'unset' },
justifyContent: 'center',
}}
>
{links
.filter((link) => link.show)
.map((link) => (
<Link
key={link.key}
href={link.href}
color="inherit"
variant="body1"
target="_blank"
rel="noreferrer noopener"
sx={{
textDecoration: 'none',
'&:hover': { textDecoration: 'underline' },
}}
>
{link.text}
</Link>
))}
</Box>
</Box>
</Box>
</Box>
);
};
export default LayoutFooter;

View File

@@ -19,6 +19,8 @@ import AppBar from 'components/AppBar';
import Drawer from 'components/Drawer'; import Drawer from 'components/Drawer';
import useAutomatischConfig from 'hooks/useAutomatischConfig'; import useAutomatischConfig from 'hooks/useAutomatischConfig';
import Footer from './Footer';
const additionalDrawerLinkIcons = { const additionalDrawerLinkIcons = {
Security: SecurityIcon, Security: SecurityIcon,
ArrowBackIosNew: ArrowBackIosNewIcon, ArrowBackIosNew: ArrowBackIosNewIcon,
@@ -141,6 +143,7 @@ function PublicLayout({ children }) {
<Stack flex={1}> <Stack flex={1}>
<Toolbar /> <Toolbar />
{children} {children}
<Footer />
</Stack> </Stack>
</Box> </Box>
</> </>

View File

@@ -37,6 +37,18 @@ const customizeTheme = (theme, config) => {
config.palettePrimaryDark, config.palettePrimaryDark,
); );
overrideIfGiven(
shallowDefaultTheme,
'palette.footer.main',
config.footerBackgroundColor,
);
overrideIfGiven(
shallowDefaultTheme,
'palette.footer.text',
config.footerTextColor,
);
return shallowDefaultTheme; return shallowDefaultTheme;
}; };

View File

@@ -273,12 +273,23 @@
"permissionSettings.title": "Conditions", "permissionSettings.title": "Conditions",
"appOAuthClientsDialog.title": "Choose your authentication client", "appOAuthClientsDialog.title": "Choose your authentication client",
"userInterfacePage.title": "User Interface", "userInterfacePage.title": "User Interface",
"userInterfacePage.generalTitle": "General",
"userInterfacePage.footerTitle": "Footer",
"userInterfacePage.successfullyUpdated": "User interface has been updated.", "userInterfacePage.successfullyUpdated": "User interface has been updated.",
"userInterfacePage.titleFieldLabel": "Title", "userInterfacePage.titleFieldLabel": "Title",
"userInterfacePage.primaryMainColorFieldLabel": "Primary main color", "userInterfacePage.primaryMainColorFieldLabel": "Primary main color",
"userInterfacePage.primaryDarkColorFieldLabel": "Primary dark color", "userInterfacePage.primaryDarkColorFieldLabel": "Primary dark color",
"userInterfacePage.primaryLightColorFieldLabel": "Primary light color", "userInterfacePage.primaryLightColorFieldLabel": "Primary light color",
"userInterfacePage.svgDataFieldLabel": "Logo SVG code", "userInterfacePage.svgDataFieldLabel": "Logo SVG code",
"userInterfacePage.footerLogoSvgDataFieldLabel": "Footer logo SVG code",
"userInterfacePage.footerCopyrightTextFieldLabel": "Copyright text",
"userInterfacePage.enableFooterLabel": "Enable footer",
"userInterfacePage.footerTextColorLabel": "Text color",
"userInterfacePage.footerBackgroundColorLabel": "Background color",
"userInterfacePage.footerDocsUrlLabel": "Documentation link",
"userInterfacePage.footerTosUrlLabel": "Terms of services link",
"userInterfacePage.footerPrivacyPolicyUrlLabel": "Privacy policy link",
"userInterfacePage.footerImprintUrlLabel": "Imprint link",
"userInterfacePage.submit": "Update", "userInterfacePage.submit": "Update",
"authenticationPage.title": "Single Sign-On with SAML", "authenticationPage.title": "Single Sign-On with SAML",
"authenticationForm.active": "Active", "authenticationForm.active": "Active",
@@ -355,5 +366,9 @@
"flowFolderChangeDialog.confirm": "Move", "flowFolderChangeDialog.confirm": "Move",
"flowFolderChangeDialog.uncategorizedFolder": "Uncategorized", "flowFolderChangeDialog.uncategorizedFolder": "Uncategorized",
"flowFolderChangeDialog.successfullyUpdatedFolder": "The flow has been successfully moved to the new folder!", "flowFolderChangeDialog.successfullyUpdatedFolder": "The flow has been successfully moved to the new folder!",
"flowFolder.uncategorized": "Uncategorized" "flowFolder.uncategorized": "Uncategorized",
"footer.docsLinkText": "Documentation",
"footer.tosLinkText": "Terms of Service",
"footer.privacyPolicyLinkText": "Privacy",
"footer.imprintLinkText": "Imprint"
} }

View File

@@ -1,10 +1,12 @@
import LoadingButton from '@mui/lab/LoadingButton'; import LoadingButton from '@mui/lab/LoadingButton';
import Grid from '@mui/material/Grid'; import Grid from '@mui/material/Grid';
import Typography from '@mui/material/Typography';
import Skeleton from '@mui/material/Skeleton'; import Skeleton from '@mui/material/Skeleton';
import Stack from '@mui/material/Stack'; import Stack from '@mui/material/Stack';
import mergeWith from 'lodash/mergeWith'; import mergeWith from 'lodash/mergeWith';
import * as React from 'react'; import * as React from 'react';
import Switch from 'components/Switch';
import ColorInput from 'components/ColorInput'; import ColorInput from 'components/ColorInput';
import Container from 'components/Container'; import Container from 'components/Container';
import Form from 'components/Form'; import Form from 'components/Form';
@@ -29,6 +31,16 @@ const defaultValues = {
palettePrimaryMain: primaryMainColor, palettePrimaryMain: primaryMainColor,
palettePrimaryDark: primaryDarkColor, palettePrimaryDark: primaryDarkColor,
palettePrimaryLight: primaryLightColor, palettePrimaryLight: primaryLightColor,
logoSvgData: '',
enableFooter: false,
footerLogoSvgData: '',
footerCopyrightText: '',
footerBackgroundColor: '#FFFFFF',
footerTextColor: '#000000',
footerDocsUrl: '',
footerTosUrl: '',
footerPrivacyPolicyUrl: '',
footerImprintUrl: '',
}; };
const mergeIfGiven = (oldValue, newValue) => { const mergeIfGiven = (oldValue, newValue) => {
@@ -51,13 +63,24 @@ export default function UserInterface() {
const handleUserInterfaceUpdate = async (uiData) => { const handleUserInterfaceUpdate = async (uiData) => {
try { try {
const input = { const input = {
title: uiData.title, enableFooter: uiData.enableFooter,
palettePrimaryMain: getPrimaryMainColor(uiData.palettePrimaryMain), footerBackgroundColor: uiData.footerBackgroundColor,
footerCopyrightText: uiData.footerCopyrightText,
footerDocsUrl: uiData.footerDocsUrl,
footerImprintUrl: uiData.footerImprintUrl,
footerLogoSvgData: uiData.footerLogoSvgData,
footerPrivacyPolicyUrl: uiData.footerPrivacyPolicyUrl,
footerTextColor: uiData.footerTextColor,
footerTosUrl: uiData.footerTosUrl,
logoSvgData: uiData.logoSvgData,
palettePrimaryDark: getPrimaryDarkColor(uiData.palettePrimaryDark), palettePrimaryDark: getPrimaryDarkColor(uiData.palettePrimaryDark),
palettePrimaryLight: getPrimaryLightColor(uiData.palettePrimaryLight), palettePrimaryLight: getPrimaryLightColor(uiData.palettePrimaryLight),
logoSvgData: uiData.logoSvgData, palettePrimaryMain: getPrimaryMainColor(uiData.palettePrimaryMain),
title: uiData.title,
}; };
await updateConfig(input); await updateConfig(input);
enqueueSnackbar(formatMessage('userInterfacePage.successfullyUpdated'), { enqueueSnackbar(formatMessage('userInterfacePage.successfullyUpdated'), {
variant: 'success', variant: 'success',
SnackbarProps: { SnackbarProps: {
@@ -92,6 +115,10 @@ export default function UserInterface() {
defaultValues={configWithDefaults} defaultValues={configWithDefaults}
> >
<Stack direction="column" gap={2}> <Stack direction="column" gap={2}>
<Typography variant="h4" gutterBottom={true}>
{formatMessage('userInterfacePage.generalTitle')}
</Typography>
<TextField <TextField
name="title" name="title"
label={formatMessage('userInterfacePage.titleFieldLabel')} label={formatMessage('userInterfacePage.titleFieldLabel')}
@@ -133,6 +160,89 @@ export default function UserInterface() {
data-test="logo-svg-data-text-field" data-test="logo-svg-data-text-field"
/> />
<Typography variant="h4" gutterBottom={true} mt={3}>
{formatMessage('userInterfacePage.footerTitle')}
</Typography>
<Switch
name="enableFooter"
label={formatMessage('userInterfacePage.enableFooterLabel')}
/>
<TextField
name="footerLogoSvgData"
label={formatMessage(
'userInterfacePage.footerLogoSvgDataFieldLabel',
)}
multiline
fullWidth
data-test="footer-logo-svg-data-text-field"
/>
<TextField
name="footerCopyrightText"
label={formatMessage(
'userInterfacePage.footerCopyrightTextFieldLabel',
)}
multiline
fullWidth
data-test="footer-copyright-text-field"
/>
<ColorInput
name="footerBackgroundColor"
label={formatMessage(
'userInterfacePage.footerBackgroundColorLabel',
)}
fullWidth
data-test="footer-background-color-input"
/>
<ColorInput
name="footerTextColor"
label={formatMessage(
'userInterfacePage.footerTextColorLabel',
)}
fullWidth
data-test="footer-text-color-input"
/>
<TextField
name="footerDocsUrl"
label={formatMessage('userInterfacePage.footerDocsUrlLabel')}
multiline
fullWidth
data-test="logo-docs-text-field"
/>
<TextField
name="footerTosUrl"
label={formatMessage('userInterfacePage.footerTosUrlLabel')}
multiline
fullWidth
data-test="logo-tos-url-text-field"
/>
<TextField
name="footerPrivacyPolicyUrl"
label={formatMessage(
'userInterfacePage.footerPrivacyPolicyUrlLabel',
)}
multiline
fullWidth
data-test="logo-privacy-policy-url-text-field"
/>
<TextField
name="footerImprintUrl"
label={formatMessage(
'userInterfacePage.footerImprintUrlLabel',
)}
multiline
fullWidth
data-test="logo-imprint-url-text-field"
/>
<LoadingButton <LoadingButton
type="submit" type="submit"
variant="contained" variant="contained"

View File

@@ -1,10 +1,13 @@
import { deepmerge } from '@mui/utils'; import { deepmerge } from '@mui/utils';
import { createTheme, alpha } from '@mui/material/styles'; import { createTheme, alpha } from '@mui/material/styles';
import { cardActionAreaClasses } from '@mui/material/CardActionArea'; import { cardActionAreaClasses } from '@mui/material/CardActionArea';
const referenceTheme = createTheme(); const referenceTheme = createTheme();
export const primaryMainColor = '#0059F7'; export const primaryMainColor = '#0059F7';
export const primaryLightColor = '#4286FF'; export const primaryLightColor = '#4286FF';
export const primaryDarkColor = '#001F52'; export const primaryDarkColor = '#001F52';
export const defaultTheme = createTheme({ export const defaultTheme = createTheme({
palette: { palette: {
primary: { primary: {
@@ -57,6 +60,10 @@ export const defaultTheme = createTheme({
paper: '#fff', paper: '#fff',
default: '#FAFAFA', default: '#FAFAFA',
}, },
footer: {
main: '#FFFFFF',
text: '#001F52',
},
}, },
shape: { shape: {
borderRadius: 4, borderRadius: 4,