247 lines
7.1 KiB
Haskell
247 lines
7.1 KiB
Haskell
-- SPDX-FileCopyrightText: 2022-2024 Gregor Kleen <gregor.kleen@ifi.lmu.de>,Sarah Vaupel <sarah.vaupel@ifi.lmu.de>,Sarah Vaupel <vaupel.sarah@campus.lmu.de>,Steffen Jost <jost@tcs.ifi.lmu.de>,Wolfgang Witt <Wolfgang.Witt@campus.lmu.de>,David Mosbach <david.mosbach@uniworx.de>
|
|
--
|
|
-- SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
module Utils.Icon where
|
|
|
|
import ClassyPrelude.Yesod hiding (Proxy)
|
|
|
|
import Data.Universe
|
|
import Data.Char
|
|
import Utils.PathPiece
|
|
-- import Text.Hamlet
|
|
import Text.Blaze (Markup)
|
|
import Control.Lens
|
|
import Language.Haskell.TH
|
|
import Language.Haskell.TH.Instances ()
|
|
import Language.Haskell.TH.Lift (deriveLift)
|
|
import Instances.TH.Lift ()
|
|
import Data.Aeson
|
|
import Data.Aeson.TH
|
|
|
|
-- | A @Widget@ for any site; no language interpolation, etc.
|
|
type WidgetSiteless = forall site. WidgetFor site ()
|
|
|
|
|
|
-----------
|
|
-- Icons --
|
|
-----------
|
|
-- We collect all used icons here for an overview.
|
|
-- For consistency, some conditional icons are also provided, having suffix True/False
|
|
|
|
---------------------------------------------------------------------------
|
|
-- IMPORTANT:
|
|
-- All icons must be manually registered within the following files:
|
|
-- - src/Utils/Icon.hs
|
|
-- - assets/icon-src/fontawesome.json
|
|
-- - frontend/src/icons.scss
|
|
---------------------------------------------------------------------------
|
|
data Icon
|
|
= IconNew
|
|
| IconOK
|
|
| IconNotOK
|
|
| IconWarning
|
|
| IconProblem
|
|
| IconVisible
|
|
| IconInvisible
|
|
-- | IconCourse -- not used, IconMenuCourse is currently only used
|
|
| IconCourseFavouriteManual | IconCourseFavouriteAutomatic | IconCourseFavouriteOff
|
|
| IconEnrolTrue
|
|
| IconEnrolFalse
|
|
| IconPlanned
|
|
| IconAnnounce
|
|
| IconExam
|
|
| IconExamRegisterTrue
|
|
| IconExamRegisterFalse
|
|
| IconExamAutoOccurrenceNudgeUp
|
|
| IconExamAutoOccurrenceNudgeDown
|
|
| IconExamAutoOccurrenceIgnore
|
|
| IconExamAutoOccurrenceReconsider
|
|
| IconCommentTrue
|
|
| IconCommentFalse
|
|
| IconLink
|
|
| IconFileDownload
|
|
| IconFileUpload
|
|
| IconFileZip
|
|
| IconFileCSV
|
|
| IconSFTQuestion -- for SheetFileType only
|
|
| IconSFTHint -- for SheetFileType only
|
|
| IconSFTSolution -- for SheetFileType only
|
|
| IconSFTMarking -- for SheetFileType only
|
|
| IconEmail
|
|
| IconRegisterTemplate
|
|
| IconNoCorrectors
|
|
| IconTooltipDefault
|
|
| IconNotificationSuccess -- used for popups
|
|
| IconNotificationInfo
|
|
| IconNotificationWarning
|
|
| IconNotificationError
|
|
| IconNotificationNonactive
|
|
| IconNotification -- used for email and lettes
|
|
| IconNoNotification
|
|
| IconNotificationSent
|
|
| IconFavourite
|
|
| IconLanguage
|
|
| IconNavContainerClose | IconPageActionChildrenClose
|
|
| IconMenuNews
|
|
| IconMenuHelp
|
|
| IconMenuProfile
|
|
| IconMenuLogin | IconMenuLogout
|
|
| IconBreadcrumbsHome
|
|
| IconMenuExtra
|
|
| IconMenuCourseList
|
|
| IconMenuCorrections
|
|
| IconMenuExams
|
|
| IconMenuAdmin
|
|
| IconMenuQualification
|
|
| IconMenuLms
|
|
| IconPageActionPrimaryExpand | IconPageActionSecondary
|
|
| IconBreadcrumbSeparator
|
|
| IconFileUploadSession
|
|
| IconStandaloneFieldError
|
|
| IconFileUser
|
|
| IconPersonalIdentification
|
|
| IconMenuWorkflows
|
|
| IconVideo
|
|
| IconSubmissionUserDuplicate
|
|
| IconSubmissionNoUsers
|
|
| IconRemoveUser
|
|
| IconReset
|
|
| IconBlocked
|
|
| IconCertificate
|
|
| IconPrintCenter
|
|
| IconLetter
|
|
| IconAt
|
|
| IconSupervisor
|
|
| IconSupervisorForeign
|
|
-- | IconWaitingForUser
|
|
| IconExpired
|
|
| IconLocked
|
|
| IconUnlocked
|
|
| IconResetTries -- also see IconReset
|
|
| IconCompany
|
|
| IconEdit
|
|
| IconUserEdit
|
|
|
|
deriving (Eq, Ord, Enum, Bounded, Show, Read, Generic)
|
|
deriving anyclass (Universe, Finite, NFData)
|
|
|
|
|
|
iconText :: Icon -> Text
|
|
iconText = camelToPathPiece' 1 . tshow
|
|
|
|
nullaryPathPiece ''Icon $ camelToPathPiece' 1
|
|
deriveLift ''Icon
|
|
|
|
deriveJSON defaultOptions
|
|
{ constructorTagModifier = camelToPathPiece' 1
|
|
} ''Icon
|
|
|
|
-- Create an icon without additional space
|
|
icon :: Icon -> Markup
|
|
icon ic = [shamlet|
|
|
$newline never
|
|
<span .ico-#{iconText ic}>
|
|
|]
|
|
|
|
|
|
-- Create an icon with fixed width
|
|
iconFixed :: Icon -> Markup
|
|
iconFixed ic = [shamlet|
|
|
$newline never
|
|
<span .ico-#{iconText ic} .fw-ico>
|
|
|]
|
|
|
|
|
|
-- Stack two icons without additional space
|
|
iconStacked :: Icon -> Icon -> Markup
|
|
iconStacked ic0 ic1
|
|
= [shamlet|
|
|
$newline never
|
|
<span .icon--stacked>
|
|
<span .ico-#{iconText ic0} .medium-ico>
|
|
<span .ico-#{iconText ic1} .medium-ico>
|
|
|]
|
|
|
|
-- Create an icon (defaults to "?") with a specified tooltip; inline-bool just affects the size of the icon
|
|
iconTooltip :: forall site. WidgetFor site () -> Maybe Icon -> Bool -> WidgetFor site ()
|
|
iconTooltip tooltip mIcon isInlineTooltip = let
|
|
ic = iconText $ fromMaybe IconTooltipDefault mIcon
|
|
urgency = "urgency__info" :: Text
|
|
in $(whamletFile "templates/widgets/tooltip.hamlet")
|
|
|
|
-- declare constats for all icons for compatibility and convenience
|
|
-- "IconCourse" generates "iconCourse = icon IconCourse"
|
|
iconShortcuts :: Q [Dec]
|
|
iconShortcuts = foldMap mkIcon (universeF :: [Icon])
|
|
where
|
|
mkIcon :: Icon -> Q [Dec]
|
|
mkIcon ic = do
|
|
iname <- newName $ over (ix 0) Data.Char.toLower $ show ic
|
|
isig <- sigD iname [t|Markup|]
|
|
idef <- valD (varP iname) (normalB [|icon ic|]) []
|
|
return [isig, idef]
|
|
|
|
|
|
----------------------
|
|
-- Conditional icons
|
|
--
|
|
-- Some case are special, hence no Template Haskell here
|
|
|
|
isVisible :: Bool -> Markup
|
|
-- ^ Display an icon that denotes that something™ is visible or invisible
|
|
isVisible True = icon IconVisible
|
|
isVisible False = icon IconInvisible
|
|
|
|
hasComment :: Bool -> Markup
|
|
-- ^ Display an icon that denotes that something™ has a comment or not
|
|
hasComment True = icon IconCommentTrue
|
|
hasComment False = icon IconCommentFalse
|
|
|
|
hasTickmark :: Bool -> Markup
|
|
-- ^ Maybe display an icon that denotes that something™ is okay
|
|
hasTickmark True = icon IconOK
|
|
hasTickmark False = mempty
|
|
|
|
isBad :: Bool -> Markup
|
|
-- ^ Maybe display an icon that denotes that something™ is bad
|
|
isBad True = icon IconProblem
|
|
isBad False = mempty
|
|
|
|
-- ^ Maybe display an icon that denotes that something™ is bad
|
|
isNew :: Bool -> Markup
|
|
isNew True = icon IconNew
|
|
isNew False = mempty
|
|
|
|
boolSymbol :: Bool -> Markup
|
|
boolSymbol True = icon IconOK
|
|
boolSymbol False = icon IconNotOK
|
|
|
|
iconEnrol :: Bool -> Markup
|
|
iconEnrol True = icon IconEnrolTrue
|
|
iconEnrol False = icon IconEnrolFalse
|
|
|
|
iconExamRegister :: Bool -> Markup
|
|
iconExamRegister True = icon IconExamRegisterTrue
|
|
iconExamRegister False = icon IconExamRegisterFalse
|
|
|
|
iconLetterOrEmail :: Bool -> Markup
|
|
iconLetterOrEmail True = icon IconLetter
|
|
iconLetterOrEmail False = icon IconAt
|
|
|
|
iconQualificationBlock :: Bool -> Markup
|
|
iconQualificationBlock True = icon IconCertificate
|
|
iconQualificationBlock False = icon IconBlocked
|
|
|
|
----------------
|
|
-- For documentation on how to avoid these unneccessary functions
|
|
-- we implement them here just once for the first icon:
|
|
--
|
|
isVisibleWidget :: Bool -> WidgetSiteless
|
|
-- ^ Widget having an icon that denotes that something™ is visible or invisible
|
|
isVisibleWidget = toWidget . isVisible
|
|
|
|
maybeIsVisibleWidget :: Maybe Bool -> WidgetSiteless
|
|
-- ^ Maybe a widget with an icon that denotes that something™ is visible or invisible
|
|
maybeIsVisibleWidget = toWidget . foldMap isVisible
|