mirror of
https://github.com/mattermost/focalboard.git
synced 2024-12-24 13:43:12 +02:00
Updating board template picker ui (#4209)
* Updating board template picker ui * Updating UI * Updating UI * Updating UI * Updating modal * Updating css * Updating new template screen * Updating css * Updating css * Updating padding
This commit is contained in:
parent
20d8d7a0ab
commit
9ab0291cb7
@ -16,7 +16,7 @@
|
||||
"BoardMember.unlinkChannel": "Unlink",
|
||||
"BoardPage.newVersion": "A new version of Boards is available, click here to reload.",
|
||||
"BoardPage.syncFailed": "Board may be deleted or access revoked.",
|
||||
"BoardTemplateSelector.add-template": "New template",
|
||||
"BoardTemplateSelector.add-template": "Create new template",
|
||||
"BoardTemplateSelector.create-empty-board": "Create empty board",
|
||||
"BoardTemplateSelector.delete-template": "Delete",
|
||||
"BoardTemplateSelector.description": "Add a board to the sidebar using any of the templates defined below or start from scratch.",
|
||||
@ -422,4 +422,4 @@
|
||||
"tutorial_tip.ok": "Next",
|
||||
"tutorial_tip.out": "Opt out of these tips.",
|
||||
"tutorial_tip.seen": "Seen this before?"
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,118 +1,175 @@
|
||||
@import '../../styles/z-index';
|
||||
|
||||
.BoardTemplateSelector__container {
|
||||
@include z-index(modal-permissions-label);
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 120px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
@media (max-height: 900) {
|
||||
padding: 80px;
|
||||
}
|
||||
}
|
||||
|
||||
.BoardTemplateSelector__container--page {
|
||||
position: absolute;
|
||||
padding: 0;
|
||||
|
||||
.BoardTemplateSelector {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.BoardTemplateSelector__backdrop {
|
||||
background-color: rgba(0, 0, 0, 0.56);
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.BoardTemplateSelector {
|
||||
@include z-index(board-template-selector);
|
||||
position: absolute;
|
||||
position: relative;
|
||||
background-color: rgb(var(--center-channel-bg-rgb));
|
||||
border: 1px solid rgba(var(--center-channel-color-rgb), 0.16);
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
padding-bottom: 48px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-radius: 12px;
|
||||
max-width: 1600px;
|
||||
max-height: 1200px;
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: flex-end;
|
||||
padding: 24px;
|
||||
padding: 20px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
padding: 32px;
|
||||
border-bottom: 1px solid rgba(var(--center-channel-color-rgb), 0.16);
|
||||
|
||||
.title {
|
||||
font-size: 25px;
|
||||
font-size: 22px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.description {
|
||||
max-width: 640px;
|
||||
text-align: center;
|
||||
margin: 0 0 32px;
|
||||
color: rgba(var(--center-channel-color-rgb), 0.56);
|
||||
border-left: 1px solid rgba(var(--center-channel-color-rgb), 0.08);
|
||||
padding-left: 8px;
|
||||
margin: 0 0 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.templates-sidebar {
|
||||
flex: 0 0 294px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
background-color: rgba(var(--center-channel-color-rgb), 0.04);
|
||||
border-right: 1px solid rgba(var(--center-channel-color-rgb), 0.08);
|
||||
}
|
||||
|
||||
.templates-sidebar__footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-top: 1px solid rgba(var(--center-channel-color-rgb), 0.16);
|
||||
padding: 24px;
|
||||
height: 89px;
|
||||
|
||||
button {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.templates__empty-board {
|
||||
color: rgb(var(--button-bg-rgb));
|
||||
padding: 0;
|
||||
border: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: transparent;
|
||||
font-weight: 600;
|
||||
gap: 10px;
|
||||
|
||||
i {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.templates {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 0 32px;
|
||||
justify-content: center;
|
||||
|
||||
@media (min-width: 768px) {
|
||||
padding: 0 10%;
|
||||
}
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
|
||||
.templates-list {
|
||||
margin-right: 32px;
|
||||
width: 300px;
|
||||
max-height: 500px;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
|
||||
.new-template {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 16px;
|
||||
margin-bottom: 4px;
|
||||
border-radius: var(--default-rad);
|
||||
cursor: pointer;
|
||||
|
||||
.template-icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(var(--center-channel-color-rgb), 0.1);
|
||||
}
|
||||
width: 100%;
|
||||
justify-content: flex-start;
|
||||
padding-left: 14px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.templates-content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
padding: 24px;
|
||||
justify-content: flex-end;
|
||||
height: 89px;
|
||||
border-top: 1px solid rgba(var(--center-channel-color-rgb), 0.16);
|
||||
background-color: rgb(var(--center-channel-bg-rgb));
|
||||
}
|
||||
|
||||
.template-preview-box {
|
||||
padding-bottom: 32px;
|
||||
padding: 32px 32px 0;
|
||||
position: relative;
|
||||
background-color: rgb(var(--center-channel-bg-rgb));
|
||||
box-shadow: rgba(var(--center-channel-color-rgb), 0.1) 0 0 0 1px,
|
||||
rgba(var(--center-channel-color-rgb), 0.1) 0 2px 4px;
|
||||
border-radius: var(--modal-rad);
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
max-width: 1000px;
|
||||
height: 512px;
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
bottom: 32px;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
flex-direction: column;
|
||||
padding: 0 24px;
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
flex-direction: row;
|
||||
}
|
||||
}
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
|
||||
.empty-board {
|
||||
background-color: rgb(var(--center-channel-bg-rgb));
|
||||
}
|
||||
|
||||
.Button {
|
||||
&:first-child {
|
||||
margin-bottom: 16px;
|
||||
|
||||
@media (min-width: 1024px) {
|
||||
margin: 0 16px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
> .buttons:first-child {
|
||||
padding-top: 32px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,13 +221,13 @@ describe('components/boardTemplateSelector/boardTemplateSelector', () => {
|
||||
expect(onClose).toBeCalledTimes(1)
|
||||
})
|
||||
test('return BoardTemplateSelector and click new template', () => {
|
||||
const {container} = render(wrapDNDIntl(
|
||||
render(wrapDNDIntl(
|
||||
<ReduxProvider store={store}>
|
||||
<BoardTemplateSelector onClose={jest.fn()}/>
|
||||
</ReduxProvider>
|
||||
,
|
||||
), {wrapper: MemoryRouter})
|
||||
const divNewTemplate = container.querySelector('div.new-template')
|
||||
const divNewTemplate = screen.getByText('Create new template').parentElement
|
||||
expect(divNewTemplate).not.toBeNull()
|
||||
userEvent.click(divNewTemplate!)
|
||||
expect(mockedMutator.addEmptyBoardTemplate).toBeCalledTimes(1)
|
||||
|
@ -3,11 +3,13 @@
|
||||
import React, {useEffect, useState, useCallback, useMemo} from 'react'
|
||||
import {FormattedMessage, useIntl} from 'react-intl'
|
||||
import {useHistory, useRouteMatch} from 'react-router-dom'
|
||||
import {useHotkeys} from 'react-hotkeys-hook'
|
||||
|
||||
import CompassIcon from '../../widgets/icons/compassIcon'
|
||||
|
||||
import {Board} from '../../blocks/board'
|
||||
import IconButton from '../../widgets/buttons/iconButton'
|
||||
import CloseIcon from '../../widgets/icons/close'
|
||||
import AddIcon from '../../widgets/icons/add'
|
||||
import Button from '../../widgets/buttons/button'
|
||||
import octoClient from '../../octoClient'
|
||||
import mutator from '../../mutator'
|
||||
@ -48,6 +50,8 @@ const BoardTemplateSelector = (props: Props) => {
|
||||
const match = useRouteMatch<{boardId: string, viewId?: string}>()
|
||||
const me = useAppSelector<IUser|null>(getMe)
|
||||
|
||||
useHotkeys('esc', () => props.onClose?.())
|
||||
|
||||
const showBoard = useCallback(async (boardId) => {
|
||||
Utils.showBoard(boardId, match, history)
|
||||
if (onClose) {
|
||||
@ -124,89 +128,100 @@ const BoardTemplateSelector = (props: Props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='BoardTemplateSelector'>
|
||||
<div className='toolbar'>
|
||||
{onClose &&
|
||||
<IconButton
|
||||
size='medium'
|
||||
onClick={onClose}
|
||||
icon={<CloseIcon/>}
|
||||
title={'Close'}
|
||||
/>}
|
||||
</div>
|
||||
<div className='header'>
|
||||
<h1 className='title'>
|
||||
{title || (
|
||||
<FormattedMessage
|
||||
id='BoardTemplateSelector.title'
|
||||
defaultMessage='Create a board'
|
||||
/>
|
||||
)}
|
||||
</h1>
|
||||
<p className='description'>
|
||||
{description || (
|
||||
<FormattedMessage
|
||||
id='BoardTemplateSelector.description'
|
||||
defaultMessage='Add a board to the sidebar using any of the templates defined below or start from scratch.'
|
||||
/>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='templates'>
|
||||
<div className='templates-list'>
|
||||
{allTemplates.map((boardTemplate) => (
|
||||
<BoardTemplateSelectorItem
|
||||
key={boardTemplate.id}
|
||||
isActive={activeTemplate?.id === boardTemplate.id}
|
||||
template={boardTemplate}
|
||||
onSelect={setActiveTemplate}
|
||||
onDelete={onBoardTemplateDelete}
|
||||
onEdit={showBoard}
|
||||
/>
|
||||
))}
|
||||
<div
|
||||
className='new-template'
|
||||
onClick={() => mutator.addEmptyBoardTemplate(currentTeam?.id || '', intl, showBoard, () => showBoard(currentBoardId))}
|
||||
>
|
||||
<span className='template-icon'><AddIcon/></span>
|
||||
<span className='template-name'>
|
||||
<FormattedMessage
|
||||
id='BoardTemplateSelector.add-template'
|
||||
defaultMessage='New template'
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className={`BoardTemplateSelector__container ${onClose ? '' : 'BoardTemplateSelector__container--page'}`}>
|
||||
{onClose &&
|
||||
<div
|
||||
onClick={onClose}
|
||||
className='BoardTemplateSelector__backdrop'
|
||||
/>}
|
||||
<div className='BoardTemplateSelector'>
|
||||
<div className='toolbar'>
|
||||
{onClose &&
|
||||
<IconButton
|
||||
size='medium'
|
||||
onClick={onClose}
|
||||
icon={<CloseIcon/>}
|
||||
title={'Close'}
|
||||
/>}
|
||||
</div>
|
||||
<div className='template-preview-box'>
|
||||
<BoardTemplateSelectorPreview activeTemplate={activeTemplate}/>
|
||||
<div className='buttons'>
|
||||
<Button
|
||||
filled={true}
|
||||
size={'medium'}
|
||||
onClick={handleUseTemplate}
|
||||
>
|
||||
<div className='header'>
|
||||
<h1 className='title'>
|
||||
{title || (
|
||||
<FormattedMessage
|
||||
id='BoardTemplateSelector.use-this-template'
|
||||
defaultMessage='Use this template'
|
||||
id='BoardTemplateSelector.title'
|
||||
defaultMessage='Create a board'
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
className='empty-board'
|
||||
filled={false}
|
||||
emphasis={'secondary'}
|
||||
size={'medium'}
|
||||
onClick={async () => {
|
||||
const boardsAndBlocks = await mutator.addEmptyBoard(currentTeam?.id || '', intl, showBoard, () => showBoard(currentBoardId))
|
||||
const board = boardsAndBlocks.boards[0]
|
||||
await mutator.updateBoard({...board, channelId: props.channelId || ''}, board, 'linked channel')
|
||||
}}
|
||||
>
|
||||
)}
|
||||
</h1>
|
||||
<p className='description'>
|
||||
{description || (
|
||||
<FormattedMessage
|
||||
id='BoardTemplateSelector.create-empty-board'
|
||||
defaultMessage='Create empty board'
|
||||
id='BoardTemplateSelector.description'
|
||||
defaultMessage='Add a board to the sidebar using any of the templates defined below or start from scratch.'
|
||||
/>
|
||||
</Button>
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<div className='templates'>
|
||||
<div className='templates-sidebar'>
|
||||
<div className='templates-list'>
|
||||
<Button
|
||||
emphasis='link'
|
||||
size='medium'
|
||||
icon={<CompassIcon icon='plus'/>}
|
||||
className='new-template'
|
||||
onClick={() => mutator.addEmptyBoardTemplate(currentTeam?.id || '', intl, showBoard, () => showBoard(currentBoardId))}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='BoardTemplateSelector.add-template'
|
||||
defaultMessage='Create new template'
|
||||
/>
|
||||
</Button>
|
||||
{allTemplates.map((boardTemplate) => (
|
||||
<BoardTemplateSelectorItem
|
||||
key={boardTemplate.id}
|
||||
isActive={activeTemplate?.id === boardTemplate.id}
|
||||
template={boardTemplate}
|
||||
onSelect={setActiveTemplate}
|
||||
onDelete={onBoardTemplateDelete}
|
||||
onEdit={showBoard}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className='templates-sidebar__footer'>
|
||||
<Button
|
||||
emphasis='secondary'
|
||||
size={'medium'}
|
||||
icon={<CompassIcon icon='kanban'/>}
|
||||
onClick={async () => {
|
||||
const boardsAndBlocks = await mutator.addEmptyBoard(currentTeam?.id || '', intl, showBoard, () => showBoard(currentBoardId))
|
||||
const board = boardsAndBlocks.boards[0]
|
||||
await mutator.updateBoard({...board, channelId: props.channelId || ''}, board, 'linked channel')
|
||||
}}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='BoardTemplateSelector.create-empty-board'
|
||||
defaultMessage='Create empty board'
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className='templates-content'>
|
||||
<div className='template-preview-box'>
|
||||
<BoardTemplateSelectorPreview activeTemplate={activeTemplate}/>
|
||||
</div>
|
||||
<div className='buttons'>
|
||||
<Button
|
||||
filled={true}
|
||||
size={'medium'}
|
||||
onClick={handleUseTemplate}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='BoardTemplateSelector.use-this-template'
|
||||
defaultMessage='Use this template'
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
i {
|
||||
font-size: 16px;
|
||||
margin: 0 -5px 0 -4px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,16 @@
|
||||
.BoardTemplateSelectorPreview {
|
||||
position: relative;
|
||||
transform: scale(0.6) translateX(-30%) translateY(-30%);
|
||||
width: 158%;
|
||||
transform-origin: top left;
|
||||
transform: scale(0.8);
|
||||
width: 126%;
|
||||
height: 480px;
|
||||
border-radius: var(--modal-rad);
|
||||
pointer-events: none;
|
||||
|
||||
.ButtonWithMenu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.Kanban {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -5,9 +5,8 @@
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
overflow-wrap: anywhere;
|
||||
|
||||
border-radius: 3px;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
padding: 12px 16px;
|
||||
box-shadow: rgba(var(--center-channel-color-rgb), 0.1) 0 0 0 1px,
|
||||
rgba(var(--center-channel-color-rgb), 0.1) 0 2px 4px;
|
||||
|
@ -104,6 +104,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.emphasis--link {
|
||||
color: rgb(var(--button-bg-rgb));
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: rgba(var(--button-bg-rgb), 0.08);
|
||||
color: rgb(var(--button-bg-rgb));
|
||||
|
Loading…
Reference in New Issue
Block a user