- Optimization and Edgecases

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-07-03 01:10:11 -04:00
parent 162d8bfffe
commit 6f2c8dba5a
6 changed files with 159 additions and 242 deletions

View File

@@ -29,7 +29,7 @@ const cardColor = (ssbuckets, totalHrs) => {
const getContrastYIQ = (bgColor) => const getContrastYIQ = (bgColor) =>
(bgColor.r * 299 + bgColor.g * 587 + bgColor.b * 114) / 1000 >= 128 ? "black" : "white"; (bgColor.r * 299 + bgColor.g * 587 + bgColor.b * 114) / 1000 >= 128 ? "black" : "white";
export default function ProductionBoardCard({ technician, card, bodyshop, cardSettings }) { export default function ProductionBoardCard({ technician, card, bodyshop, cardSettings, clone }) {
const { t } = useTranslation(); const { t } = useTranslation();
const { metadata } = card; const { metadata } = card;
@@ -73,9 +73,7 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe
size="small" size="small"
style={{ style={{
backgroundColor: cardSettings?.cardcolor && `rgba(${bgColor.r},${bgColor.g},${bgColor.b},${bgColor.a})`, backgroundColor: cardSettings?.cardcolor && `rgba(${bgColor.r},${bgColor.g},${bgColor.b},${bgColor.a})`,
color: cardSettings?.cardcolor && contrastYIQ, color: cardSettings?.cardcolor && contrastYIQ
maxWidth: "250px",
margin: "5px"
}} }}
title={ title={
<Space> <Space>
@@ -99,96 +97,98 @@ export default function ProductionBoardCard({ technician, card, bodyshop, cardSe
</Link> </Link>
} }
> >
<Row> {!clone && (
{cardSettings?.ownr_nm && ( <Row>
<Col span={24}> {cardSettings?.ownr_nm && (
{cardSettings.compact ? ( <Col span={24}>
<div className="ellipses">{`${metadata.ownr_ln || ""} ${metadata.ownr_co_nm || ""}`}</div> {cardSettings.compact ? (
) : ( <div className="ellipses">{`${metadata.ownr_ln || ""} ${metadata.ownr_co_nm || ""}`}</div>
<div className="ellipses"> ) : (
<OwnerNameDisplay ownerObject={card} /> <div className="ellipses">
</div> <OwnerNameDisplay ownerObject={card} />
)} </div>
</Col> )}
)} </Col>
{cardSettings?.model_info && ( )}
<Col span={24}> {cardSettings?.model_info && (
<div className="ellipses">{`${metadata.v_model_yr || ""} ${metadata.v_make_desc || ""} ${metadata.v_model_desc || ""}`}</div> <Col span={24}>
</Col> <div className="ellipses">{`${metadata.v_model_yr || ""} ${metadata.v_make_desc || ""} ${metadata.v_model_desc || ""}`}</div>
)} </Col>
{cardSettings?.ins_co_nm && metadata.ins_co_nm && ( )}
<Col span={cardSettings.compact ? 24 : 12}> {cardSettings?.ins_co_nm && metadata.ins_co_nm && (
<div className="ellipses">{metadata.ins_co_nm || ""}</div> <Col span={cardSettings.compact ? 24 : 12}>
</Col> <div className="ellipses">{metadata.ins_co_nm || ""}</div>
)} </Col>
{cardSettings?.clm_no && metadata.clm_no && ( )}
<Col span={cardSettings.compact ? 24 : 12}> {cardSettings?.clm_no && metadata.clm_no && (
<div className="ellipses">{metadata.clm_no || ""}</div> <Col span={cardSettings.compact ? 24 : 12}>
</Col> <div className="ellipses">{metadata.clm_no || ""}</div>
)} </Col>
{cardSettings?.employeeassignments && ( )}
<Col span={24}> {cardSettings?.employeeassignments && (
<Row> <Col span={24}>
<Col span={cardSettings.compact ? 24 : 12}>{`B: ${ <Row>
employee_body ? `${employee_body.first_name.substr(0, 3)} ${employee_body.last_name.charAt(0)}` : "" <Col span={cardSettings.compact ? 24 : 12}>{`B: ${
} ${metadata.labhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col> employee_body ? `${employee_body.first_name.substr(0, 3)} ${employee_body.last_name.charAt(0)}` : ""
<Col span={cardSettings.compact ? 24 : 12}>{`P: ${ } ${metadata.labhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col>
employee_prep ? `${employee_prep.first_name.substr(0, 3)} ${employee_prep.last_name.charAt(0)}` : "" <Col span={cardSettings.compact ? 24 : 12}>{`P: ${
}`}</Col> employee_prep ? `${employee_prep.first_name.substr(0, 3)} ${employee_prep.last_name.charAt(0)}` : ""
<Col span={cardSettings.compact ? 24 : 12}>{`R: ${ }`}</Col>
employee_refinish <Col span={cardSettings.compact ? 24 : 12}>{`R: ${
? `${employee_refinish.first_name.substr(0, 3)} ${employee_refinish.last_name.charAt(0)}` employee_refinish
: "" ? `${employee_refinish.first_name.substr(0, 3)} ${employee_refinish.last_name.charAt(0)}`
} ${metadata.larhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col> : ""
<Col span={cardSettings.compact ? 24 : 12}>{`C: ${ } ${metadata.larhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col>
employee_csr ? `${employee_csr.first_name} ${employee_csr.last_name}` : "" <Col span={cardSettings.compact ? 24 : 12}>{`C: ${
}`}</Col> employee_csr ? `${employee_csr.first_name} ${employee_csr.last_name}` : ""
</Row> }`}</Col>
</Col> </Row>
)} </Col>
{cardSettings?.actual_in && metadata.actual_in && ( )}
<Col span={cardSettings.compact ? 24 : 12}> {cardSettings?.actual_in && metadata.actual_in && (
<Space> <Col span={cardSettings.compact ? 24 : 12}>
<DownloadOutlined /> <Space>
<DateTimeFormatter format="MM/DD">{metadata.actual_in}</DateTimeFormatter> <DownloadOutlined />
</Space> <DateTimeFormatter format="MM/DD">{metadata.actual_in}</DateTimeFormatter>
</Col> </Space>
)} </Col>
{cardSettings?.scheduled_completion && metadata.scheduled_completion && ( )}
<Col span={cardSettings.compact ? 24 : 12}> {cardSettings?.scheduled_completion && metadata.scheduled_completion && (
<Space className={pastDueAlert}> <Col span={cardSettings.compact ? 24 : 12}>
<CalendarOutlined /> <Space className={pastDueAlert}>
<DateTimeFormatter format="MM/DD">{metadata.scheduled_completion}</DateTimeFormatter> <CalendarOutlined />
</Space> <DateTimeFormatter format="MM/DD">{metadata.scheduled_completion}</DateTimeFormatter>
</Col> </Space>
)} </Col>
{cardSettings?.ats && metadata.alt_transport && ( )}
<Col span={12}> {cardSettings?.ats && metadata.alt_transport && (
<div>{metadata.alt_transport || ""}</div> <Col span={12}>
</Col> <div>{metadata.alt_transport || ""}</div>
)} </Col>
{cardSettings?.sublets && ( )}
<Col span={12}> {cardSettings?.sublets && (
<ProductionSubletsManageComponent subletJobLines={metadata.subletLines} /> <Col span={12}>
</Col> <ProductionSubletsManageComponent subletJobLines={metadata.subletLines} />
)} </Col>
{cardSettings?.production_note && ( )}
<Col span={24}> {cardSettings?.production_note && (
<ProductionListColumnProductionNote <Col span={24}>
record={{ <ProductionListColumnProductionNote
production_vars: card?.metadata.production_vars, record={{
id: card?.id, production_vars: card?.metadata.production_vars,
refetch: card?.refetch id: card?.id,
}} refetch: card?.refetch
/> }}
</Col> />
)} </Col>
{cardSettings?.partsstatus && ( )}
<Col span={24}> {cardSettings?.partsstatus && (
<JobPartsQueueCount parts={metadata.joblines_status} /> <Col span={24}>
</Col> <JobPartsQueueCount parts={metadata.joblines_status} />
)} </Col>
</Row> )}
</Row>
)}
</Card> </Card>
); );
} }

View File

@@ -63,7 +63,7 @@ export function ProductionBoardKanbanComponent({
}, [associationSettings]); }, [associationSettings]);
useEffect(() => { useEffect(() => {
const newBoardData = createBoardData( const newBoardData = createFakeBoardData(
[...bodyshop.md_ro_statuses.production_statuses, ...(bodyshop.md_ro_statuses.additional_board_statuses || [])], [...bodyshop.md_ro_statuses.production_statuses, ...(bodyshop.md_ro_statuses.additional_board_statuses || [])],
data, data,
filter filter
@@ -205,7 +205,7 @@ export function ProductionBoardKanbanComponent({
const Header = useCallback( const Header = useCallback(
({ title }) => ( ({ title }) => (
<div className="react-trello-column-header" style={{ backgroundColor: "#e3e3e3" }}> <div className="react-trello-column-header" style={{ backgroundColor: "#e3e3e3" }}>
<UnorderedListOutlined style={{ marginRight: "5px" }} /> {title} <UnorderedListOutlined style={{ marginRight: "5px" }} /> {title.substring(0, 10)}
</div> </div>
), ),
[] []

View File

@@ -1,5 +1,5 @@
import { groupBy } from "lodash"; import { groupBy } from "lodash";
import fakeData from "./testData/board600.json"; import fakeData from "./testData/board1200.json";
const sortByParentId = (arr) => { const sortByParentId = (arr) => {
// return arr.reduce((accumulator, currentValue) => { // return arr.reduce((accumulator, currentValue) => {

View File

@@ -1,6 +1,6 @@
import React, { useCallback, useEffect, useState, useMemo } from "react"; import React, { useCallback, useEffect, useState, useMemo } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { DragDropContext, Droppable } from "../dnd/lib"; import { DragDropContext } from "../dnd/lib";
import PropTypes from "prop-types"; import PropTypes from "prop-types";
import pick from "lodash/pick"; import pick from "lodash/pick";
import isEqual from "lodash/isEqual"; import isEqual from "lodash/isEqual";
@@ -20,16 +20,6 @@ import * as actions from "../../../redux/trello/trello.actions.js";
* @param {boolean} props.draggable - Whether the board is draggable * @param {boolean} props.draggable - Whether the board is draggable
* @param {Object} props.style - The CSS styles to apply to the board * @param {Object} props.style - The CSS styles to apply to the board
* @param {Function} props.onDataChange - Callback function when the board data changes * @param {Function} props.onDataChange - Callback function when the board data changes
* @param {Function} props.onCardAdd - Callback function when a card is added
* @param {Function} props.onCardUpdate - Callback function when a card is updated
* @param {Function} props.onCardClick - Callback function when a card is clicked
* @param {Function} props.onBeforeCardDelete - Callback function before a card is deleted
* @param {Function} props.onCardDelete - Callback function when a card is deleted
* @param {Function} props.onLaneScroll - Callback function when a lane is scrolled
* @param {Function} props.onLaneClick - Callback function when a lane is clicked
* @param {Function} props.onLaneAdd - Callback function when a lane is added
* @param {Function} props.onLaneDelete - Callback function when a lane is deleted
* @param {Function} props.onLaneUpdate - Callback function when a lane is updated
* @param {Function} props.onDragEnd - Callback function when a drag ends * @param {Function} props.onDragEnd - Callback function when a drag ends
* @param {boolean} props.editable - Whether the board is editable * @param {boolean} props.editable - Whether the board is editable
* @param {boolean} props.canAddLanes - Whether lanes can be added to the board * @param {boolean} props.canAddLanes - Whether lanes can be added to the board
@@ -48,16 +38,6 @@ const BoardContainer = ({
draggable = false, draggable = false,
style, style,
onDataChange = () => {}, onDataChange = () => {},
onCardAdd = () => {},
onCardUpdate = () => {},
onCardClick = () => {},
onBeforeCardDelete = () => {},
onCardDelete = () => {},
onLaneScroll = () => {},
onLaneClick = () => {},
onLaneAdd = () => {},
onLaneDelete = () => {},
onLaneUpdate = () => {},
onDragEnd = () => {}, onDragEnd = () => {},
editable = false, editable = false,
canAddLanes = false, canAddLanes = false,
@@ -68,7 +48,6 @@ const BoardContainer = ({
cardStyle, cardStyle,
...otherProps ...otherProps
}) => { }) => {
const [addLaneMode, setAddLaneMode] = useState(false);
const [isDragging, setIsDragging] = useState(false); const [isDragging, setIsDragging] = useState(false);
const [isProcessing, setIsProcessing] = useState(false); const [isProcessing, setIsProcessing] = useState(false);
@@ -126,15 +105,9 @@ const BoardContainer = ({
} }
}, [currentReducerData, reducerData, onDataChange]); }, [currentReducerData, reducerData, onDataChange]);
const onDragUpdate = () => {};
const onDragStart = useCallback(() => { const onDragStart = useCallback(() => {
setIsDragging(true); setIsDragging(true);
}, []); }, [setIsDragging]);
const onBeforeDragStart = () => {};
const onBeforeCapture = () => {};
const getCardDetails = useCallback( const getCardDetails = useCallback(
(laneId, cardIndex) => { (laneId, cardIndex) => {
@@ -143,23 +116,6 @@ const BoardContainer = ({
[currentReducerData] [currentReducerData]
); );
const hideEditableLane = useCallback(() => {
setAddLaneMode(false);
}, []);
const showEditableLane = useCallback(() => {
setAddLaneMode(true);
}, []);
const addNewLane = useCallback(
(params) => {
hideEditableLane();
dispatch(actions.addLane(params));
onLaneAdd(params);
},
[dispatch, hideEditableLane, onLaneAdd]
);
const passThroughProps = useMemo( const passThroughProps = useMemo(
() => () =>
pick( pick(
@@ -170,16 +126,6 @@ const BoardContainer = ({
draggable, draggable,
style, style,
onDataChange, onDataChange,
onCardAdd,
onCardUpdate,
onCardClick,
onBeforeCardDelete,
onCardDelete,
onLaneScroll,
onLaneClick,
onLaneAdd,
onLaneDelete,
onLaneUpdate,
editable, editable,
canAddLanes, canAddLanes,
laneStyle, laneStyle,
@@ -220,16 +166,7 @@ const BoardContainer = ({
draggable, draggable,
style, style,
onDataChange, onDataChange,
onCardAdd,
onCardUpdate,
onCardClick,
onBeforeCardDelete,
onCardDelete,
onLaneScroll,
onLaneClick,
onLaneAdd,
onLaneDelete,
onLaneUpdate,
editable, editable,
canAddLanes, canAddLanes,
laneStyle, laneStyle,
@@ -272,14 +209,7 @@ const BoardContainer = ({
return ( return (
<components.BoardWrapper style={style} orientation={orientation}> <components.BoardWrapper style={style} orientation={orientation}>
<PopoverWrapper> <PopoverWrapper>
<DragDropContext <DragDropContext onDragEnd={onLaneDrag} onDragStart={onDragStart} contextId={groupName}>
onDragEnd={onLaneDrag}
onDragUpdate={onDragUpdate}
onDragStart={onDragStart}
onBeforeDragStart={onBeforeDragStart}
onBeforeCapture={onBeforeCapture}
contextId={groupName}
>
{currentReducerData.lanes.map((lane, index) => { {currentReducerData.lanes.map((lane, index) => {
const { id, droppable, ...laneOtherProps } = lane; const { id, droppable, ...laneOtherProps } = lane;
return ( return (
@@ -303,15 +233,6 @@ const BoardContainer = ({
/> />
); );
})} })}
{canAddLanes && (
<Droppable type="placeholder" direction={orientation === "horizontal" ? "vertical" : "grid"}>
{editable && !addLaneMode ? (
<components.NewLaneSection onClick={showEditableLane} />
) : (
addLaneMode && <components.NewLaneForm onCancel={hideEditableLane} onAdd={addNewLane} />
)}
</Droppable>
)}
</DragDropContext> </DragDropContext>
</PopoverWrapper> </PopoverWrapper>
</components.BoardWrapper> </components.BoardWrapper>

View File

@@ -44,9 +44,6 @@ const Lane = ({
canAddLanes = false, canAddLanes = false,
hideCardDeleteIcon = false, hideCardDeleteIcon = false,
components = {}, components = {},
getCardDetails,
handleDragStart = () => {},
handleDragEnd = () => {},
orientation = "vertical", orientation = "vertical",
className, className,
currentPage, currentPage,
@@ -93,11 +90,11 @@ const Lane = ({
const showEditableCard = useCallback(() => { const showEditableCard = useCallback(() => {
setAddCardMode(true); setAddCardMode(true);
}, []); }, [setAddCardMode]);
const hideEditableCard = useCallback(() => { const hideEditableCard = useCallback(() => {
setAddCardMode(false); setAddCardMode(false);
}, []); }, [setAddCardMode]);
const addNewCard = useCallback( const addNewCard = useCallback(
(params) => { (params) => {
@@ -188,14 +185,7 @@ const Lane = ({
); );
const ItemWrapper = ({ children, ...props }) => ( const ItemWrapper = ({ children, ...props }) => (
<div <div {...props} className="item-wrapper">
{...props}
style={{
display: "flex",
flex: 1,
whiteSpace: "nowrap"
}}
>
{children} {children}
</div> </div>
); );
@@ -206,7 +196,11 @@ const Lane = ({
const commonProps = { const commonProps = {
useWindowScroll: true, useWindowScroll: true,
data: renderedCards data: renderedCards,
overscan: {
main: 22,
reverse: 22
}
}; };
const componentProps = const componentProps =
@@ -222,36 +216,21 @@ const Lane = ({
ref={ref} ref={ref}
{...props} {...props}
style={{ style={{
display: "flex",
flexWrap: "wrap",
...style ...style
}} }}
> >
{children} {children}
</div> </div>
)), )),
Item: ({ children, ...props }) => ( Item: ({ children, ...props }) => <div {...props}>{children}</div>
<div
{...props}
style={{
width: 152,
display: "flex"
}}
>
{children}
</div>
)
}, },
itemContent: (index, item) => <ItemWrapper>{renderDraggable(index, item)}</ItemWrapper> itemContent: (index, item) => <ItemWrapper>{renderDraggable(index, item)}</ItemWrapper>
} }
: { : {
...commonProps, ...commonProps,
overscan: {
main: 22,
reverse: 22
},
components: { Item: HeightPreservingItem }, components: { Item: HeightPreservingItem },
itemContent: (index, item) => renderDraggable(index, item) itemContent: (index, item) => renderDraggable(index, item),
scrollerRef: provided.innerRef
}; };
const finalComponentProps = collapsed ? {} : componentProps; const finalComponentProps = collapsed ? {} : componentProps;
return ( return (
@@ -282,7 +261,12 @@ const Lane = ({
direction={orientation === "horizontal" ? "vertical" : "grid"} direction={orientation === "horizontal" ? "vertical" : "grid"}
mode="virtual" mode="virtual"
renderClone={(provided, snapshot, rubric) => ( renderClone={(provided, snapshot, rubric) => (
<Card provided={provided} isDragging={snapshot.isDragging} item={renderedCards[rubric.source.index]} /> <Card
clone={true}
provided={provided}
isDragging={snapshot.isDragging}
item={renderedCards[rubric.source.index]}
/>
)} )}
> >
{(provided) => renderDroppable(provided, renderedCards)} {(provided) => renderDroppable(provided, renderedCards)}
@@ -327,9 +311,6 @@ const Lane = ({
canAddLanes, canAddLanes,
hideCardDeleteIcon, hideCardDeleteIcon,
components, components,
getCardDetails,
handleDragStart,
handleDragEnd,
orientation, orientation,
className, className,
currentPage, currentPage,
@@ -363,19 +344,9 @@ Lane.propTypes = {
labelStyle: PropTypes.object, labelStyle: PropTypes.object,
cards: PropTypes.array, cards: PropTypes.array,
label: PropTypes.string, label: PropTypes.string,
currentPage: PropTypes.number,
draggable: PropTypes.bool, draggable: PropTypes.bool,
collapsibleLanes: PropTypes.bool, collapsibleLanes: PropTypes.bool,
droppable: PropTypes.bool, droppable: PropTypes.bool,
onCardClick: PropTypes.func,
onBeforeCardDelete: PropTypes.func,
onCardDelete: PropTypes.func,
onCardAdd: PropTypes.func,
onCardUpdate: PropTypes.func,
onLaneDelete: PropTypes.func,
onLaneUpdate: PropTypes.func,
onLaneClick: PropTypes.func,
onLaneScroll: PropTypes.func,
editable: PropTypes.bool, editable: PropTypes.bool,
cardDraggable: PropTypes.bool, cardDraggable: PropTypes.bool,
cardDragClass: PropTypes.string, cardDragClass: PropTypes.string,
@@ -383,9 +354,6 @@ Lane.propTypes = {
canAddLanes: PropTypes.bool, canAddLanes: PropTypes.bool,
hideCardDeleteIcon: PropTypes.bool, hideCardDeleteIcon: PropTypes.bool,
components: PropTypes.object, components: PropTypes.object,
getCardDetails: PropTypes.func,
handleDragStart: PropTypes.func,
handleDragEnd: PropTypes.func,
orientation: PropTypes.string orientation: PropTypes.string
}; };

View File

@@ -16,12 +16,14 @@ const getBoardWrapperStyles = (props) => {
}; };
const getSectionStyles = (props) => { const getSectionStyles = (props) => {
// TODO The min width here is where we will set the size settings for horizontal lanes (card visibility)
if (props.orientation === "horizontal") { if (props.orientation === "horizontal") {
return ` return `
display: inline-flex; display: inline-flex;
flex-direction: column; flex-direction: column;
white-space: nowrap; white-space: nowrap;
// overflow-y: none; // overflow-y: none;
min-width: 8.5%;
`; `;
} }
return ` return `
@@ -73,8 +75,10 @@ export const GlobalStyle = createGlobalStyle`
export const StyleHorizontal = styled.div` export const StyleHorizontal = styled.div`
.react-trello-lane { .react-trello-lane {
min-width: 250px; width: 100%;
min-height: 25px; height: 100%;
overflow-y: visible;
overflow-x: visible; // change this line
} }
.react-trello-lane.lane-collapsed { .react-trello-lane.lane-collapsed {
@@ -83,8 +87,15 @@ export const StyleHorizontal = styled.div`
.ant-card-body { .ant-card-body {
padding: 4px; padding: 4px;
} }
.item-wrapper {
display: flex;
flex: 1 1 auto;
white-space: nowrap;
min-width: 4%;
}
.react-trello-card { .react-trello-card {
height: auto; height: auto;
margin: 2px;
} }
`; `;
@@ -95,6 +106,7 @@ export const StyleVertical = styled.div`
.react-trello-lane { .react-trello-lane {
min-height: 5px; min-height: 5px;
height: 100%;
} }
.react-trello-lane.lane-collapsed { .react-trello-lane.lane-collapsed {
@@ -103,22 +115,39 @@ export const StyleVertical = styled.div`
.react-trello-card { .react-trello-card {
flex: 0 1 auto; flex: 0 1 auto;
width: 150px; width: 100%;
height: auto; height: 100%;
}
.grid-container {
display: flex;
flex-wrap: wrap;
}
.grid-item {
width: 8%; // TODO: THIS IS WHERE WE GET VERTICAL CARD CUSTOMIZATION
display: flex;
align-content: stretch;
box-sizing: border-box;
}
.item {
height: 100%;
width: 100%;
}
.item-wrapper {
width: 100%;
height: 100%;
} }
.react-trello-board { .react-trello-board {
display: flex; display: flex;
} }
.grid-container {
}
.grid-item {
}
.ant-card-body { .ant-card-body {
} }
.ant-card {
height: 100%;
}
`; `;
export const CustomPopoverContainer = styled(PopoverContainer)` export const CustomPopoverContainer = styled(PopoverContainer)`
@@ -236,15 +265,14 @@ export const RightContent = styled.span`
padding-right: 10px; padding-right: 10px;
font-size: 13px; font-size: 13px;
`; `;
export const CardWrapper = styled.article` export const CardWrapper = styled.article`
border-radius: 3px; border-radius: 3px;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
background-color: #fff; background-color: #fff;
position: relative;
padding: 10px;
cursor: pointer; cursor: pointer;
max-width: 250px;
margin-bottom: 7px; margin-bottom: 7px;
max-width: 250px;
min-width: 230px; min-width: 230px;
`; `;