mirror of
https://github.com/plankanban/planka.git
synced 2025-12-27 01:11:50 +03:00
Background gradients, migrate from CSS to SCSS, remove !important
This commit is contained in:
@@ -10,7 +10,7 @@ import EditNameStep from './EditNameStep';
|
||||
import EditBackgroundStep from './EditBackgroundStep';
|
||||
import DeleteStep from '../../DeleteStep';
|
||||
|
||||
import styles from './ActionsPopup.module.css';
|
||||
import styles from './ActionsPopup.module.scss';
|
||||
|
||||
const StepTypes = {
|
||||
EDIT_NAME: 'EDIT_NAME',
|
||||
@@ -54,11 +54,17 @@ const ActionsStep = React.memo(
|
||||
);
|
||||
|
||||
const handleBackgroundImageDelete = useCallback(() => {
|
||||
onUpdate({
|
||||
background: null,
|
||||
const data = {
|
||||
backgroundImage: null,
|
||||
});
|
||||
}, [onUpdate]);
|
||||
};
|
||||
|
||||
// TODO: move to services?
|
||||
if (project.background && project.background.type === 'image') {
|
||||
data.background = null;
|
||||
}
|
||||
|
||||
onUpdate(data);
|
||||
}, [project.background, onUpdate]);
|
||||
|
||||
if (step) {
|
||||
if (step) {
|
||||
@@ -76,6 +82,7 @@ const ActionsStep = React.memo(
|
||||
return (
|
||||
<EditBackgroundStep
|
||||
defaultValue={project.background}
|
||||
imageCoverUrl={project.backgroundImage && project.backgroundImage.coverUrl}
|
||||
isImageUpdating={project.isBackgroundImageUpdating}
|
||||
onUpdate={handleBackgroundUpdate}
|
||||
onImageUpdate={onBackgroundImageUpdate}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
.menu {
|
||||
margin: -7px -12px -5px !important;
|
||||
width: calc(100% + 24px) !important;
|
||||
}
|
||||
|
||||
.menuItem {
|
||||
margin: 0 !important;
|
||||
padding-left: 14px !important;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
:global(#app) {
|
||||
.menu {
|
||||
margin: -7px -12px -5px;
|
||||
width: calc(100% + 24px);
|
||||
}
|
||||
|
||||
.menuItem {
|
||||
margin: 0;
|
||||
padding-left: 14px;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,59 @@
|
||||
import dequal from 'dequal';
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
import camelCase from 'lodash/camelCase';
|
||||
import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from 'semantic-ui-react';
|
||||
import { Button, Image } from 'semantic-ui-react';
|
||||
import { FilePicker, Popup } from '../../../lib/custom-ui';
|
||||
|
||||
import styles from './EditBackgroundStep.module.css';
|
||||
import ProjectBackgroundGradients from '../../../constants/ProjectBackgroundGradients';
|
||||
|
||||
import styles from './EditBackgroundStep.module.scss';
|
||||
import globalStyles from '../../../styles.module.scss';
|
||||
|
||||
const EditBackgroundStep = React.memo(
|
||||
({ defaultValue, isImageUpdating, onImageUpdate, onImageDelete, onBack }) => {
|
||||
({
|
||||
defaultValue,
|
||||
imageCoverUrl,
|
||||
isImageUpdating,
|
||||
onUpdate,
|
||||
onImageUpdate,
|
||||
onImageDelete,
|
||||
onBack,
|
||||
}) => {
|
||||
const [t] = useTranslation();
|
||||
|
||||
const field = useRef(null);
|
||||
|
||||
const handleGradientClick = useCallback(
|
||||
(_, { value }) => {
|
||||
const background = {
|
||||
type: 'gradient',
|
||||
name: value,
|
||||
};
|
||||
|
||||
if (!dequal(background, defaultValue)) {
|
||||
onUpdate({
|
||||
type: 'gradient',
|
||||
name: value,
|
||||
});
|
||||
}
|
||||
},
|
||||
[defaultValue, onUpdate],
|
||||
);
|
||||
|
||||
const handleImageClick = useCallback(() => {
|
||||
const background = {
|
||||
type: 'image',
|
||||
};
|
||||
|
||||
if (!dequal(background, defaultValue)) {
|
||||
onUpdate(background);
|
||||
}
|
||||
}, [defaultValue, onUpdate]);
|
||||
|
||||
const handleFileSelect = useCallback(
|
||||
(file) => {
|
||||
onImageUpdate({
|
||||
@@ -21,6 +63,14 @@ const EditBackgroundStep = React.memo(
|
||||
[onImageUpdate],
|
||||
);
|
||||
|
||||
const handleDeleteImageClick = useCallback(() => {
|
||||
onImageDelete();
|
||||
}, [onImageDelete]);
|
||||
|
||||
const handleRemoveClick = useCallback(() => {
|
||||
onUpdate(null);
|
||||
}, [onUpdate]);
|
||||
|
||||
useEffect(() => {
|
||||
field.current.focus();
|
||||
}, []);
|
||||
@@ -33,24 +83,76 @@ const EditBackgroundStep = React.memo(
|
||||
})}
|
||||
</Popup.Header>
|
||||
<Popup.Content>
|
||||
<div className={styles.gradientButtons}>
|
||||
{ProjectBackgroundGradients.map((gradient) => (
|
||||
<Button
|
||||
key={gradient}
|
||||
type="button"
|
||||
name="gradient"
|
||||
value={gradient}
|
||||
className={classNames(
|
||||
styles.gradientButton,
|
||||
defaultValue &&
|
||||
defaultValue.type === 'gradient' &&
|
||||
gradient === defaultValue.name &&
|
||||
styles.gradientButtonActive,
|
||||
globalStyles[`background${upperFirst(camelCase(gradient))}`],
|
||||
)}
|
||||
onClick={handleGradientClick}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{imageCoverUrl && (
|
||||
/* TODO: wrap in button */
|
||||
<Image
|
||||
src={imageCoverUrl}
|
||||
label={
|
||||
defaultValue &&
|
||||
defaultValue.type === 'image' && {
|
||||
corner: 'left',
|
||||
size: 'small',
|
||||
icon: {
|
||||
name: 'star',
|
||||
color: 'grey',
|
||||
inverted: true,
|
||||
},
|
||||
className: styles.imageLabel,
|
||||
}
|
||||
}
|
||||
className={styles.image}
|
||||
onClick={handleImageClick}
|
||||
/>
|
||||
)}
|
||||
<div className={styles.action}>
|
||||
<FilePicker accept="image/*" onSelect={handleFileSelect}>
|
||||
<Button
|
||||
ref={field}
|
||||
content={t('action.uploadNewBackground')}
|
||||
content={t('action.uploadNewImage')}
|
||||
loading={isImageUpdating}
|
||||
disabled={isImageUpdating}
|
||||
className={styles.actionButton}
|
||||
/>
|
||||
</FilePicker>
|
||||
</div>
|
||||
{imageCoverUrl && (
|
||||
<div className={styles.action}>
|
||||
<Button
|
||||
content={t('action.deleteImage')}
|
||||
disabled={isImageUpdating}
|
||||
className={styles.actionButton}
|
||||
onClick={handleDeleteImageClick}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{defaultValue && (
|
||||
<Button
|
||||
negative
|
||||
content={t('action.deleteBackground')}
|
||||
disabled={isImageUpdating}
|
||||
onClick={onImageDelete}
|
||||
/>
|
||||
<div className={styles.action}>
|
||||
<Button
|
||||
content={t('action.removeBackground')}
|
||||
disabled={isImageUpdating}
|
||||
className={styles.actionButton}
|
||||
onClick={handleRemoveClick}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</Popup.Content>
|
||||
</>
|
||||
@@ -60,8 +162,9 @@ const EditBackgroundStep = React.memo(
|
||||
|
||||
EditBackgroundStep.propTypes = {
|
||||
defaultValue: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
imageCoverUrl: PropTypes.string,
|
||||
isImageUpdating: PropTypes.bool.isRequired,
|
||||
// onUpdate: PropTypes.func.isRequired,
|
||||
onUpdate: PropTypes.func.isRequired,
|
||||
onImageUpdate: PropTypes.func.isRequired,
|
||||
onImageDelete: PropTypes.func.isRequired,
|
||||
onBack: PropTypes.func.isRequired,
|
||||
@@ -69,6 +172,7 @@ EditBackgroundStep.propTypes = {
|
||||
|
||||
EditBackgroundStep.defaultProps = {
|
||||
defaultValue: undefined,
|
||||
imageCoverUrl: undefined,
|
||||
};
|
||||
|
||||
export default EditBackgroundStep;
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
.action {
|
||||
border: none;
|
||||
display: inline-block;
|
||||
height: 36px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
transition: background 0.3s ease;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.action:hover {
|
||||
background: #e9e9e9 !important;
|
||||
}
|
||||
|
||||
.actionButton {
|
||||
background: transparent !important;
|
||||
color: #6b808c !important;
|
||||
font-weight: normal !important;
|
||||
height: 36px;
|
||||
line-height: 24px !important;
|
||||
padding: 6px 12px !important;
|
||||
text-align: left !important;
|
||||
text-decoration: underline !important;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
:global(#app) {
|
||||
.action {
|
||||
border: none;
|
||||
display: inline-block;
|
||||
height: 36px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
transition: background 0.3s ease;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background: #e9e9e9;
|
||||
}
|
||||
}
|
||||
|
||||
.actionButton {
|
||||
background: transparent;
|
||||
color: #6b808c;
|
||||
font-weight: normal;
|
||||
height: 36px;
|
||||
line-height: 24px;
|
||||
padding: 6px 12px;
|
||||
text-align: left;
|
||||
text-decoration: underline;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.gradientButton {
|
||||
float: left;
|
||||
height: 40px;
|
||||
margin: 4px;
|
||||
padding: 0;
|
||||
position: relative;
|
||||
width: 49.6px;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
|
||||
.gradientButtonActive:before {
|
||||
bottom: 3px;
|
||||
color: #ffffff;
|
||||
content: "Г";
|
||||
font-size: 18px;
|
||||
line-height: 36px;
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
text-align: center;
|
||||
top: 0;
|
||||
transform: rotate(-135deg);
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
.gradientButtons {
|
||||
margin: -4px;
|
||||
padding-bottom: 8px;
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
.image {
|
||||
cursor: pointer;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.imageLabel {
|
||||
border-color: rgba(29, 46, 63, 0.8);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { Input, Popup } from '../../../lib/custom-ui';
|
||||
|
||||
import { useField } from '../../../hooks';
|
||||
|
||||
import styles from './EditNameStep.module.css';
|
||||
import styles from './EditNameStep.module.scss';
|
||||
|
||||
const EditNameStep = React.memo(({ defaultValue, onUpdate, onBack, onClose }) => {
|
||||
const [t] = useTranslation();
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
.field {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.text {
|
||||
color: #444444;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
:global(#app) {
|
||||
.field {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.text {
|
||||
color: #444444;
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ import { Popup } from '../../../lib/custom-ui';
|
||||
|
||||
import UserItem from './UserItem';
|
||||
|
||||
import styles from './AddMembershipPopup.module.css';
|
||||
import styles from './AddMembershipPopup.module.scss';
|
||||
|
||||
const AddMembershipStep = React.memo(({ users, currentUserIds, onCreate, onClose }) => {
|
||||
const [t] = useTranslation();
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
.menu {
|
||||
border: none;
|
||||
margin: -7px auto -5px;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
:global(#app) {
|
||||
.menu {
|
||||
border: none;
|
||||
margin: -7px auto -5px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import classNames from 'classnames';
|
||||
|
||||
import User from '../../User';
|
||||
|
||||
import styles from './UserItem.module.css';
|
||||
import styles from './UserItem.module.scss';
|
||||
|
||||
const UserItem = React.memo(({ name, avatarUrl, isActive, onSelect }) => (
|
||||
<button type="button" disabled={isActive} className={styles.menuItem} onClick={onSelect}>
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
.menuItem {
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
padding: 4px;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.menuItem:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.menuItemText {
|
||||
display: inline-block;
|
||||
line-height: 32px;
|
||||
position: relative;
|
||||
width: calc(100% - 40px);
|
||||
}
|
||||
|
||||
.menuItemTextActive:before {
|
||||
bottom: 2px;
|
||||
color: #798d99;
|
||||
content: "Г";
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
line-height: 36px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
text-align: center;
|
||||
transform: rotate(-135deg);
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
.user {
|
||||
display: inline-block;
|
||||
line-height: 32px;
|
||||
padding-right: 8px;
|
||||
width: 40px;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
:global(#app) {
|
||||
.menuItem {
|
||||
background: transparent;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
margin: 0;
|
||||
outline: 0;
|
||||
padding: 4px;
|
||||
text-align: left;
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
.menuItemText {
|
||||
display: inline-block;
|
||||
line-height: 32px;
|
||||
position: relative;
|
||||
width: calc(100% - 40px);
|
||||
}
|
||||
|
||||
.menuItemTextActive:before {
|
||||
bottom: 2px;
|
||||
color: #798d99;
|
||||
content: "Г";
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
line-height: 36px;
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
text-align: center;
|
||||
transform: rotate(-135deg);
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
.user {
|
||||
display: inline-block;
|
||||
line-height: 32px;
|
||||
padding-right: 8px;
|
||||
width: 40px;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { useSteps } from '../../hooks';
|
||||
import User from '../User';
|
||||
import DeleteStep from '../DeleteStep';
|
||||
|
||||
import styles from './EditMembershipPopup.module.css';
|
||||
import styles from './EditMembershipPopup.module.scss';
|
||||
|
||||
const StepTypes = {
|
||||
DELETE: 'DELETE',
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
.content {
|
||||
display: inline-block;
|
||||
width: calc(100% - 44px);
|
||||
}
|
||||
|
||||
.deleteButton {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
flex: 0 0 auto;
|
||||
font-weight: normal !important;
|
||||
margin: 0 0 0 -10px !important;
|
||||
padding: 11px 10px !important;
|
||||
text-decoration: underline !important;
|
||||
}
|
||||
|
||||
.deleteButton:hover {
|
||||
background: #e9e9e9 !important;
|
||||
}
|
||||
|
||||
.email {
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
line-height: 1.2;
|
||||
padding: 4px 0 4px 2px;
|
||||
}
|
||||
|
||||
.name {
|
||||
color: #212121;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
padding: 9px 28px 0 2px;
|
||||
}
|
||||
|
||||
.user {
|
||||
display: inline-block;
|
||||
padding-right: 8px;
|
||||
padding-top: 8px;
|
||||
vertical-align: top;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
:global(#app) {
|
||||
.content {
|
||||
display: inline-block;
|
||||
width: calc(100% - 44px);
|
||||
}
|
||||
|
||||
.deleteButton {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
flex: 0 0 auto;
|
||||
font-weight: normal;
|
||||
margin: 0 0 0 -10px;
|
||||
padding: 11px 10px;
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
background: #e9e9e9;
|
||||
}
|
||||
}
|
||||
|
||||
.email {
|
||||
color: #888888;
|
||||
font-size: 14px;
|
||||
line-height: 1.2;
|
||||
padding: 4px 0 4px 2px;
|
||||
}
|
||||
|
||||
.name {
|
||||
color: #212121;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
padding: 9px 28px 0 2px;
|
||||
}
|
||||
|
||||
.user {
|
||||
display: inline-block;
|
||||
padding-right: 8px;
|
||||
padding-top: 8px;
|
||||
vertical-align: top;
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import AddMembershipPopup from './AddMembershipPopup';
|
||||
import EditMembershipPopup from './EditMembershipPopup';
|
||||
import User from '../User';
|
||||
|
||||
import styles from './Project.module.css';
|
||||
import styles from './Project.module.scss';
|
||||
|
||||
const Project = React.memo(
|
||||
({
|
||||
@@ -38,16 +38,6 @@ const Project = React.memo(
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (background) {
|
||||
if (background.type === 'image') {
|
||||
document.body.style.background = `url(${backgroundImage.url}) center / cover fixed #22252a`;
|
||||
}
|
||||
} else {
|
||||
document.body.style.background = null;
|
||||
}
|
||||
}, [background, backgroundImage]);
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<Grid className={styles.header}>
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
.addUser {
|
||||
background: rgba(0, 0, 0, 0.24) !important;
|
||||
border-radius: 50% !important;
|
||||
box-shadow: none !important;
|
||||
color: #fff !important;
|
||||
line-height: 36px !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
transition: all 0.1s ease 0s !important;
|
||||
vertical-align: top !important;
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
.addUser:hover {
|
||||
background: rgba(0, 0, 0, 0.32) !important;
|
||||
}
|
||||
|
||||
.header {
|
||||
flex: 0 0 auto;
|
||||
margin: 0 -1rem !important;
|
||||
}
|
||||
|
||||
.name {
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
color: #fff !important;
|
||||
display: inline-block !important;
|
||||
font-size: 32px !important;
|
||||
font-weight: bold !important;
|
||||
line-height: 36px !important;
|
||||
margin-right: 8px !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.user {
|
||||
display: inline-block;
|
||||
margin: 0 -4px 0 0;
|
||||
vertical-align: top;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.users {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
background: rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
}
|
||||
56
client/src/components/Project/Project.module.scss
Normal file
56
client/src/components/Project/Project.module.scss
Normal file
@@ -0,0 +1,56 @@
|
||||
:global(#app) {
|
||||
.addUser {
|
||||
background: rgba(0, 0, 0, 0.24);
|
||||
border-radius: 50%;
|
||||
box-shadow: none;
|
||||
color: #fff;
|
||||
line-height: 36px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
transition: all 0.1s ease 0s;
|
||||
vertical-align: top;
|
||||
width: 36px;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.32);
|
||||
}
|
||||
}
|
||||
|
||||
.header {
|
||||
flex: 0 0 auto;
|
||||
margin: 0 -1rem;
|
||||
}
|
||||
|
||||
.name {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
color: #fff;
|
||||
display: inline-block;
|
||||
font-size: 32px;
|
||||
font-weight: bold;
|
||||
line-height: 36px;
|
||||
margin-right: 8px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.user {
|
||||
display: inline-block;
|
||||
margin: 0 -4px 0 0;
|
||||
vertical-align: top;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.users {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
background: rgba(0, 0, 0, 0.08);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 0 20px;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user