From 1e01c0fb0d87a687e9bd6732569ed46a9f55006d Mon Sep 17 00:00:00 2001 From: I531348 Date: Mon, 17 Nov 2025 07:17:25 +0100 Subject: [PATCH 01/12] footer --- .changeset/shaggy-memes-push.md | 11 ++ .../PageFooter/PageFooter.component.tsx | 47 ++--- .../PageFooter/PageFooter.stories.tsx | 164 +++++++++++++++++- .../components/PageFooter/PageFooter.test.tsx | 49 ++++-- .../src/components/PageFooter/page-footer.css | 62 +++++++ packages/ui-components/src/global.css | 22 +++ packages/ui-components/src/theme.css | 20 +++ 7 files changed, 336 insertions(+), 39 deletions(-) create mode 100644 .changeset/shaggy-memes-push.md create mode 100644 packages/ui-components/src/components/PageFooter/page-footer.css diff --git a/.changeset/shaggy-memes-push.md b/.changeset/shaggy-memes-push.md new file mode 100644 index 0000000000..2ca0bd4d82 --- /dev/null +++ b/.changeset/shaggy-memes-push.md @@ -0,0 +1,11 @@ +--- +"@cloudoperators/juno-ui-components": major +--- + +Enhance PageFooter with flexible content and theming options + +- Removed the hardcoded cloud illustration for improved branding and theming flexibility. +- Added support for a dynamic copyright section to be displayed conditionally. +- Implemented responsive handling of children within a grid layout to adapt to varying content. +- Updated design tokens to facilitate theme-specific styling in alignment with design requirements. +- Improved semantic structure for accessibility by using ARIA roles and attributes. diff --git a/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx b/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx index 581a1fabb7..945e25d1c3 100644 --- a/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx +++ b/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx @@ -4,43 +4,44 @@ */ import React from "react" -import CCloudShape from "../../img/ccloud_shape.svg" +import "./page-footer.css" -const basePageFooter = ` +const basePageFooterStyles = ` jn:flex jn:shrink-0 jn:grow-0 jn:basis-auto jn:relative - jn:bg-theme-global-bg jn:min-h-[3.25rem] - jn:pl-6 - jn:pr-24 - jn:py-5 jn:z-50 + jn:px-6 + jn:py-5 + jn:border-t + jn:bg-theme-pagefooter + jn:text-theme-pagefooter + jn:bg-theme-pagefooter ` -const logoStyles = ` - jn:h-[2.625rem] - jn:absolute - jn:right-0 - jn:bottom-0 -` +export interface PageFooterProps extends React.HTMLAttributes { + /** Additional custom styling class name for the footer container */ + className?: string + /** The content to render inside the footer, typically links or informational text */ + children?: React.ReactNode + /** Optional copyright notice to display within the footer */ + copyright?: string +} /** - * The page footer component renders a footer at the bottom of the website. Place as last child of AppBody. + * PageFooter component renders a footer at the bottom of the page. + * It consists of a flexible content area for children and an optional copyright section. + * Usage: + * The component can be used to add legal disclaimers, links, or other contextual information at the page's footer. */ -export const PageFooter: React.FC = ({ className = "", children, ...props }) => { +export const PageFooter: React.FC = ({ className = "", children, copyright = "", ...props }) => { return ( -
- {children} - +
+
{children}
+ {copyright &&
{copyright}
}
) } - -export interface PageFooterProps extends React.HTMLAttributes { - /** Add custom class name */ - className?: string - children?: React.ReactNode -} diff --git a/packages/ui-components/src/components/PageFooter/PageFooter.stories.tsx b/packages/ui-components/src/components/PageFooter/PageFooter.stories.tsx index 74e18825d2..ca44cc9495 100644 --- a/packages/ui-components/src/components/PageFooter/PageFooter.stories.tsx +++ b/packages/ui-components/src/components/PageFooter/PageFooter.stories.tsx @@ -4,7 +4,6 @@ */ import React from "react" - import { PageFooter, PageFooterProps } from "./index" export default { @@ -17,6 +16,15 @@ export default { type: { summary: "ReactNode" }, }, }, + copyright: { + control: "text", + table: { + type: { summary: "string" }, + }, + }, + className: { + control: false, + }, }, } @@ -24,15 +32,163 @@ const Template = (args: PageFooterProps) => export const Simple = { render: Template, + parameters: { + docs: { + description: { + story: "A basic example of the PageFooter component without any children or custom content.", + }, + }, + }, + args: {}, +} +export const WithCustomCopyright = { + render: Template, parameters: { docs: { description: { - story: - "The page footer component renders a footer at the bottom of the website. Place as last child of AppBody.", + story: "PageFooter with a custom copyright notice.", }, }, }, + args: { + copyright: "© 2023 Custom Corporation. All rights reserved.", + }, +} - args: {}, +export const InlineLinks = { + render: Template, + parameters: { + docs: { + description: { + story: "PageFooter rendering inline links, illustrating how children can be displayed within the footer.", + }, + }, + }, + args: { + children: ( + + ), + }, +} + +export const WithTwoColumns = { + render: Template, + parameters: { + docs: { + description: { + story: "An example showing two columns within the PageFooter, each with a title and list of items.", + }, + }, + }, + args: { + children: ( + <> +
+ + +
+
+ + +
+ + ), + }, +} + +export const WithThreeColumns = { + render: Template, + parameters: { + docs: { + description: { + story: "An example showing three columns within the PageFooter, each with a title and list of items.", + }, + }, + }, + args: { + copyright: "© 2023 Custom Corporation. All rights reserved.", + children: ( + <> +
+ + +
+
+ + +
+
+ + +
+ + ), + }, } diff --git a/packages/ui-components/src/components/PageFooter/PageFooter.test.tsx b/packages/ui-components/src/components/PageFooter/PageFooter.test.tsx index 066e7ea4a4..9a2d7b42bd 100644 --- a/packages/ui-components/src/components/PageFooter/PageFooter.test.tsx +++ b/packages/ui-components/src/components/PageFooter/PageFooter.test.tsx @@ -10,35 +10,60 @@ import { PageFooter } from "./index" describe("PageFooter", () => { test("renders a simple Page Footer and has flexbox layout", () => { render() - expect(screen.getByRole("contentinfo")).toBeInTheDocument() - expect(screen.getByRole("contentinfo")).toHaveClass("jn:flex") + const footer = screen.getByRole("contentinfo") + expect(footer).toBeInTheDocument() + expect(footer).toHaveClass("jn:flex") }) - test("renders a Page Footer to have the global bg color", () => { + test("renders a Page Footer with specific styling", () => { render() - expect(screen.getByRole("contentinfo")).toBeInTheDocument() - expect(screen.getByRole("contentinfo")).toHaveClass("jn:bg-theme-global-bg") + const footer = screen.getByRole("contentinfo") + expect(footer).toBeInTheDocument() + expect(footer).toHaveClass("juno-pagefooter") // Confirm it has the main class }) test("renders children as passed", () => { render( - + ) - expect(screen.getByRole("contentinfo")).toBeInTheDocument() - expect(screen.getByRole("button")).toBeInTheDocument() + const button = screen.getByRole("button") + expect(button).toBeInTheDocument() + expect(button).toHaveTextContent("Test Button") }) test("renders a custom className", () => { render() - expect(screen.getByRole("contentinfo")).toBeInTheDocument() - expect(screen.getByRole("contentinfo")).toHaveClass("my-custom-classname") + const footer = screen.getByRole("contentinfo") + expect(footer).toBeInTheDocument() + expect(footer).toHaveClass("my-custom-classname") }) test("renders all props", () => { render() - expect(screen.getByRole("contentinfo")).toBeInTheDocument() - expect(screen.getByRole("contentinfo")).toHaveAttribute("data-lolol", "some-prop") + const footer = screen.getByRole("contentinfo") + expect(footer).toBeInTheDocument() + expect(footer).toHaveAttribute("data-lolol", "some-prop") + }) + + test("renders copyright section when provided", () => { + render() + const footer = screen.getByRole("contentinfo") + const copyrightSection = footer.querySelector(".juno-pagefooter-copyright") + expect(copyrightSection).toBeInTheDocument() + expect(copyrightSection).toHaveTextContent("© 2023 Test") + }) + + test("renders children section with flex layout", () => { + render( + + Child Item + + ) + const childrenSection = screen.getByRole("contentinfo").querySelector(".juno-pagefooter-children") + expect(childrenSection).toBeInTheDocument() + expect(childrenSection).toHaveClass("juno-pagefooter-children") + expect(childrenSection).toHaveTextContent("Child Item") }) }) diff --git a/packages/ui-components/src/components/PageFooter/page-footer.css b/packages/ui-components/src/components/PageFooter/page-footer.css new file mode 100644 index 0000000000..99b9f00053 --- /dev/null +++ b/packages/ui-components/src/components/PageFooter/page-footer.css @@ -0,0 +1,62 @@ +.juno-pagefooter { + padding: 1rem 2rem 0 2rem; + border-color: var(--color-pagefooter-border); +} + +.juno-pagefooter-title { + font-weight: bold; + color: var(--color-pagefooter-title, var(--text-color-theme-pagefooter)); +} + +.juno-pagefooter-items { + list-style: none; + padding: 0; + margin: 0; +} + +.juno-pagefooter-items-inline { + display: flex; + list-style: none; + padding: 0; + margin: 0; +} + +.juno-pagefooter-items-inline > li { + position: relative; +} + +.juno-pagefooter-items-inline > li::after { + content: "|"; + margin-left: 0.38rem; + margin-right: 0.38rem; + color: var(--color-pagefooter-item-default); +} + +.juno-pagefooter-items-inline > li:last-child::after { + content: ""; +} + +.juno-pagefooter-item { + color: var(--color-pagefooter-item-default); + flex: 1; +} + +.juno-pagefooter-item:hover { + color: var(--color-pagefooter-item-hover); + text-decoration: underline; +} + +.juno-pagefooter-item:active { + color: var(--color-pagefooter-item-active); +} + +.juno-pagefooter-children { + display: flex; + gap: 1rem; +} + +.juno-pagefooter-copyright { + margin-left: auto; + text-align: right; + color: var(--footer-text-color); +} diff --git a/packages/ui-components/src/global.css b/packages/ui-components/src/global.css index a23bdd9675..a6cac476f3 100644 --- a/packages/ui-components/src/global.css +++ b/packages/ui-components/src/global.css @@ -14,6 +14,7 @@ @import "./components/ThemeToggle/themeToggle.css" layer(utilities); @import "./components/DataGridRow/data-grid-row.css" layer(utilities); @import "./components/SideNavigationItem/sidenavigationitem.css" layer(utilities); +@import "./components/PageFooter/page-footer.css" layer(utilities); :root, :host { @@ -337,6 +338,11 @@ --color-theme-button-subdued: var(--color-button-subdued-text); --color-theme-button-sundued-hover: var(--color-button-subdued-hover-text); --color-theme-button-sundued-active: var(--color-button-subdued-active-text); + + /* PageFooter */ + --text-color-theme-pagefooter: var(--color-pagefooter-text); + --background-color-theme-pagefooter: var(--color-pagefooter-background); + /* TODO Border Color */ --border-theme-button-subdued: 1px solid var(--color-button-subdued-border); --border-theme-button-subdued-hover: var(--color-button-subdued-hover-border); @@ -722,6 +728,14 @@ /* LT Box Shadow */ --box-shadow-default: 0 1px 2px 0 rgba(34, 54, 73, 0.3); --box-shadow-hover: 0 0 0 1px var(--color-color-shadow, rgba(79, 79, 79, 0.3)), 0 2px 8px 0 rgba(0, 0, 0, 0.3); + /* LT PageFooter */ + --color-pagefooter-text: var(--color-text-light); + --color-pagefooter-background: var(--color-transparent); + --color-pagefooter-border: var(--color-border-default); + --color-pagefooter-title: var(--color-text-default); + --color-pagefooter-item-default: var(--color-text-light); + --color-pagefooter-item-hover: var(--color-text-light); + --color-pagefooter-item-active: var(--color-accent); } /* JUNO THEME: DARK MODE */ @@ -960,6 +974,14 @@ /* DT Box Shadow */ --box-shadow-default: 0 1px 2px 0 rgba(34, 54, 73, 0.3); --box-shadow-hover: 0 1px 2px 0 rgba(34, 54, 73, 0.3); + /* DT PageFooter */ + --color-pagefooter-text: var(--color-text-light); + --color-pagefooter-background: var(--color-transparent); + --color-pagefooter-border: var(--color-border-default); + --color-pagefooter-title: var(--color-text-default); + --color-pagefooter-item-default: var(--color-text-light); + --color-pagefooter-item-hover: var(--color-text-light); + --color-pagefooter-item-active: var(--color-accent); } /* diff --git a/packages/ui-components/src/theme.css b/packages/ui-components/src/theme.css index d9049faf95..35d54d8809 100644 --- a/packages/ui-components/src/theme.css +++ b/packages/ui-components/src/theme.css @@ -329,6 +329,10 @@ --color-theme-button-sundued-hover: var(--color-button-subdued-hover-text); --color-theme-button-sundued-active: var(--color-button-subdued-active-text); + /* PageFooter */ + --text-color-theme-pagefooter: var(--color-pagefooter-text); + --background-color-theme-pagefooter: var(--color-pagefooter-background); + /* TODO Border Color */ --border-theme-button-subdued: 1px solid var(--color-button-subdued-border); --border-theme-button-subdued-hover: var(--color-button-subdued-hover-border); @@ -715,6 +719,14 @@ /* LT Box Shadow */ --box-shadow-default: 0 1px 2px 0 rgba(34, 54, 73, 0.3); --box-shadow-hover: 0 0 0 1px var(--color-color-shadow, rgba(79, 79, 79, 0.3)), 0 2px 8px 0 rgba(0, 0, 0, 0.3); + /* LT PageFooter */ + --color-pagefooter-text: var(--color-text-light); + --color-pagefooter-background: var(--color-transparent); + --color-pagefooter-border: var(--color-border-default); + --color-pagefooter-title: var(--color-text-default); + --color-pagefooter-item-default: var(--color-text-light); + --color-pagefooter-item-hover: var(--color-text-light); + --color-pagefooter-item-active: var(--color-accent); } /* JUNO THEME: DARK MODE */ @@ -953,6 +965,14 @@ /* DT Box Shadow */ --box-shadow-default: 0 1px 2px 0 rgba(34, 54, 73, 0.3); --box-shadow-hover: 0 1px 2px 0 rgba(34, 54, 73, 0.3); + /* DT PageFooter */ + --color-pagefooter-text: var(--color-text-light); + --color-pagefooter-background: var(--color-transparent); + --color-pagefooter-border: var(--color-border-default); + --color-pagefooter-title: var(--color-text-default); + --color-pagefooter-item-default: var(--color-text-light); + --color-pagefooter-item-hover: var(--color-text-light); + --color-pagefooter-item-active: var(--color-accent); } /* From 8a053fe84275c7fc13cdb4affc3f6e5750d58c7c Mon Sep 17 00:00:00 2001 From: I531348 Date: Mon, 17 Nov 2025 07:50:38 +0100 Subject: [PATCH 02/12] footer imprv --- .../src/components/PageFooter/PageFooter.component.tsx | 5 +++-- .../src/components/PageFooter/page-footer.css | 10 ++++++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx b/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx index 945e25d1c3..bb81cd4fbe 100644 --- a/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx +++ b/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx @@ -17,7 +17,6 @@ const basePageFooterStyles = ` jn:px-6 jn:py-5 jn:border-t - jn:bg-theme-pagefooter jn:text-theme-pagefooter jn:bg-theme-pagefooter ` @@ -25,7 +24,9 @@ const basePageFooterStyles = ` export interface PageFooterProps extends React.HTMLAttributes { /** Additional custom styling class name for the footer container */ className?: string - /** The content to render inside the footer, typically links or informational text */ + /** The content to render inside the footer, typically links or informational text + * Use a list structure (e.g.,
    with
  • ) for grouped content or links, as in examples. + */ children?: React.ReactNode /** Optional copyright notice to display within the footer */ copyright?: string diff --git a/packages/ui-components/src/components/PageFooter/page-footer.css b/packages/ui-components/src/components/PageFooter/page-footer.css index 99b9f00053..47c40d78a6 100644 --- a/packages/ui-components/src/components/PageFooter/page-footer.css +++ b/packages/ui-components/src/components/PageFooter/page-footer.css @@ -1,4 +1,5 @@ .juno-pagefooter { + font-size: 0.875; padding: 1rem 2rem 0 2rem; border-color: var(--color-pagefooter-border); } @@ -25,20 +26,24 @@ position: relative; } -.juno-pagefooter-items-inline > li::after { +.juno-pagefooter-items-inline > li:not(:last-child)::after { content: "|"; margin-left: 0.38rem; margin-right: 0.38rem; - color: var(--color-pagefooter-item-default); } .juno-pagefooter-items-inline > li:last-child::after { content: ""; + margin-right: 0; } .juno-pagefooter-item { color: var(--color-pagefooter-item-default); flex: 1; + min-width: 12.5rem; + max-width: 21.875rem; + line-height: 1.25rem; + margin-bottom: 0.13rem; } .juno-pagefooter-item:hover { @@ -48,6 +53,7 @@ .juno-pagefooter-item:active { color: var(--color-pagefooter-item-active); + text-decoration: none; } .juno-pagefooter-children { From 5f2fbe459aefdc3317d012f1b0f73889bfc90f40 Mon Sep 17 00:00:00 2001 From: I531348 Date: Mon, 17 Nov 2025 07:54:18 +0100 Subject: [PATCH 03/12] doc imprv --- .../src/components/PageFooter/PageFooter.component.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx b/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx index bb81cd4fbe..e735655094 100644 --- a/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx +++ b/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx @@ -26,6 +26,11 @@ export interface PageFooterProps extends React.HTMLAttributes { className?: string /** The content to render inside the footer, typically links or informational text * Use a list structure (e.g.,
      with
    • ) for grouped content or links, as in examples. + * * Available CSS classes for styling: + * - `.juno-pagefooter-title`: Style for a title element within a column. + * - `.juno-pagefooter-items`: Style for a list of items. + * - `.juno-pagefooter-items-inline`: Style for a single line list with pipe separators. + * - `.juno-pagefooter-item`: Style for individual list items. */ children?: React.ReactNode /** Optional copyright notice to display within the footer */ From b56a169d083e2b67c042fb740327fc24d3ab4c98 Mon Sep 17 00:00:00 2001 From: I531348 Date: Mon, 17 Nov 2025 09:22:29 +0100 Subject: [PATCH 04/12] fix font size --- .../src/components/PageFooter/PageFooter.component.tsx | 4 ++-- .../ui-components/src/components/PageFooter/page-footer.css | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx b/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx index e735655094..42c923c91d 100644 --- a/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx +++ b/packages/ui-components/src/components/PageFooter/PageFooter.component.tsx @@ -25,8 +25,8 @@ export interface PageFooterProps extends React.HTMLAttributes { /** Additional custom styling class name for the footer container */ className?: string /** The content to render inside the footer, typically links or informational text - * Use a list structure (e.g.,
        with
      • ) for grouped content or links, as in examples. - * * Available CSS classes for styling: + * Use a list structure e.g. `
          ` with `
        • ` for grouped content or links, as in examples. + * Available CSS classes for styling: * - `.juno-pagefooter-title`: Style for a title element within a column. * - `.juno-pagefooter-items`: Style for a list of items. * - `.juno-pagefooter-items-inline`: Style for a single line list with pipe separators. diff --git a/packages/ui-components/src/components/PageFooter/page-footer.css b/packages/ui-components/src/components/PageFooter/page-footer.css index 47c40d78a6..3c9acc52f5 100644 --- a/packages/ui-components/src/components/PageFooter/page-footer.css +++ b/packages/ui-components/src/components/PageFooter/page-footer.css @@ -1,5 +1,5 @@ .juno-pagefooter { - font-size: 0.875; + font-size: 0.875rem; padding: 1rem 2rem 0 2rem; border-color: var(--color-pagefooter-border); } From fa6ed192191b54b245127bf31603b5ac0b884dd6 Mon Sep 17 00:00:00 2001 From: I531348 Date: Mon, 17 Nov 2025 09:25:57 +0100 Subject: [PATCH 05/12] changeset --- .changeset/great-peaches-drop.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .changeset/great-peaches-drop.md diff --git a/.changeset/great-peaches-drop.md b/.changeset/great-peaches-drop.md new file mode 100644 index 0000000000..6741e50aad --- /dev/null +++ b/.changeset/great-peaches-drop.md @@ -0,0 +1,9 @@ +--- +"@cloudoperators/juno-ui-components": minor +--- + +Feat: Add DescriptionList, DescriptionTerm, and DescriptionDefinition components + +- Implement HTML `
          `, `
          `, and `
          ` rendering for consistent metadata display. +- Provide alias exports (DL, DT, DD) for quicker usage. +- Enable flexible child handling with multi-node and grouping support. From 30bbcaf25f2202695c23a461df7c96b68b33a613 Mon Sep 17 00:00:00 2001 From: I531348 Date: Wed, 10 Dec 2025 17:11:33 +0100 Subject: [PATCH 06/12] pr suggestions --- .changeset/great-peaches-drop.md | 13 +++++++---- apps/example/src/App.tsx | 7 +++--- .../src/components/app-shell/Footer.tsx | 23 ------------------- .../PageFooter/PageFooter.stories.tsx | 12 ---------- packages/ui-components/src/global.css | 6 +++-- packages/ui-components/src/theme.css | 6 +++-- 6 files changed, 20 insertions(+), 47 deletions(-) delete mode 100644 apps/example/src/components/app-shell/Footer.tsx diff --git a/.changeset/great-peaches-drop.md b/.changeset/great-peaches-drop.md index 6741e50aad..0cb76d969a 100644 --- a/.changeset/great-peaches-drop.md +++ b/.changeset/great-peaches-drop.md @@ -1,9 +1,12 @@ --- -"@cloudoperators/juno-ui-components": minor +"@cloudoperators/juno-ui-components": major --- -Feat: Add DescriptionList, DescriptionTerm, and DescriptionDefinition components +Feat: Enhance `PageFooter` Component for Flexible Theming and Accessibility -- Implement HTML `
          `, `
          `, and `
          ` rendering for consistent metadata display. -- Provide alias exports (DL, DT, DD) for quicker usage. -- Enable flexible child handling with multi-node and grouping support. +- Customizable Branding: Removed hardcoded cloud illustration, allowing CSS-based branding customization. +- Conditional Copyright Notice: Added a `copyright` prop for optional right-side rendering. +- Responsive Grid Layout: Updated `children` rendering to support single/multiple items with defined spacing. +- Accessibility Improvements: Integrated ARIA roles and attributes (role="group", aria-labelledby) for better semantic clarity. +- Theming Consistency: Implemented design tokens, accommodating `light` and `dark` modes. +- Integration: Added `PageFooter` to Example App. diff --git a/apps/example/src/App.tsx b/apps/example/src/App.tsx index 05123a606a..9bb3758ea6 100644 --- a/apps/example/src/App.tsx +++ b/apps/example/src/App.tsx @@ -6,11 +6,10 @@ import React, { useEffect, useMemo } from "react" import { QueryClient, QueryClientProvider } from "@tanstack/react-query" import { MessagesProvider } from "@cloudoperators/juno-messages-provider" -import { AppShell, AppShellProvider } from "@cloudoperators/juno-ui-components" +import { AppShell, AppShellProvider, PageFooter } from "@cloudoperators/juno-ui-components" import useAuthStore from "./store/useAuthStore" import AsyncWorker from "./components/AsyncWorker" -import Footer from "./components/app-shell/Footer" import useConfigStore from "./store/useConfigStore" import Content from "./components/app-shell/Content" import Header from "./components/app-shell/header/Header" @@ -32,13 +31,15 @@ const App: React.FC = ({ endpoint = "", id = "" }) => { setEndpoint(endpoint) }, [endpoint]) + const COPYRIGHT_TEXT = "Copyright © 2024 SAP SE, SAP affiliates and Juno contributors" + return ( } sideNavigation={isUserAuthenticated ? : null} - pageFooter={