style(allocations): improve display of unset priorities

This commit is contained in:
Gregor Kleen 2020-02-28 22:11:44 +01:00
parent ee2e504ffa
commit 5090cca98b
5 changed files with 63 additions and 43 deletions

View File

@ -358,6 +358,10 @@ input[type="button"].btn-info:hover,
.table__td--overriden .table__td--overriden
font-weight: bold font-weight: bold
.table__td--center > .table__td-content
margin: auto
width: max-content
.table__th .table__th
background-color: var(--color-dark) background-color: var(--color-dark)
position: relative position: relative
@ -531,10 +535,9 @@ section
.notification .notification
position: relative position: relative
border-radius: 3px border-radius: 3px
padding: 10px 20px 20px padding: 10px 20px 10px 100px
margin: 40px auto margin: 40px auto
box-shadow: 0 0 4px 2px inset currentColor box-shadow: 0 0 4px 2px inset currentColor
padding-left: 100px
min-height: 100px min-height: 100px
max-width: 700px max-width: 700px
font-weight: 600 font-weight: 600

View File

@ -9,6 +9,7 @@
transition: transform .2s ease transition: transform .2s ease
transform: scaleY(0) transform: scaleY(0)
transform-origin: top transform-origin: top
z-index: 1
&:hover &:hover
background-color: var(--color-grey-light) background-color: var(--color-grey-light)

View File

