generated from gravity-ui/package-example
-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(Gallery): add Gallery and FilesGallery components
- Loading branch information
kseniyakuzina
committed
Dec 19, 2024
1 parent
b855931
commit 8c07955
Showing
42 changed files
with
1,461 additions
and
11 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
@use '../variables'; | ||
|
||
$block: '.#{variables.$ns}files-gallery'; | ||
|
||
$filePreviewBlock: '.#{variables.$ns}file-preview'; | ||
|
||
#{$block} { | ||
&__active-item-info { | ||
align-self: center; | ||
} | ||
|
||
&__file-preview { | ||
&[class] { | ||
width: 100%; | ||
height: 100%; | ||
} | ||
|
||
#{$filePreviewBlock}__card { | ||
width: 100%; | ||
min-width: 100%; | ||
height: 100%; | ||
padding: 0; | ||
} | ||
|
||
#{$filePreviewBlock}__image, | ||
#{$filePreviewBlock}__icon { | ||
width: 100%; | ||
height: 100%; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import React from 'react'; | ||
|
||
import {ChevronsCollapseUpRight, ChevronsExpandUpRight} from '@gravity-ui/icons'; | ||
import {ActionTooltip, Button, Icon} from '@gravity-ui/uikit'; | ||
|
||
import {Gallery, GalleryProps} from '../Gallery'; | ||
import {block} from '../utils/cn'; | ||
|
||
import {useFullScreen} from './hooks/useFullScreen'; | ||
import {i18n} from './i18n'; | ||
import {GalleryFileBase} from './types'; | ||
import {renderActiveItemInfo} from './utils/renderActiveItemInfo'; | ||
import {renderItemPreview} from './utils/renderItemPreview'; | ||
|
||
import './FilesGallery.scss'; | ||
|
||
export const cnFilesGallery = block('files-gallery'); | ||
|
||
export type FilesGalleryProps<GalleryFileType extends GalleryFileBase> = Omit< | ||
GalleryProps<GalleryFileType>, | ||
'fullScreen' | 'renderItemPreview' | 'renderActiveItemInfo' | ||
> & {}; | ||
|
||
export const FilesGallery = <GalleryFileType extends GalleryFileBase>({ | ||
renderActions: providedRenderActions, | ||
activeItemInfoClassName, | ||
...galleryProps | ||
}: FilesGalleryProps<GalleryFileType>) => { | ||
const {fullScreen, handleSwitchFullScreenMode} = useFullScreen(); | ||
|
||
const renderActions = React.useCallback< | ||
NonNullable<GalleryProps<GalleryFileType>['renderActions']> | ||
>( | ||
(item) => { | ||
return ( | ||
<React.Fragment> | ||
{providedRenderActions?.(item)} | ||
<ActionTooltip | ||
title={fullScreen ? i18n('exit-full-screen') : i18n('enter-full-screen')} | ||
hotkey="Shift+F" | ||
> | ||
<Button | ||
size="l" | ||
view="flat" | ||
extraProps={{ | ||
'aria-label': fullScreen | ||
? i18n('exit-full-screen') | ||
: i18n('enter-full-screen'), | ||
}} | ||
onClick={handleSwitchFullScreenMode} | ||
> | ||
<Icon | ||
data={fullScreen ? ChevronsCollapseUpRight : ChevronsExpandUpRight} | ||
/> | ||
</Button> | ||
</ActionTooltip> | ||
</React.Fragment> | ||
); | ||
}, | ||
[fullScreen, handleSwitchFullScreenMode, providedRenderActions], | ||
); | ||
|
||
return ( | ||
<Gallery<GalleryFileType> | ||
fullScreen={fullScreen} | ||
renderItemPreview={renderItemPreview} | ||
renderActions={renderActions} | ||
renderActiveItemInfo={renderActiveItemInfo} | ||
activeItemInfoClassName={cnFilesGallery('active-item-info', activeItemInfoClassName)} | ||
{...galleryProps} | ||
/> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
## FilesGallery | ||
|
||
The component for rendering file galleries. | ||
The component is responsible for the gallery navigation (keyboard arrows, body side click and header arrow click). | ||
You should provide the renderers for the body and file actions, for example the copy link action and the download action. | ||
|
||
### PropTypes | ||
|
||
| Property | Type | Required | Values | Default | Description | | ||
| :---------------------- | :------------------------------------------------- | :------- | :----- | :------ | :---------------------------------------------------- | | ||
| items | `(GalleryFileType extends GalleryFileBase)[]` | Yes | | | The gallery items list | | ||
| initialItemIndex | `Number` | | | 0 | The initial active item index | | ||
| open | `Boolean` | | | | The modal opened state | | ||
| onClose | `() => void` | Yes | | | The modal close handler | | ||
| renderActions | `(activeItem: GalleryFileType) => React.ReactNode` | | | | The gallery actions renderer, accepts the active item | | ||
| renderBody | `(activeItem: GalleryFileType) => React.ReactNode` | Yes | | | The gallery body renderer, accepts the active item | | ||
| modalClassName | `String` | | | | The modal class | | ||
| className | `String` | | | | The modal content class | | ||
| headerClassName | `String` | | | | The gallery header class | | ||
| activeItemInfoClassName | `String` | | | | The active item info class name | | ||
| footerClassName | `String` | | | | The gallery footer class | | ||
| bodyClassName | `String` | | | | The gallery body class | | ||
|
||
### Examples | ||
|
||
```tsx | ||
import { | ||
FilesGallery, | ||
FilesGalleryFallbackText, | ||
ImageFileView, | ||
VideoFileView, | ||
DocumentFileView, | ||
} from '@gravity-ui/components'; | ||
|
||
const FilesGalleryShowcase = () => { | ||
const [open, setOpen] = React.useState(false); | ||
|
||
const container = usePortalContainer(); | ||
|
||
const handleClose = React.useCallback(() => { | ||
setOpen(false); | ||
}, []); | ||
|
||
const handleOpen = React.useCallback(() => { | ||
setOpen(true); | ||
}, []); | ||
|
||
const renderBody = React.useCallback((activeFile: GalleryFile) => { | ||
switch (activeFile.type) { | ||
case 'image': { | ||
return <ImageFileView src={activeFile.url} />; | ||
} | ||
case 'video': { | ||
return <VideoFileView src={activeFile.url} />; | ||
} | ||
case 'document': { | ||
return <DocumentFileView name={activeFile.data.name} src={activeFile.url} />; | ||
} | ||
case 'text': { | ||
return <Text variant="body-1">{activeFile.text}</Text>; | ||
} | ||
default: { | ||
return <FilesGalleryFallbackText />; | ||
} | ||
} | ||
}, []); | ||
|
||
const renderActions = React.useCallback((activeFile: GalleryFile) => { | ||
return ( | ||
<React.Fragment> | ||
<CopyToClipboard text={'url' in activeFile ? activeFile.url : activeFile.text}> | ||
{() => ( | ||
<div> | ||
<ActionTooltip title="Copy link"> | ||
<Button | ||
size="l" | ||
view="flat" | ||
extraProps={{ | ||
'aria-label': 'Copy link', | ||
}} | ||
> | ||
<Icon data={Link} /> | ||
</Button> | ||
</ActionTooltip> | ||
</div> | ||
)} | ||
</CopyToClipboard> | ||
{'url' in activeFile && ( | ||
<ActionTooltip title="Download"> | ||
<Button | ||
size="l" | ||
view="flat" | ||
extraProps={{ | ||
'aria-label': 'download', | ||
}} | ||
onClick={(event) => event.stopPropagation()} | ||
href={`${activeFile.url}?inline=false`} | ||
target="_blank" | ||
rel="noreferrer" | ||
> | ||
<Icon data={ArrowDownToLine} /> | ||
</Button> | ||
</ActionTooltip> | ||
)} | ||
</React.Fragment> | ||
); | ||
}, []); | ||
|
||
return ( | ||
<React.Fragment> | ||
<Button onClick={handleOpen} view="action" size="l"> | ||
Open gallery | ||
</Button> | ||
<FilesGallery<GalleryFile> | ||
theme="dark" | ||
open={open} | ||
onClose={handleClose} | ||
container={container || undefined} | ||
items={files} | ||
renderBody={renderBody} | ||
renderActions={renderActions} | ||
/> | ||
</React.Fragment> | ||
); | ||
}; | ||
``` |
Oops, something went wrong.