Skip to content

eclipse-tractusx/portal-shared-components

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Catena-X Portal Shared UI Components

Contains the Shared UI Components that are used to build the Portal Frontend and other applications in the Catena-X ecosystem.

User documentation

To use components in your own project follow this guide. First create a new react app and add dependencies for the library and Material UI. We are using yarn and TypeScript, if you prefer a different setup like npm/npx or JavaScript there are other templates available.

yarn create vite sample-shared-components --template react-ts
cd sample-shared-components
yarn add @catena-x/portal-shared-components @mui/icons-material @mui/material

Then start the development server and open the browser

yarn dev
# press o + enter

Check the default Vite React App in your browser which shows a button counting the number of times it has been clicked. Now let's modify this App so it's using the Shared Components instead of default HTML elements.

Edit src/main.tsx to import and wrap the App with the Catena-X SharedThemeProvider context.

+ import { SharedThemeProvider } from '@catena-x/portal-shared-components'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
+   <SharedThemeProvider>
      <App />
+   </SharedThemeProvider>
  </React.StrictMode>,
)

Open src/App.tsx to import the Button component and replace the default button with it.

+ import { Button } from '@catena-x/portal-shared-components'
...
-   <button ...>
+   <Button ...>
...
-   </button>
+   </Button>

Then check in your browser how the appearance of the button has changed from a dark more rectangle shaped to a larger blue more rounded one. However the behavior of the button hasn't changed.

Now let's have a look at a more complex example. In a first step we remove the stylings because the components are coming with Catena-X UI styling presets.

Remove the css import from src/main.tsx

+ import './index.css'

Add two more libraries

yarn add amount-to-words @javascript-packages/roman-numerals

Then edit src/App.tsx again and overwrite the content with this example.

import { useState } from 'react'
import { Button, Cards, ViewSelector } from '@catena-x/portal-shared-components'
import { numberToWords } from 'amount-to-words'
import { toRoman } from '@javascript-packages/roman-numerals'

const isPrime = (num: number) => {
    for (let i = 2, s = Math.sqrt(num); i <= s; i++)
        if (num % i === 0)
            return false
    return num > 1
}

enum ViewType {
    ALL = 'ALL',
    ODD = 'ODD',
    EVEN = 'EVEN',
    PRIME = 'PRIME',
}

const viewFilter: Record<ViewType, (n: number) => boolean> = {
    ALL: () => true,
    ODD: (n) => n % 2 === 1,
    EVEN: (n) => n % 2 === 0,
    PRIME: isPrime,
}

const svgtext = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" style="background-color:green"><style>text{font:36px bold;stroke-linejoin:round;stroke:#ffa600;fill:#b3cb2d;text-anchor:middle;dominant-baseline:middle;stroke-width:4px;paint-order:stroke;}</style><text x="32" y="36">N</text></svg>'

const generateImage = (n: number) => `data:image/svg+xml,${encodeURIComponent(svgtext.replace('N', n.toString()))}`

const generateCard = (n: number) => ({
    title: numberToWords(n),
    subtitle: n === 0 ? '0' : toRoman(n),
    subscriptionStatus: isPrime(n) ? 'Prime' : undefined,
    description: 'This is a description of the card',
    image: {
        src: generateImage(n),
    }
})

const cardsArgs = {
    variant: 'compact',
    expandOnHover: true,
    imageSize: 'medium',
    imageShape: 'round',
    buttonText: 'View',
}

export default function App() {
    const [count, setCount] = useState<number>(1)
    const [view, setView] = useState<ViewType>(ViewType.ALL)

    return (
        <>
            <Button onClick={() => { setCount(() => count + 1) }}> count is {count} </Button>
            <ViewSelector views={
                Object.keys(ViewType)
                    .map(
                        (buttonText) => ({
                            buttonText,
                            buttonValue: buttonText,
                            onButtonClick: (e: React.MouseEvent) => { setView(e.target.value as ViewType) },
                        })
                    )
            }
                activeView={view}
            />
            <Cards {...cardsArgs} items={
                new Array(count)
                    .fill(0)
                    .map((_, i) => i)
                    .filter(viewFilter[view])
                    .map(generateCard)
            } />
        </>
    )
}

This example shows several components working together. Every button click adds a new card for that number and you can filter the cards by various criteria.

Developer documentation

Steps to run local storybook and dev server

yarn
yarn start:storybook
yarn start:dev

License

Distributed under the Apache 2.0 License. See LICENSE for more information.