@ -5,12 +5,15 @@ import { MovementObserver } from '../../lib/movement-observer/movement-observer'
var TOOLTIP_CLASS = 'tooltip'; var TOOLTIP_CLASS = 'tooltip';
var TOOLTIP_INITIALIZED_CLASS = 'tooltip--initialized'; var TOOLTIP_INITIALIZED_CLASS = 'tooltip--initialized';
var TOOLTIP_OPEN_CLASS = 'tooltip--active'; var TOOLTIP_OPEN_CLASS = 'tooltip--active';
var TOOLTIP_ORIENTATION_MARGIN = 10;
var TOOLTIP_CENTER_THRESHOLD = 20;
@Utility({ @Utility({
selector: `.${TOOLTIP_CLASS}`, selector: `.${TOOLTIP_CLASS}`,
}) })
export class Tooltip { export class Tooltip {
_element; _element;
_handle;
_content; _content;
_movementObserver; _movementObserver;
@ -20,6 +23,8 @@ export class Tooltip {
_xOffset = 3; _xOffset = 3;
_yOffset = -10; _yOffset = -10;
_xArrowOffset = 18;
constructor(element) { constructor(element) {
if (!element) { if (!element) {
throw new Error('Tooltip utility cannot be setup without an element!'); throw new Error('Tooltip utility cannot be setup without an element!');
@ -38,8 +43,9 @@ export class Tooltip {
this._content = content; this._content = content;
this._element = element; this._element = element;
this._handle = element.querySelector('.tooltip__handle') || element;
this._movementObserver = new MovementObserver(this._element, { leadingCallback: this.close.bind(this) }); this._movementObserver = new MovementObserver(this._handle, { leadingCallback: this.close.bind(this) });
element.classList.add(TOOLTIP_INITIALIZED_CLASS); element.classList.add(TOOLTIP_INITIALIZED_CLASS);
} }
@ -103,9 +109,9 @@ export class Tooltip {
this.close(); this.close();
} }
_reposition() { _reposition(forceRight, forceBottom) {
const doRight = this._decideRight(); const doRight = forceRight === undefined ? this._decideRight() : !!forceRight;
const doBottom = this._decideBottom(); const doBottom = forceBottom === undefined ? this._decideBottom() : !!forceBottom;
// console.log('doRight', doRight); // console.log('doRight', doRight);
// console.log('doBottom', doBottom); // console.log('doBottom', doBottom);
@ -120,34 +126,39 @@ export class Tooltip {
else else
this._element.classList.remove('tooltip--right'); this._element.classList.remove('tooltip--right');
const handleCoords = this._element.getBoundingClientRect(); const handleCoords = this._handle.getBoundingClientRect();
const left = doRight ? handleCoords.right - this._xOffset : handleCoords.left + this._xOffset; for (let _i of [1,2]) { // eslint-disable-line no-unused-vars
const bottom = doBottom ? handleCoords.bottom - this._yOffset : handleCoords.top + this._yOffset; const left = doRight ? handleCoords.right - this._getXOffset() - this._content.offsetWidth : handleCoords.left + this._getXOffset();
const top = doBottom ? handleCoords.bottom - this._yOffset : handleCoords.top + this._yOffset - this._content.offsetHeight;
if (doRight) {
const right = left - this._content.offsetWidth;
this._content.style.left = `${right}px`;
} else
this._content.style.left = `${left}px`; this._content.style.left = `${left}px`;
if (doBottom)
this._content.style.top = `${bottom}px`;
else {
const top = bottom - this._content.offsetHeight;
this._content.style.top = `${top}px`; this._content.style.top = `${top}px`;
} }
} }
_getXOffset() {
if (this._decideCenter())
return this._handle.offsetWidth / 2 - this._xArrowOffset;
else
return this._xOffset;
}
_decideCenter() {
return this._handle.offsetWidth <= TOOLTIP_CENTER_THRESHOLD;
}
_decideBottom() { _decideBottom() {
const handleCoords = this._element.getBoundingClientRect(); const handleCoords = this._handle.getBoundingClientRect();
const windowHeight = window.innerHeight || document.documentElement.clientHeight; const windowHeight = window.innerHeight || document.documentElement.clientHeight;
const bottom = handleCoords.top + this._yOffset; this._reposition(false, false);
const bottomBottom = handleCoords.bottom - this._yOffset; const top = handleCoords.top + this._yOffset - this._content.offsetHeight - 2 * TOOLTIP_ORIENTATION_MARGIN;
const isHeight = Math.min(this._content.offsetHeight + 2 * TOOLTIP_ORIENTATION_MARGIN, Math.max(0, windowHeight - top));
const isHeight = Math.min(windowHeight, bottom) - Math.max(0, bottom - this._content.offsetHeight); this._reposition(false, true);
const isHeightBottom = Math.min(windowHeight, bottomBottom) - Math.max(0, bottomBottom - this._content.offsetHeight); const topBottom = handleCoords.bottom - this._yOffset;
const isHeightBottom = Math.min(this._content.offsetHeight + 2 * TOOLTIP_ORIENTATION_MARGIN, Math.max(0, windowHeight - topBottom));
// console.log('_decideBottom', isHeight, isHeightBottom); // console.log('_decideBottom', isHeight, isHeightBottom);
@ -155,14 +166,16 @@ export class Tooltip {
} }
_decideRight() { _decideRight() {
const handleCoords = this._element.getBoundingClientRect(); const handleCoords = this._handle.getBoundingClientRect();
const windowWidth = window.innerWidth || document.documentElement.clientWidth; const windowWidth = window.innerWidth || document.documentElement.clientWidth;
const left = handleCoords.left + this._yOffset; this._reposition(false, false);
const leftRight = handleCoords.right - this._yOffset; const left = handleCoords.left + this._getXOffset();
const isWidth = Math.min(this._content.offsetWidth + 2 * TOOLTIP_ORIENTATION_MARGIN, Math.max(0, windowWidth - left));
const isWidth = Math.max(0, Math.min(windowWidth - left , this._content.offsetWidth)) + Math.min(0, left); this._reposition(true, false);
const isWidthRight = Math.max(0, Math.min(windowWidth - leftRight, this._content.offsetWidth)) + Math.min(0, leftRight); const leftRight = handleCoords.right - this._getXOffset() - this._content.offsetWidth - 2 * TOOLTIP_ORIENTATION_MARGIN;
const isWidthRight = Math.min(this._content.offsetWidth + 2 * TOOLTIP_ORIENTATION_MARGIN, Math.max(0, windowWidth - leftRight));
// console.log('_decideRight', isWidth, isWidthRight); // console.log('_decideRight', isWidth, isWidthRight);

View File

@ -103,15 +103,11 @@ instance CsvColumnsExplained AllocationUserTableCsv where
getAUsersR, postAUsersR :: TermId -> SchoolId -> AllocationShorthand -> Handler Html getAUsersR, postAUsersR :: TermId -> SchoolId -> AllocationShorthand -> Handler Html
getAUsersR = postAUsersR getAUsersR = postAUsersR
postAUsersR tid ssh ash = do postAUsersR tid ssh ash = do
(usersTable, missingPriorities) <- runDB $ do usersTable <- runDB $ do
Entity aId _ <- getBy404 $ TermSchoolAllocationShort tid ssh ash Entity aId _ <- getBy404 $ TermSchoolAllocationShort tid ssh ash
now <- liftIO getCurrentTime now <- liftIO getCurrentTime
resultsDone <- (<= NTop (Just now)) . NTop <$> allocationDone aId resultsDone <- (<= NTop (Just now)) . NTop <$> allocationDone aId
missingPriorities <- E.selectExists . E.from $ \allocationUser ->
E.where_ $ allocationUser E.^. AllocationUserAllocation E.==. E.val aId
E.&&. E.isNothing (allocationUser E.^. AllocationUserPriority)
csvName <- getMessageRender <*> pure (MsgAllocationUsersCsvName tid ssh ash) csvName <- getMessageRender <*> pure (MsgAllocationUsersCsvName tid ssh ash)
let let
@ -147,9 +143,11 @@ postAUsersR tid ssh ash = do
, coursesModalApplied $ colAllocationApplied resultAppliedCourses , coursesModalApplied $ colAllocationApplied resultAppliedCourses
, coursesModalVetoed $ colAllocationVetoed resultVetoedCourses , coursesModalVetoed $ colAllocationVetoed resultVetoedCourses
, coursesModalAssigned . assignedHeated $ colAllocationAssigned resultAssignedCourses , coursesModalAssigned . assignedHeated $ colAllocationAssigned resultAssignedCourses
, emptyOpticColonnade (resultAllocationUser . _entityVal . _allocationUserPriority . _Just) colAllocationPriority , emptyOpticColonnade' emptyPriorityCell (resultAllocationUser . _entityVal . _allocationUserPriority . _Just) colAllocationPriority
] ]
where where
emptyPriorityCell = addCellClass ("table__td--center" :: Text) . cell $
messageTooltip =<< messageIconI Error IconMissingAllocationPriority MsgAllocationMissingPrioritiesIgnored
assignedHeated assignedHeated
| resultsDone = imapColonnade assignedHeated' | resultsDone = imapColonnade assignedHeated'
| otherwise = id | otherwise = id
@ -225,11 +223,9 @@ postAUsersR tid ssh ash = do
& defaultPagesize PagesizeAll & defaultPagesize PagesizeAll
usersTable <- dbTableDB' allocationUsersDBTableValidator allocationUsersDBTable usersTable <- dbTableDB' allocationUsersDBTableValidator allocationUsersDBTable
return (usersTable, missingPriorities) return usersTable
siteLayoutMsg MsgMenuAllocationUsers $ do siteLayoutMsg MsgMenuAllocationUsers $ do
setTitleI $ MsgAllocationUsersTitle tid ssh ash setTitleI $ MsgAllocationUsersTitle tid ssh ash
when missingPriorities $
notification NotificationBroad =<< messageIconI Warning IconMissingAllocationPriority MsgAllocationMissingPrioritiesIgnored
usersTable usersTable

View File

@ -902,15 +902,22 @@ maybeAnchorColonnadeM mkUrl = imapColonnade anchorColonnade'
anchorColonnade' inp (view dbCell -> (attrs, act)) = review dbCell . (attrs,) $ anchorColonnade' inp (view dbCell -> (attrs, act)) = review dbCell . (attrs,) $
view (dbCell . _2) . maybeAnchorCellM (mkUrl inp) =<< act view (dbCell . _2) . maybeAnchorCellM (mkUrl inp) =<< act
emptyOpticColonnade :: forall h r' focus c. emptyOpticColonnade :: forall h r' focus c.
( Monoid c Monoid c
)
=> Getting (Endo [focus]) r' focus -- ^ View on @focus@ within @r'@ that may produce any number of results => Getting (Endo [focus]) r' focus -- ^ View on @focus@ within @r'@ that may produce any number of results
-> ((forall focus'. Getting focus' r' focus) -> Colonnade h r' c) -- ^ `OpticColonnade focus` -> ((forall focus'. Getting focus' r' focus) -> Colonnade h r' c) -- ^ `OpticColonnade focus`
-> Colonnade h r' c -> Colonnade h r' c
-- ^ Generalize an `OpticColonnade` from `Getter` to `Fold` by defaulting results of zero values to `mempty` -- ^ Generalize an `OpticColonnade` from `Getter` to `Fold` by defaulting results of zero values to `mempty`
emptyOpticColonnade l' c emptyOpticColonnade = emptyOpticColonnade' mempty
emptyOpticColonnade' :: forall h r' focus c.
c
-> Getting (Endo [focus]) r' focus -- ^ View on @focus@ within @r'@ that may produce any number of results
-> ((forall focus'. Getting focus' r' focus) -> Colonnade h r' c) -- ^ `OpticColonnade focus`
-> Colonnade h r' c
-- ^ Generalize an `OpticColonnade` from `Getter` to `Fold` by defaulting results of zero values
emptyOpticColonnade' defC l' c
= Colonnade $ oldColonnade <&> \column -> column { oneColonnadeEncode = \s -> defaultColumn s $ oneColonnadeEncode column } = Colonnade $ oldColonnade <&> \column -> column { oneColonnadeEncode = \s -> defaultColumn s $ oneColonnadeEncode column }
where where
l :: Fold r' focus l :: Fold r' focus
@ -925,7 +932,7 @@ emptyOpticColonnade l' c
defaultColumn :: r' -> (r' -> c) -> c defaultColumn :: r' -> (r' -> c) -> c
defaultColumn x f defaultColumn x f
| has l x = f x | has l x = f x
| otherwise = mempty | otherwise = defC
maybeOpticSortColumn :: OpticSortColumn (Maybe val) -> OpticSortColumn val maybeOpticSortColumn :: OpticSortColumn (Maybe val) -> OpticSortColumn val
maybeOpticSortColumn sortColumn = \queryFocus -> sortColumn $ queryFocus . to E.just maybeOpticSortColumn sortColumn = \queryFocus -> sortColumn $ queryFocus . to E.just