1
0
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:
Asaad Mahmood 2022-11-23 21:22:28 +05:00 committed by GitHub
parent 20d8d7a0ab
commit 9ab0291cb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 713 additions and 576 deletions

View File

@ -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?"
}
}

View File

@ -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;
}
}
}
}

View File

@ -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)

View File

@ -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>

View File

@ -23,7 +23,6 @@
i {
font-size: 16px;
margin: 0 -5px 0 -4px;
}
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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));