Skip to content

Commit

Permalink
Add widget breadcrumb (#736)
Browse files Browse the repository at this point in the history
* Add widget breadcrumb

* Fix linting issues

* Apply eslint-fixer changes

* Fix border-color token

* Automatic frontend build

---------

Co-authored-by: vin0401 <[email protected]>
  • Loading branch information
vin0401 and vin0401 authored Nov 25, 2024
1 parent bc2fea8 commit 4671ccb
Show file tree
Hide file tree
Showing 46 changed files with 2,370 additions and 122 deletions.
36 changes: 26 additions & 10 deletions assets/js/src/core/components/breadcrumb/breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Text } from '@Pimcore/components/text/text'
import { useBreadcrumbSize } from './hooks/use-breadcrumb-size'
import { type ElementType } from 'types/element-type.d'
import { useStyle } from './breadcrumb.styles'
import { Filename } from '../filename/filename'

interface BreadcrumbProps {
path: string
Expand All @@ -32,6 +33,7 @@ interface BreadcrumbProps {

export const Breadcrumb = ({ path, elementType, editorTabsWidth, pageSize }: BreadcrumbProps): React.JSX.Element => {
const dispatch = useAppDispatch()
const hasFilename = elementType === 'asset'

const [initialBreadcrumbLastElementWidth, setInitialBreadcrumbLastElementWidth] = useState<number>(0)

Expand Down Expand Up @@ -77,15 +79,28 @@ export const Breadcrumb = ({ path, elementType, editorTabsWidth, pageSize }: Bre
}

// Generate the breadcrumb text with ellipsis
const generateBreadcrumbText = ({ content, style, className }: { content: string, style?: CSSProperties, className?: string }): ReactElement => (
<Text
className={ cn(styles.breadcrumbLink, className) }
ellipsis={ { tooltip: { title: content, placement: 'top' } } }
style={ style }
>
{content}
</Text>
)
const generateBreadcrumbText = ({ content, style, className, hasFilename = false }: { content: string, style?: CSSProperties, className?: string, hasFilename?: boolean }): ReactElement => {
if (hasFilename) {
return (
<Filename
className={ cn(styles.breadcrumbLink, className) }
ellipsis
style={ style }
value={ content }
/>
)
}

return (
<Text
className={ cn(styles.breadcrumbLink, className) }
ellipsis={ { tooltip: { title: content } } }
style={ style }
>
{content}
</Text>
)
}

// Prepend the "..." menu to the existing items array
const addDotsMenu = ({ dotsMenuItems, items }: { dotsMenuItems: MenuItemProps[], items: BreadcrumbItemType[] }): ItemType[] => [
Expand Down Expand Up @@ -146,7 +161,8 @@ export const Breadcrumb = ({ path, elementType, editorTabsWidth, pageSize }: Bre
{generateBreadcrumbText({
content: partList[partListAmount - 1],
style: { ...(isHideBreadcrumb && { maxWidth: `${currentBreadcrumbWidth}px` }) },
className: styles.breadcrumbLinkLast
className: styles.breadcrumbLinkLast,
hasFilename
})}
</span>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import { ContentToolbarSidebarLayout } from '@Pimcore/components/content-toolbar-sidebar-layout/content-toolbar-sidebar-layout'
import { ContentLayout } from '@Pimcore/components/content-layout/content-layout'
import { Sidebar } from '@Pimcore/components/sidebar/sidebar'
import { HighlightedEntries as sidebarArgs } from '@Pimcore/components/sidebar/sidebar.stories'
import { Toolbar, type ToolbarProps } from '@Pimcore/components/toolbar/toolbar'
import { Secondary } from '@Pimcore/components/toolbar/toolbar.stories'
import { Position, Secondary } from '@Pimcore/components/toolbar/toolbar.stories'
import { type Meta } from '@storybook/react'
import React from 'react'
import { Content } from '../content/content'

/* eslint-disable react/jsx-key */
const config: Meta = {
title: 'Components/layout/Content-Toolbar-Sidebar-Layout',
component: ContentToolbarSidebarLayout,
title: 'Components/layout/Content-Layout',
component: ContentLayout,
parameters: {
layout: 'fullscreen',

Expand All @@ -38,6 +38,7 @@ export default config

const demoData = {
children: <Content none />,
renderTopBar: <Toolbar { ...Position.args as ToolbarProps } />,
renderToolbar: <Toolbar { ...Secondary.args as ToolbarProps } />,
renderSidebar: <Sidebar { ...sidebarArgs.args } />
}
Expand All @@ -61,3 +62,10 @@ export const NoSidebar = {
renderSidebar: undefined
}
}

export const NoTopBar = {
args: {
...demoData,
renderTopBar: undefined
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,39 +15,47 @@ import { createStyles } from 'antd-style'

export const useStyles = createStyles(({ token, css }) => {
return {
ContentToolbarSidebarLayout: css`
ContentLayout: css`
&.content-toolbar-sidebar-layout {
position: relative;
display: grid;
grid-template-columns: 1fr auto;
grid-template-rows: 1fr auto;
grid-template-rows: auto 1fr auto;
height: 100%;
width: 100%;
overflow: hidden;
}
.content-toolbar-sidebar-layout__top-bar {
grid-column: 1 / 2;
grid-row: 1 / 2;
position: sticky;
bottom: 0;
height: max-content;
overflow: hidden;
}
.content-toolbar-sidebar-layout__content {
display: flex;
grid-column: 1 / 2;
grid-row: 1 / 2;
grid-row: 2 / 3;
overflow: auto;
height: 100%;
width: 100%;
}
.content-toolbar-sidebar-layout__toolbar {
border-top: 1px solid ${token.colorBorderTertiary};
grid-column: 1 / 2;
grid-row: 2 / 3;
grid-row: 3 / 4;
position: sticky;
bottom: 0;
height: ${token.sizeXXL}px;
height: max-content;
overflow: hidden;
}
.content-toolbar-sidebar-layout__sidebar {
grid-column: 2 / 3;
grid-row: 1 / 3;
grid-row: 1 / 4;
}
`
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,32 @@
*/

import React, { memo, type ReactNode } from 'react'
import { useStyles } from './content-toolbar-sidebar-layout.styles'
import { useStyles } from './content-layout.styles'
import { Content } from '../content/content'

interface ContentToolbarViewProps {
children: ReactNode
renderToolbar?: ReactNode
renderTopBar?: ReactNode
renderSidebar?: ReactNode
renderToolbar?: ReactNode
}

const Component = (props: ContentToolbarViewProps): React.JSX.Element => {
const { styles } = useStyles()
const classes = ['content-toolbar-sidebar-layout', styles.ContentToolbarSidebarLayout]
const classes = ['content-toolbar-sidebar-layout', styles.ContentLayout]

if (props.renderToolbar !== undefined) {
classes.push('content-toolbar-sidebar-layout--with-toolbar')
}

return (
<div className={ classes.join(' ') }>
{ props.renderTopBar !== undefined && (
<div className='content-toolbar-sidebar-layout__top-bar'>
{props.renderTopBar}
</div>
)}

<Content className='content-toolbar-sidebar-layout__content'>
{props.children}
</Content>
Expand All @@ -50,4 +57,4 @@ const Component = (props: ContentToolbarViewProps): React.JSX.Element => {
)
}

export const ContentToolbarSidebarLayout = memo(Component)
export const ContentLayout = memo(Component)
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,6 @@ export const useStyle = createStyles(({ token, css }) => {
display: flex;
align-items: center;
gap: 8px;
height: 40px;
border-bottom: 1px solid #DFD7EA;
.ant-breadcrumb {
padding-left: ${token.paddingXS}px;
}
.element-toolbar__info-dropdown {
.ant-dropdown-trigger {
Expand Down
37 changes: 37 additions & 0 deletions assets/js/src/core/components/filename/filename.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import { type StoryObj, type Meta } from '@storybook/react'
import { Filename, type FilenameProps } from './filename'

const config: Meta = {
title: 'Components/Data Display/Filename',
component: Filename,
tags: ['autodocs']
}

export default config

export const _default: StoryObj<FilenameProps> = {
args: {
value: 'filename.jpg',
ellipsis: false
}
}

export const Ellipsis = {
args: {
value: 'Lorem-ipsum-dolor-sit-amet-consetetur-sadipscing-elitr-sed-diam-nonumy-eirmod-tempor-invidunt-ut-labore-et-dolore-magna-aliquyam-erat-sed-diam-voluptua.jpg',
ellipsis: true
}
}
49 changes: 49 additions & 0 deletions assets/js/src/core/components/filename/filename.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import React from 'react'
import { Text } from '../text/text'
import { Flex } from '../flex/flex'

export interface FilenameProps extends React.HTMLAttributes<HTMLDivElement> {
value: string
ellipsis?: boolean
}

export const Filename = ({ value, ellipsis, ...props }: FilenameProps): React.JSX.Element => {
const filename = value
const hasExtension = filename.includes('.')

if (hasExtension && ellipsis === true) {
const parts = filename.split('.')
const extension = parts.pop()
const name = parts.join('.')

return (
<Flex { ...props }>
<Text
ellipsis={ ellipsis ? { tooltip: { title: filename, overlayStyle: { maxWidth: 'min(100%, 500px)' }, mouseEnterDelay: 0.3 } } : false }
style={ { color: 'inherit' } }
>{name}</Text>.
<Text style={ { whiteSpace: 'nowrap', color: 'inherit' } }>{extension}</Text>
</Flex>
)
}

return (
<Text
ellipsis={ ellipsis }
{ ...props }
>{ filename }</Text>
)
}
2 changes: 2 additions & 0 deletions assets/js/src/core/components/modal/modal.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ export const Large = (): React.JSX.Element => {
</Button>
</ModalFooter>
}
mask={ false }
maskClosable={ false }
onCancel={ handleClose }
open={ isOpen }
size='L'
Expand Down
33 changes: 33 additions & 0 deletions assets/js/src/core/components/toolbar/toolbar.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { Toolbar } from '@Pimcore/components/toolbar/toolbar'
import { type StoryObj, type Meta } from '@storybook/react'
import { Button } from '@Pimcore/components/button/button'
import React from 'react'
import { Breadcrumb } from '../breadcrumb/breadcrumb'
import { _default as breadcrumbStory } from '../breadcrumb/breadcrumb.stories'

const config: Meta = {
title: 'Components/Controls/Toolbar',
Expand Down Expand Up @@ -73,6 +75,37 @@ export const Secondary: Story = {
}
}

export const Size: Story = {
args: {
children: (
<>
<Breadcrumb
{ ...breadcrumbStory.args }
elementType='asset'
/>
</>
),
size: 'small',
theme: 'secondary'
}
}

export const Position: Story = {
args: {
children: (
<>
<Breadcrumb
{ ...breadcrumbStory.args }
elementType='asset'
/>
</>
),
position: 'top',
size: 'small',
theme: 'secondary'
}
}

export const RightAligned: Story = {
args: {
...demoData,
Expand Down
14 changes: 12 additions & 2 deletions assets/js/src/core/components/toolbar/toolbar.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ export const useStyles = createStyles(({ token, css }) => {
toolbar: css`
width: 100%;
height: 48px;
border-top: 1px solid ${token.colorBorder};
padding: ${token.paddingXS}px;
&.toolbar--theme-primary {
Expand All @@ -30,6 +28,18 @@ export const useStyles = createStyles(({ token, css }) => {
&.toolbar--theme-secondary {
background-color: ${token.colorBgBase};
}
&.toolbar--position-top {
border-bottom: 1px solid ${token.colorBorderTertiary};
}
&.toolbar--position-bottom {
border-top: 1px solid ${token.colorBorderTertiary};
}
&.toolbar--size-small {
height: 40px;
}
`
}
})
Loading

0 comments on commit 4671ccb

Please sign in to comment.