-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #88 from nebulabroadcast/87-friendlier-buttons-in-…
…the-asset-editor-navbar Friendlier asset editor navbar
- Loading branch information
Showing
8 changed files
with
318 additions
and
231 deletions.
There are no files selected for viewing
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,48 @@ | ||
import styled from 'styled-components' | ||
|
||
import { forwardRef } from 'react' | ||
import clsx from 'clsx' | ||
|
||
import Button from './Button' | ||
|
||
const RadioContainer = styled.div` | ||
display: flex; | ||
gap: 1px; | ||
button { | ||
border-radius: 0; | ||
border-right: 0; | ||
border-top-right-radius: 0; | ||
border-bottom-right-radius: 0; | ||
&:first-child { | ||
border-top-left-radius: 4px; | ||
border-bottom-left-radius: 4px; | ||
} | ||
&:last-child { | ||
border-top-right-radius: 4px; | ||
border-bottom-right-radius: 4px; | ||
} | ||
` | ||
|
||
const RadioButton = ({ options, value, onChange }) => { | ||
return ( | ||
<RadioContainer> | ||
{options.map((option) => ( | ||
<Button | ||
key={option.value} | ||
onClick={() => onChange(option.value)} | ||
className={clsx({ active: option.value === value })} | ||
icon={option.icon} | ||
label={option.label} | ||
tooltip={option.tooltip} | ||
style={option.buttonStyle} | ||
/> | ||
))} | ||
</RadioContainer> | ||
) | ||
} | ||
|
||
export default RadioButton |
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,180 @@ | ||
import nebula from '/src/nebula' | ||
|
||
import { useDispatch } from 'react-redux' | ||
import { useState, useMemo } from 'react' | ||
import { | ||
setCurrentViewId, | ||
setSearchQuery, | ||
showSendToDialog, | ||
} from '/src/actions' | ||
|
||
import { | ||
Navbar, | ||
Button, | ||
Spacer, | ||
Dropdown, | ||
ToolbarSeparator, | ||
InputTimecode, | ||
Dialog, | ||
} from '/src/components' | ||
|
||
import { UploadButton } from '/src/containers/Upload' | ||
|
||
import MetadataDetail from './MetadataDetail' | ||
import ContextActionResult from './ContextAction' | ||
import AssigneesButton from './AssigneesButton' | ||
|
||
import contentType from 'content-type' | ||
|
||
const AssetEditorNav = ({ assetData, setMeta, enabledActions }) => { | ||
const [detailsVisible, setDetailsVisible] = useState(false) | ||
const [contextActionResult, setContextActionResult] = useState(null) | ||
const dispatch = useDispatch() | ||
|
||
const currentFolder = useMemo(() => { | ||
if (!nebula.settings.folders) return null | ||
for (const f of nebula.settings.folders) { | ||
if (f.id !== assetData?.id_folder) continue | ||
return f | ||
} | ||
}, [{ ...assetData }]) | ||
|
||
const folderOptions = useMemo(() => { | ||
return nebula.getWritableFolders().map((f) => ({ | ||
label: f.name, | ||
style: { borderLeft: `4px solid ${f.color}` }, | ||
onClick: () => setMeta('id_folder', f.id), | ||
})) | ||
}, []) | ||
|
||
// Actions | ||
|
||
const scopedEndpoints = useMemo(() => { | ||
const result = [] | ||
for (const scopedEndpoints of nebula.getScopedEndpoints('asset')) { | ||
result.push({ | ||
label: scopedEndpoints.title, | ||
onClick: () => { | ||
nebula | ||
.request(scopedEndpoints.endpoint, { id_asset: assetData.id }) | ||
.then((response) => { | ||
setContextActionResult({ | ||
contentType: contentType.parse(response.headers['content-type']) | ||
.type, | ||
payload: response.data, | ||
}) | ||
}) | ||
}, | ||
}) | ||
} | ||
return result | ||
}, [assetData.id]) | ||
|
||
const linkOptions = useMemo(() => { | ||
if (!currentFolder) return [] | ||
|
||
return currentFolder.links.map((l) => ({ | ||
label: l.name, | ||
disabled: !assetData[l['source_key']], | ||
onClick: () => { | ||
const query = `${l['target_key']}:${assetData[l['source_key']]}` | ||
dispatch(setCurrentViewId(l.view)) | ||
dispatch(setSearchQuery(query)) | ||
}, | ||
})) | ||
}, [currentFolder]) | ||
|
||
const assetActions = useMemo(() => { | ||
const result = [ | ||
{ | ||
label: 'Send to...', | ||
onClick: () => dispatch(showSendToDialog({ ids: [assetData.id] })), | ||
}, | ||
...scopedEndpoints, | ||
...linkOptions, | ||
] | ||
if (result.length > 1) { | ||
result[1].separator = true | ||
} | ||
return result | ||
}, [scopedEndpoints, linkOptions]) | ||
|
||
// End actions | ||
|
||
const fps = useMemo(() => { | ||
if (!assetData) return 25 | ||
return assetData['video/fps_f'] || 25 | ||
}, [assetData['video/fps_f']]) | ||
|
||
return ( | ||
<Navbar> | ||
{detailsVisible && ( | ||
<Dialog | ||
style={{ height: '80%', width: '80%' }} | ||
onHide={() => setDetailsVisible(false)} | ||
> | ||
<MetadataDetail assetData={assetData} /> | ||
</Dialog> | ||
)} | ||
|
||
{contextActionResult && ( | ||
<ContextActionResult | ||
mime={contextActionResult.contentType} | ||
payload={contextActionResult.payload} | ||
onHide={() => setContextActionResult(null)} | ||
/> | ||
)} | ||
|
||
<Dropdown | ||
options={folderOptions} | ||
buttonStyle={{ | ||
borderLeft: ` 4px solid ${currentFolder?.color}`, | ||
minWidth: 130, | ||
width: 130, | ||
}} | ||
label={currentFolder?.name || 'no folder'} | ||
disabled={!enabledActions.folderChange} | ||
/> | ||
|
||
<InputTimecode | ||
value={assetData?.duration} | ||
fps={fps} | ||
onChange={(val) => setMeta('duration', val)} | ||
tooltip="Asset duration" | ||
readOnly={assetData.status || !enabledActions.edit} | ||
/> | ||
|
||
<ToolbarSeparator /> | ||
|
||
{enabledActions.advanced && ( | ||
<AssigneesButton | ||
assignees={assetData?.assignees || []} | ||
setAssignees={(val) => setMeta('assignees', val)} | ||
/> | ||
)} | ||
|
||
<Spacer /> | ||
|
||
{enabledActions.advanced && ( | ||
<> | ||
<Dropdown | ||
options={assetActions} | ||
disabled={!enabledActions.actions} | ||
label="Actions" | ||
/> | ||
<Button | ||
icon="manage_search" | ||
label="Details" | ||
onClick={() => setDetailsVisible(true)} | ||
/> | ||
</> | ||
)} | ||
|
||
{nebula.settings?.system?.ui_asset_upload && ( | ||
<UploadButton assetData={assetData} disabled={!enabledActions.upload} /> | ||
)} | ||
</Navbar> | ||
) | ||
} | ||
|
||
export default AssetEditorNav |
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
Oops, something went wrong.