Merge branch 'master' of gitlab.cip.ifi.lmu.de:jost/UniWorX
This commit is contained in:
commit
ae64b10d5c
@ -50,3 +50,7 @@ SubmissionAlreadyExistsFor user@Text: #{user} hat bereits eine Abgabe zu diesem
|
|||||||
EMailUnknown email@Text: E-Mail #{email} gehört zu keinem bekannten Benutzer.
|
EMailUnknown email@Text: E-Mail #{email} gehört zu keinem bekannten Benutzer.
|
||||||
NotAParticipant user@Text tid@TermIdentifier csh@Text: #{user} ist nicht im Kurs #{termToText tid}-#{csh} angemeldet.
|
NotAParticipant user@Text tid@TermIdentifier csh@Text: #{user} ist nicht im Kurs #{termToText tid}-#{csh} angemeldet.
|
||||||
|
|
||||||
|
HomeHeading: Startseite
|
||||||
|
TermsHeading: Semesterübersicht
|
||||||
|
|
||||||
|
NumCourses n@Int64: #{tshow n} Kurse
|
||||||
@ -1,7 +1,7 @@
|
|||||||
{-# LANGUAGE NoImplicitPrelude #-}
|
{-# LANGUAGE NoImplicitPrelude #-}
|
||||||
{-# LANGUAGE OverloadedStrings #-}
|
{-# LANGUAGE OverloadedStrings #-}
|
||||||
{-# LANGUAGE OverloadedLists #-}
|
{-# LANGUAGE OverloadedLists #-}
|
||||||
{-# LANGUAGE TemplateHaskell #-}
|
{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
|
||||||
{-# LANGUAGE MultiParamTypeClasses #-}
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
{-# LANGUAGE ViewPatterns #-}
|
{-# LANGUAGE ViewPatterns #-}
|
||||||
@ -445,11 +445,14 @@ instance Yesod UniWorX where
|
|||||||
-- value passed to hamletToRepHtml cannot be a widget, this allows
|
-- value passed to hamletToRepHtml cannot be a widget, this allows
|
||||||
-- you to use normal widget features in default-layout.
|
-- you to use normal widget features in default-layout.
|
||||||
|
|
||||||
|
|
||||||
let
|
let
|
||||||
navbar :: Widget
|
navbar :: Widget
|
||||||
navbar = $(widgetFile "widgets/navbar")
|
navbar = $(widgetFile "widgets/navbar")
|
||||||
asidenav :: Widget
|
asidenav :: Widget
|
||||||
asidenav = $(widgetFile "widgets/asidenav")
|
asidenav = $(widgetFile "widgets/asidenav")
|
||||||
|
contentHeadline :: Maybe Widget
|
||||||
|
contentHeadline = pageHeading =<< mcurrentRoute
|
||||||
breadcrumbs :: Widget
|
breadcrumbs :: Widget
|
||||||
breadcrumbs = $(widgetFile "widgets/breadcrumbs")
|
breadcrumbs = $(widgetFile "widgets/breadcrumbs")
|
||||||
pageactionprime :: Widget
|
pageactionprime :: Widget
|
||||||
@ -606,6 +609,14 @@ pageActions (TermCourseListR _) =
|
|||||||
|
|
||||||
pageActions _ = []
|
pageActions _ = []
|
||||||
|
|
||||||
|
pageHeading :: Route UniWorX -> Maybe Widget
|
||||||
|
pageHeading HomeR
|
||||||
|
= Just [whamlet|_{MsgHomeHeading}|]
|
||||||
|
pageHeading TermShowR
|
||||||
|
= Just [whamlet|_{MsgTermsHeading}|]
|
||||||
|
pageHeading _
|
||||||
|
= Nothing
|
||||||
|
|
||||||
defaultLinks :: [MenuTypes]
|
defaultLinks :: [MenuTypes]
|
||||||
defaultLinks = -- Define the menu items of the header.
|
defaultLinks = -- Define the menu items of the header.
|
||||||
[ NavbarRight $ MenuItem
|
[ NavbarRight $ MenuItem
|
||||||
@ -633,21 +644,15 @@ defaultLinks = -- Define the menu items of the header.
|
|||||||
, menuItemAccessCallback' = isJust <$> maybeAuthPair
|
, menuItemAccessCallback' = isJust <$> maybeAuthPair
|
||||||
}
|
}
|
||||||
, NavbarAside $ MenuItem
|
, NavbarAside $ MenuItem
|
||||||
{ menuItemLabel = "Aktuelle Veranstaltungen"
|
{ menuItemLabel = "Veranstaltungen"
|
||||||
, menuItemIcon = Just "book"
|
, menuItemIcon = Just "book"
|
||||||
, menuItemRoute = CourseListR -- should be CourseListActiveR or similar in the future
|
, menuItemRoute = CourseListR -- should be CourseListActiveR or similar in the future
|
||||||
, menuItemAccessCallback' = return True
|
, menuItemAccessCallback' = return True
|
||||||
}
|
}
|
||||||
, NavbarAside $ MenuItem
|
, NavbarAside $ MenuItem
|
||||||
{ menuItemLabel = "Alte Veranstaltungen"
|
{ menuItemLabel = "Semester"
|
||||||
, menuItemIcon = Just "book"
|
, menuItemIcon = Nothing
|
||||||
, menuItemRoute = CourseListR -- should be CourseListInactiveR or similar in the future
|
, menuItemRoute = CourseListR -- should be TermListR ,,,
|
||||||
, menuItemAccessCallback' = return True
|
|
||||||
}
|
|
||||||
, NavbarAside $ MenuItem
|
|
||||||
{ menuItemLabel = "Veranstaltungen"
|
|
||||||
, menuItemIcon = Just "book"
|
|
||||||
, menuItemRoute = CourseListR
|
|
||||||
, menuItemAccessCallback' = return True
|
, menuItemAccessCallback' = return True
|
||||||
}
|
}
|
||||||
, NavbarAside $ MenuItem
|
, NavbarAside $ MenuItem
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
{-# LANGUAGE FlexibleInstances #-}
|
{-# LANGUAGE FlexibleInstances #-}
|
||||||
|
{-# LANGUAGE TypeOperators #-}
|
||||||
|
|
||||||
module Handler.Sheet where
|
module Handler.Sheet where
|
||||||
|
|
||||||
@ -154,7 +155,7 @@ getSheetList courseEnt = do
|
|||||||
rated <- count $ (SubmissionRatingTime !=. Nothing):sheetsub
|
rated <- count $ (SubmissionRatingTime !=. Nothing):sheetsub
|
||||||
return (sid, sheet, (submissions, rated))
|
return (sid, sheet, (submissions, rated))
|
||||||
let colBase = mconcat
|
let colBase = mconcat
|
||||||
[ headed "Blatt" $ \(sid,sheet,_) -> linkButton (toWgt $ sheetName sheet) BCLink $ CSheetR tid csh (sheetName sheet) SShowR
|
[ headed "Blatt" $ \(sid,sheet,_) -> simpleLink (toWgt $ sheetName sheet) $ CSheetR tid csh (sheetName sheet) SShowR
|
||||||
, headed "Abgabe ab" $ toWgt . formatTimeGerWD . sheetActiveFrom . snd3
|
, headed "Abgabe ab" $ toWgt . formatTimeGerWD . sheetActiveFrom . snd3
|
||||||
, headed "Abgabe bis" $ toWgt . formatTimeGerWD . sheetActiveTo . snd3
|
, headed "Abgabe bis" $ toWgt . formatTimeGerWD . sheetActiveTo . snd3
|
||||||
, headed "Bewertung" $ toWgt . show . sheetType . snd3
|
, headed "Bewertung" $ toWgt . show . sheetType . snd3
|
||||||
@ -162,8 +163,8 @@ getSheetList courseEnt = do
|
|||||||
let colAdmin = mconcat -- only show edit button for allowed course assistants
|
let colAdmin = mconcat -- only show edit button for allowed course assistants
|
||||||
[ headed "Korrigiert" $ toWgt . snd . trd3
|
[ headed "Korrigiert" $ toWgt . snd . trd3
|
||||||
, headed "Eingereicht" $ toWgt . fst . trd3
|
, headed "Eingereicht" $ toWgt . fst . trd3
|
||||||
, headed "" $ \s -> linkButton "Edit" BCLink $ CSheetR tid csh (sheetName $ snd3 s) SEditR
|
, headed "" $ \s -> simpleLink "Edit" $ CSheetR tid csh (sheetName $ snd3 s) SEditR
|
||||||
, headed "" $ \s -> linkButton "Delete" BCLink $ CSheetR tid csh (sheetName $ snd3 s) SDelR
|
, headed "" $ \s -> simpleLink "Delete" $ CSheetR tid csh (sheetName $ snd3 s) SDelR
|
||||||
]
|
]
|
||||||
showAdmin <- case sheets of
|
showAdmin <- case sheets of
|
||||||
((_,firstSheet,_):_) -> do
|
((_,firstSheet,_):_) -> do
|
||||||
@ -209,10 +210,10 @@ getSShowR tid csh shn = do
|
|||||||
-- return desired columns
|
-- return desired columns
|
||||||
return $ (file E.^. FileTitle, file E.^. FileModified, sheetFile E.^. SheetFileType)
|
return $ (file E.^. FileTitle, file E.^. FileModified, sheetFile E.^. SheetFileType)
|
||||||
let colonnadeFiles = mconcat
|
let colonnadeFiles = mconcat
|
||||||
[ sortable (Just "type") "Typ" $ \(_, (_,_, E.Value ftype)) -> textCell $ toPathPiece ftype
|
[ sortable (Just "type") "Typ" $ \(_,_, E.Value ftype) -> textCell $ toPathPiece ftype
|
||||||
, sortable (Just "path") "Dateiname" $ anchorCell (\(_, (E.Value fName,_,E.Value fType)) -> CSheetR tid csh shn (SFileR fType fName))
|
, sortable (Just "path") "Dateiname" $ anchorCell (\(E.Value fName,_,E.Value fType) -> CSheetR tid csh shn (SFileR fType fName))
|
||||||
(\(_, (E.Value fName,_,_)) -> str2widget fName)
|
(\(E.Value fName,_,_) -> str2widget fName)
|
||||||
, sortable (Just "time") "Modifikation" $ \(_, (_,E.Value modified,_)) -> stringCell $ formatTimeGerWDT modified
|
, sortable (Just "time") "Modifikation" $ \(_,E.Value modified,_) -> stringCell $ formatTimeGerWDT (modified :: UTCTime)
|
||||||
]
|
]
|
||||||
fileTable <- dbTable def $ DBTable
|
fileTable <- dbTable def $ DBTable
|
||||||
{ dbtSQLQuery = fileData
|
{ dbtSQLQuery = fileData
|
||||||
|
|||||||
@ -238,9 +238,9 @@ submissionHelper tid csh shn (SubmissionMode mcid) = do
|
|||||||
-- Maybe construct a table to display uploaded archive files
|
-- Maybe construct a table to display uploaded archive files
|
||||||
let colonnadeFiles cid = mconcat
|
let colonnadeFiles cid = mconcat
|
||||||
-- [ sortable (Just "type") "Typ" $ \(_,_, E.Value ftype) -> textCell $ toPathPiece ftype
|
-- [ sortable (Just "type") "Typ" $ \(_,_, E.Value ftype) -> textCell $ toPathPiece ftype
|
||||||
[ sortable (Just "path") "Dateiname" $ anchorCell (\(_, (Entity _ File{..})) -> SubmissionDownloadSingleR cid fileTitle)
|
[ sortable (Just "path") "Dateiname" $ anchorCell (\(Entity _ File{..}) -> SubmissionDownloadSingleR cid fileTitle)
|
||||||
(\(_, (Entity _ File{..})) -> str2widget fileTitle)
|
(\(Entity _ File{..}) -> str2widget fileTitle)
|
||||||
, sortable (Just "time") "Modifikation" $ \(_, (Entity _ File{..})) -> stringCell $ formatTimeGerWDT fileModified
|
, sortable (Just "time") "Modifikation" $ \(Entity _ File{..}) -> stringCell $ formatTimeGerWDT fileModified
|
||||||
]
|
]
|
||||||
smid2ArchiveTable (smid,cid) = DBTable
|
smid2ArchiveTable (smid,cid) = DBTable
|
||||||
{ dbtSQLQuery = submissionFileQuery smid
|
{ dbtSQLQuery = submissionFileQuery smid
|
||||||
@ -254,6 +254,7 @@ submissionHelper tid csh shn (SubmissionMode mcid) = do
|
|||||||
, SortColumn $ \(sf `E.InnerJoin` f) -> f E.^. FileModified
|
, SortColumn $ \(sf `E.InnerJoin` f) -> f E.^. FileModified
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
, dbtFilter = []
|
||||||
}
|
}
|
||||||
mFileTable <- traverse (dbTable def) . fmap smid2ArchiveTable $ (,) <$> msmid <*> mcid
|
mFileTable <- traverse (dbTable def) . fmap smid2ArchiveTable $ (,) <$> msmid <*> mcid
|
||||||
|
|
||||||
|
|||||||
@ -31,10 +31,10 @@ getTermShowR = do
|
|||||||
-- return term
|
-- return term
|
||||||
--
|
--
|
||||||
let
|
let
|
||||||
|
termData :: E.SqlExpr (Entity Term) -> E.SqlQuery (E.SqlExpr (Entity Term), E.SqlExpr (E.Value Int64))
|
||||||
termData term = do
|
termData term = do
|
||||||
-- E.orderBy [E.desc $ term E.^. TermStart ]
|
-- E.orderBy [E.desc $ term E.^. TermStart ]
|
||||||
let courseCount :: E.SqlExpr (E.Value Int)
|
let courseCount = E.sub_select . E.from $ \course -> do
|
||||||
courseCount = E.sub_select . E.from $ \course -> do
|
|
||||||
E.where_ $ term E.^. TermId E.==. course E.^. CourseTerm
|
E.where_ $ term E.^. TermId E.==. course E.^. CourseTerm
|
||||||
return E.countRows
|
return E.countRows
|
||||||
return (term, courseCount)
|
return (term, courseCount)
|
||||||
@ -42,7 +42,7 @@ getTermShowR = do
|
|||||||
provideRep $ toJSON . map fst <$> runDB (E.select $ E.from termData)
|
provideRep $ toJSON . map fst <$> runDB (E.select $ E.from termData)
|
||||||
provideRep $ do
|
provideRep $ do
|
||||||
let colonnadeTerms = mconcat
|
let colonnadeTerms = mconcat
|
||||||
[ sortable Nothing "Kürzel" $ \(_, (Entity tid Term{..},_)) -> cell $ do
|
[ sortable Nothing "Kürzel" $ \(Entity tid Term{..},_) -> cell $ do
|
||||||
-- Scrap this if to slow, create term edit page instead
|
-- Scrap this if to slow, create term edit page instead
|
||||||
adminLink <- handlerToWidget $ isAuthorized (TermEditExistR tid) False
|
adminLink <- handlerToWidget $ isAuthorized (TermEditExistR tid) False
|
||||||
[whamlet|
|
[whamlet|
|
||||||
@ -52,22 +52,20 @@ getTermShowR = do
|
|||||||
$else
|
$else
|
||||||
#{termToText termName}
|
#{termToText termName}
|
||||||
|]
|
|]
|
||||||
, sortable (Just "lecture-start") "Beginn Vorlesungen" $ \(_, (Entity _ Term{..},_)) ->
|
, sortable (Just "lecture-start") "Beginn Vorlesungen" $ \(Entity _ Term{..},_) ->
|
||||||
stringCell $ formatTimeGerWD termLectureStart
|
stringCell $ formatTimeGerWD termLectureStart
|
||||||
, sortable (Just "lecture-end") "Ende Vorlesungen" $ \(_, (Entity _ Term{..},_)) ->
|
, sortable (Just "lecture-end") "Ende Vorlesungen" $ \(Entity _ Term{..},_) ->
|
||||||
stringCell $ formatTimeGerWD termLectureEnd
|
stringCell $ formatTimeGerWD termLectureEnd
|
||||||
, sortable Nothing "Aktiv" $ \(_, (Entity _ Term{..},_)) ->
|
, sortable Nothing "Aktiv" $ \(Entity _ Term{..},_) ->
|
||||||
textCell $ bool "" tickmark termActive
|
textCell $ bool "" tickmark termActive
|
||||||
, sortable Nothing "Kursliste" $ \(_, (Entity tid Term{..}, E.Value numCourses)) ->
|
, sortable Nothing "Kursliste" $ anchorCell
|
||||||
cell [whamlet|
|
(\(Entity tid _, _) -> TermCourseListR tid)
|
||||||
<a href=@{TermCourseListR tid}>
|
(\(_, E.Value numCourses) -> [whamlet|_{MsgNumCourses numCourses}|])
|
||||||
#{show numCourses} Kurse
|
, sortable (Just "start") "Semesteranfang" $ \(Entity _ Term{..},_) ->
|
||||||
|]
|
|
||||||
, sortable (Just "start") "Semesteranfang" $ \(_, (Entity _ Term{..},_)) ->
|
|
||||||
stringCell $ formatTimeGerWD termStart
|
stringCell $ formatTimeGerWD termStart
|
||||||
, sortable (Just "end") "Semesterende" $ \(_, (Entity _ Term{..},_)) ->
|
, sortable (Just "end") "Semesterende" $ \(Entity _ Term{..},_) ->
|
||||||
stringCell $ formatTimeGerWD termEnd
|
stringCell $ formatTimeGerWD termEnd
|
||||||
, sortable Nothing "Feiertage im Semester" $ \(_, (Entity _ Term{..},_)) ->
|
, sortable Nothing "Feiertage im Semester" $ \(Entity _ Term{..},_) ->
|
||||||
stringCell $ (intercalate ", ") $ map formatTimeGerWD termHolidays
|
stringCell $ (intercalate ", ") $ map formatTimeGerWD termHolidays
|
||||||
]
|
]
|
||||||
table <- dbTable def $ DBTable
|
table <- dbTable def $ DBTable
|
||||||
@ -86,6 +84,10 @@ getTermShowR = do
|
|||||||
, SortColumn $ \term -> term E.^. TermLectureEnd
|
, SortColumn $ \term -> term E.^. TermLectureEnd
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
, dbtFilter = [ ( "active"
|
||||||
|
, FilterColumn $ \term -> (term E.^. TermActive :: E.SqlExpr (E.Value Bool))
|
||||||
|
)
|
||||||
|
]
|
||||||
, dbtAttrs = tableDefault
|
, dbtAttrs = tableDefault
|
||||||
, dbtIdent = "terms" :: Text
|
, dbtIdent = "terms" :: Text
|
||||||
}
|
}
|
||||||
|
|||||||
@ -135,6 +135,8 @@ linkButton lbl cls url = [whamlet| <a href=@{url} .btn .#{bcc2txt cls} role=butt
|
|||||||
-- |]
|
-- |]
|
||||||
-- <input .btn .#{bcc2txt cls} type="submit" value=^{lbl}>
|
-- <input .btn .#{bcc2txt cls} type="submit" value=^{lbl}>
|
||||||
|
|
||||||
|
simpleLink :: Widget -> Route UniWorX -> Widget
|
||||||
|
simpleLink lbl url = [whamlet| <a href=@{url}>^{lbl} |]
|
||||||
|
|
||||||
buttonField :: Button a => a -> Field Handler a
|
buttonField :: Button a => a -> Field Handler a
|
||||||
buttonField btn = Field {fieldParse, fieldView, fieldEnctype}
|
buttonField btn = Field {fieldParse, fieldView, fieldEnctype}
|
||||||
|
|||||||
@ -7,10 +7,15 @@
|
|||||||
, LambdaCase
|
, LambdaCase
|
||||||
, ViewPatterns
|
, ViewPatterns
|
||||||
, FlexibleContexts
|
, FlexibleContexts
|
||||||
|
, FlexibleInstances
|
||||||
|
, MultiParamTypeClasses
|
||||||
|
, TypeFamilies
|
||||||
#-}
|
#-}
|
||||||
|
|
||||||
module Handler.Utils.Table.Pagination
|
module Handler.Utils.Table.Pagination
|
||||||
( SortColumn(..), SortDirection(..)
|
( SortColumn(..), SortDirection(..)
|
||||||
|
, FilterColumn(..), IsFilterColumn
|
||||||
|
, DBRow(..), DBOutput
|
||||||
, DBTable(..)
|
, DBTable(..)
|
||||||
, PaginationSettings(..)
|
, PaginationSettings(..)
|
||||||
, PSValidator(..)
|
, PSValidator(..)
|
||||||
@ -36,11 +41,14 @@ import qualified Network.Wai as Wai
|
|||||||
import Data.CaseInsensitive (CI)
|
import Data.CaseInsensitive (CI)
|
||||||
import qualified Data.CaseInsensitive as CI
|
import qualified Data.CaseInsensitive as CI
|
||||||
|
|
||||||
import Control.Monad.RWS hiding ((<>), Foldable(..), mapM_)
|
import Control.Monad.RWS hiding ((<>), Foldable(..), mapM_, forM_)
|
||||||
|
|
||||||
import Data.Map (Map, (!))
|
import Data.Map (Map, (!))
|
||||||
|
import qualified Data.Map as Map
|
||||||
|
|
||||||
import Colonnade hiding (bool, fromMaybe)
|
import Data.Profunctor (lmap)
|
||||||
|
|
||||||
|
import Colonnade hiding (bool, fromMaybe, singleton)
|
||||||
import Colonnade.Encode
|
import Colonnade.Encode
|
||||||
import Yesod.Colonnade
|
import Yesod.Colonnade
|
||||||
|
|
||||||
@ -65,21 +73,64 @@ sqlSortDirection :: t -> (SortColumn t, SortDirection) -> E.SqlExpr E.OrderBy
|
|||||||
sqlSortDirection t (SortColumn e, SortAsc ) = E.asc $ e t
|
sqlSortDirection t (SortColumn e, SortAsc ) = E.asc $ e t
|
||||||
sqlSortDirection t (SortColumn e, SortDesc) = E.desc $ e t
|
sqlSortDirection t (SortColumn e, SortDesc) = E.desc $ e t
|
||||||
|
|
||||||
data DBTable = forall a r h i t.
|
|
||||||
( ToSortable h
|
data FilterColumn t = forall a. IsFilterColumn t a => FilterColumn a
|
||||||
, E.SqlSelect a r
|
|
||||||
|
filterColumn :: FilterColumn t -> [Text] -> t -> E.SqlExpr (E.Value Bool)
|
||||||
|
filterColumn (FilterColumn f) = filterColumn' f
|
||||||
|
|
||||||
|
class IsFilterColumn t a where
|
||||||
|
filterColumn' :: a -> [Text] -> t -> E.SqlExpr (E.Value Bool)
|
||||||
|
|
||||||
|
instance IsFilterColumn t (E.SqlExpr (E.Value Bool)) where
|
||||||
|
filterColumn' fin _ _ = fin
|
||||||
|
|
||||||
|
instance IsFilterColumn t cont => IsFilterColumn t (t -> cont) where
|
||||||
|
filterColumn' cont is t = filterColumn' (cont t) is t
|
||||||
|
|
||||||
|
instance {-# OVERLAPPABLE #-} (PathPiece (Element l), IsFilterColumn t cont, MonoPointed l, Monoid l) => IsFilterColumn t (l -> cont) where
|
||||||
|
filterColumn' cont is t = filterColumn' (cont input) is' t
|
||||||
|
where
|
||||||
|
(input, ($ []) -> is') = go (mempty, id) is
|
||||||
|
go acc [] = acc
|
||||||
|
go (acc, is') (i:is)
|
||||||
|
| Just i' <- fromPathPiece i = go (acc `mappend` singleton i', is') is
|
||||||
|
| otherwise = go (acc, is' . (i:)) is
|
||||||
|
|
||||||
|
|
||||||
|
data DBRow r = DBRow
|
||||||
|
{ dbrIndex, dbrCount :: Int64
|
||||||
|
, dbrOutput :: r
|
||||||
|
}
|
||||||
|
|
||||||
|
class DBOutput r r' where
|
||||||
|
dbProj :: r -> r'
|
||||||
|
|
||||||
|
instance DBOutput r r where
|
||||||
|
dbProj = id
|
||||||
|
instance DBOutput (DBRow r) r where
|
||||||
|
dbProj = dbrOutput
|
||||||
|
instance DBOutput (DBRow r) (Int64, r) where
|
||||||
|
dbProj = (,) <$> dbrIndex <*> dbrOutput
|
||||||
|
|
||||||
|
|
||||||
|
data DBTable = forall a r r' h i t.
|
||||||
|
( ToSortable h, Functor h
|
||||||
|
, E.SqlSelect a r, DBOutput (DBRow r) r'
|
||||||
, PathPiece i
|
, PathPiece i
|
||||||
, E.From E.SqlQuery E.SqlExpr E.SqlBackend t
|
, E.From E.SqlQuery E.SqlExpr E.SqlBackend t
|
||||||
) => DBTable
|
) => DBTable
|
||||||
{ dbtSQLQuery :: t -> E.SqlQuery a
|
{ dbtSQLQuery :: t -> E.SqlQuery a
|
||||||
, dbtColonnade :: Colonnade h (Int64, r) (Cell UniWorX)
|
, dbtColonnade :: Colonnade h r' (Cell UniWorX)
|
||||||
, dbtSorting :: Map Text (SortColumn t)
|
, dbtSorting :: Map Text (SortColumn t)
|
||||||
|
, dbtFilter :: Map Text (FilterColumn t)
|
||||||
, dbtAttrs :: Attribute
|
, dbtAttrs :: Attribute
|
||||||
, dbtIdent :: i
|
, dbtIdent :: i
|
||||||
}
|
}
|
||||||
|
|
||||||
data PaginationSettings = PaginationSettings
|
data PaginationSettings = PaginationSettings
|
||||||
{ psSorting :: [(Text, SortDirection)]
|
{ psSorting :: [(Text, SortDirection)]
|
||||||
|
, psFilter :: Map Text [Text]
|
||||||
, psLimit :: Int64
|
, psLimit :: Int64
|
||||||
, psPage :: Int64
|
, psPage :: Int64
|
||||||
, psShortcircuit :: Bool
|
, psShortcircuit :: Bool
|
||||||
@ -88,15 +139,16 @@ data PaginationSettings = PaginationSettings
|
|||||||
instance Default PaginationSettings where
|
instance Default PaginationSettings where
|
||||||
def = PaginationSettings
|
def = PaginationSettings
|
||||||
{ psSorting = []
|
{ psSorting = []
|
||||||
|
, psFilter = Map.empty
|
||||||
, psLimit = 50
|
, psLimit = 50
|
||||||
, psPage = 0
|
, psPage = 0
|
||||||
, psShortcircuit = False
|
, psShortcircuit = False
|
||||||
}
|
}
|
||||||
|
|
||||||
newtype PSValidator = PSValidator { runPSValidator :: Maybe PaginationSettings -> ([SomeMessage UniWorX], PaginationSettings) }
|
newtype PSValidator = PSValidator { runPSValidator :: DBTable -> Maybe PaginationSettings -> ([SomeMessage UniWorX], PaginationSettings) }
|
||||||
|
|
||||||
instance Default PSValidator where
|
instance Default PSValidator where
|
||||||
def = PSValidator $ \case
|
def = PSValidator $ \DBTable{..} -> \case
|
||||||
Nothing -> def
|
Nothing -> def
|
||||||
Just ps -> swap . (\act -> execRWS act () ps) $ do
|
Just ps -> swap . (\act -> execRWS act () ps) $ do
|
||||||
l <- gets psLimit
|
l <- gets psLimit
|
||||||
@ -106,7 +158,7 @@ instance Default PSValidator where
|
|||||||
|
|
||||||
|
|
||||||
dbTable :: PSValidator -> DBTable -> Handler Widget
|
dbTable :: PSValidator -> DBTable -> Handler Widget
|
||||||
dbTable PSValidator{..} DBTable{ dbtIdent = (toPathPiece -> dbtIdent), .. } = do
|
dbTable PSValidator{..} dbtable@(DBTable{ dbtIdent = (toPathPiece -> dbtIdent), dbtColonnade = (lmap dbProj -> dbtColonnade), .. }) = do
|
||||||
let
|
let
|
||||||
sortingOptions = mkOptionList
|
sortingOptions = mkOptionList
|
||||||
[ Option t' (t, d) t'
|
[ Option t' (t, d) t'
|
||||||
@ -114,35 +166,43 @@ dbTable PSValidator{..} DBTable{ dbtIdent = (toPathPiece -> dbtIdent), .. } = do
|
|||||||
, d <- [SortAsc, SortDesc]
|
, d <- [SortAsc, SortDesc]
|
||||||
, let t' = t <> "-" <> toPathPiece d
|
, let t' = t <> "-" <> toPathPiece d
|
||||||
]
|
]
|
||||||
(_, defPS) = runPSValidator Nothing
|
(_, defPS) = runPSValidator dbtable Nothing
|
||||||
wIdent n
|
wIdent n
|
||||||
| not $ null dbtIdent = dbtIdent <> "-" <> n
|
| not $ null dbtIdent = dbtIdent <> "-" <> n
|
||||||
| otherwise = n
|
| otherwise = n
|
||||||
dbtAttrs'
|
dbtAttrs'
|
||||||
| not $ null dbtIdent = Html5.id (fromString $ unpack dbtIdent) <> dbtAttrs
|
| not $ null dbtIdent = Html5.id (fromString $ unpack dbtIdent) <> dbtAttrs
|
||||||
| otherwise = dbtAttrs
|
| otherwise = dbtAttrs
|
||||||
|
multiTextField = Field
|
||||||
|
{ fieldParse = \ts _ -> return . Right $ Just ts
|
||||||
|
, fieldView = undefined
|
||||||
|
, fieldEnctype = UrlEncoded
|
||||||
|
}
|
||||||
|
|
||||||
psResult <- runInputGetResult $ PaginationSettings
|
psResult <- runInputGetResult $ PaginationSettings
|
||||||
<$> (fromMaybe [] <$> iopt (multiSelectField $ return sortingOptions) (wIdent "sorting"))
|
<$> (fromMaybe [] <$> iopt (multiSelectField $ return sortingOptions) (wIdent "sorting"))
|
||||||
|
<*> (Map.mapMaybe ((\args -> args <$ guard (not $ null args)) =<<) <$> Map.traverseWithKey (\k _ -> iopt multiTextField (wIdent $ "filter." <> k)) dbtFilter)
|
||||||
<*> (fromMaybe (psLimit defPS) <$> iopt intField (wIdent "pagesize"))
|
<*> (fromMaybe (psLimit defPS) <$> iopt intField (wIdent "pagesize"))
|
||||||
<*> (fromMaybe (psPage defPS) <$> iopt intField (wIdent "page"))
|
<*> (fromMaybe (psPage defPS) <$> iopt intField (wIdent "page"))
|
||||||
<*> ireq checkBoxField (wIdent "table-only")
|
<*> ireq checkBoxField (wIdent "table-only")
|
||||||
|
|
||||||
$(logDebug) . tshow $ (,,,) <$> (length . psSorting <$> psResult)
|
$(logDebug) . tshow $ (,,,,) <$> (length . psSorting <$> psResult)
|
||||||
<*> (psLimit <$> psResult)
|
<*> (Map.keys . psFilter <$> psResult)
|
||||||
<*> (psPage <$> psResult)
|
<*> (psLimit <$> psResult)
|
||||||
<*> (psShortcircuit <$> psResult)
|
<*> (psPage <$> psResult)
|
||||||
|
<*> (psShortcircuit <$> psResult)
|
||||||
|
|
||||||
let
|
let
|
||||||
(errs, PaginationSettings{..}) = case psResult of
|
(errs, PaginationSettings{..}) = case psResult of
|
||||||
FormSuccess ps -> runPSValidator $ Just ps
|
FormSuccess ps -> runPSValidator dbtable $ Just ps
|
||||||
FormFailure errs -> first (map SomeMessage errs <>) $ runPSValidator Nothing
|
FormFailure errs -> first (map SomeMessage errs <>) $ runPSValidator dbtable Nothing
|
||||||
FormMissing -> runPSValidator Nothing
|
FormMissing -> runPSValidator dbtable Nothing
|
||||||
psSorting' = map (first (dbtSorting !)) psSorting
|
psSorting' = map (first (dbtSorting !)) psSorting
|
||||||
sqlQuery' = E.from $ \t -> dbtSQLQuery t
|
sqlQuery' = E.from $ \t -> dbtSQLQuery t
|
||||||
<* E.orderBy (map (sqlSortDirection t) psSorting')
|
<* E.orderBy (map (sqlSortDirection t) psSorting')
|
||||||
<* E.limit psLimit
|
<* E.limit psLimit
|
||||||
<* E.offset (psPage * psLimit)
|
<* E.offset (psPage * psLimit)
|
||||||
|
<* E.where_ (Map.foldrWithKey (\key args expr -> filterColumn (dbtFilter ! key) args t E.&&. expr) (E.val True) psFilter)
|
||||||
|
|
||||||
mapM_ (addMessageI "warning") errs
|
mapM_ (addMessageI "warning") errs
|
||||||
|
|
||||||
@ -152,7 +212,7 @@ dbTable PSValidator{..} DBTable{ dbtIdent = (toPathPiece -> dbtIdent), .. } = do
|
|||||||
rowCount
|
rowCount
|
||||||
| ((_, E.Value n), _):_ <- rows' = n
|
| ((_, E.Value n), _):_ <- rows' = n
|
||||||
| otherwise = 0
|
| otherwise = 0
|
||||||
rows = map (\((E.Value i, _), r) -> (i, r)) rows'
|
rows = map (\((E.Value i, E.Value n), r) -> DBRow i n r) rows'
|
||||||
|
|
||||||
bool return (sendResponse <=< tblLayout) psShortcircuit $ do
|
bool return (sendResponse <=< tblLayout) psShortcircuit $ do
|
||||||
getParams <- handlerToWidget $ queryToQueryText . Wai.queryString . reqWaiRequest <$> getRequest
|
getParams <- handlerToWidget $ queryToQueryText . Wai.queryString . reqWaiRequest <$> getRequest
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import Colonnade
|
|||||||
import Colonnade.Encode
|
import Colonnade.Encode
|
||||||
|
|
||||||
data Sortable a = Sortable
|
data Sortable a = Sortable
|
||||||
{ sortableKey :: (Maybe Text)
|
{ sortableKey :: Maybe Text
|
||||||
, sortableContent :: a
|
, sortableContent :: a
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,6 +24,9 @@ instance Headedness Sortable where
|
|||||||
headednessExtract = Just $ \(Sortable _ x) -> x
|
headednessExtract = Just $ \(Sortable _ x) -> x
|
||||||
headednessExtractForall = Just $ ExtractForall (\(Sortable _ x) -> x)
|
headednessExtractForall = Just $ ExtractForall (\(Sortable _ x) -> x)
|
||||||
|
|
||||||
|
instance Functor Sortable where
|
||||||
|
fmap f Sortable{..} = Sortable { sortableContent = f sortableContent, .. }
|
||||||
|
|
||||||
newtype SortableP s = SortableP { toSortable :: forall a. s a -> Sortable a}
|
newtype SortableP s = SortableP { toSortable :: forall a. s a -> Sortable a}
|
||||||
|
|
||||||
class Headedness s => ToSortable s where
|
class Headedness s => ToSortable s where
|
||||||
|
|||||||
@ -32,3 +32,6 @@
|
|||||||
.glyphicon--logout::before {
|
.glyphicon--logout::before {
|
||||||
content: '\e163';
|
content: '\e163';
|
||||||
}
|
}
|
||||||
|
.glyphicon--none::before {
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
.tab-group {
|
.tab-group {
|
||||||
/* box-shadow: 0 0 0 18px white, 0 0 0 20px #b3b7c1; */
|
|
||||||
border-top: 2px solid #dcdcdc;
|
border-top: 2px solid #dcdcdc;
|
||||||
padding-top: 30px;
|
padding-top: 30px;
|
||||||
margin-top: 40px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tab-group-openers {
|
.tab-group-openers {
|
||||||
|
|||||||
@ -30,9 +30,13 @@
|
|||||||
$maybe regTo <- courseRegisterTo course
|
$maybe regTo <- courseRegisterTo course
|
||||||
\ bis #{formatTimeGerWD regTo}
|
\ bis #{formatTimeGerWD regTo}
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
<td>
|
||||||
$# if allowed to register
|
$# if allowed to register
|
||||||
<div .course__registration>
|
<div .course__registration.container>
|
||||||
<a href="#">Anmelden
|
<button class="btn btn-primary">
|
||||||
|
<a href="#">Anmelden
|
||||||
|
|
||||||
$# <form method=post action=@{CourseR tid csh CShow} enctype=#{regEnctype}>
|
$# <form method=post action=@{CourseR tid csh CShow} enctype=#{regEnctype}>
|
||||||
$# ^{regWidget}
|
$# ^{regWidget}
|
||||||
@ -63,11 +67,7 @@
|
|||||||
<td>Do 18.04.18
|
<td>Do 18.04.18
|
||||||
<td>NotGraded
|
<td>NotGraded
|
||||||
<tr .no-hover.no-stripe>
|
<tr .no-hover.no-stripe>
|
||||||
<td>
|
<td colspan="4">
|
||||||
<td>
|
|
||||||
<td>
|
|
||||||
<td>
|
|
||||||
<td>
|
|
||||||
<a href="/course/S2018/ffp/ex/new" #modal-toggler__new-sheet>Neues Übungsblatt anlegen
|
<a href="/course/S2018/ffp/ex/new" #modal-toggler__new-sheet>Neues Übungsblatt anlegen
|
||||||
<div .tab data-tab-name="Übungsgruppen">
|
<div .tab data-tab-name="Übungsgruppen">
|
||||||
<h3 .tab-title>Übungsgruppen
|
<h3 .tab-title>Übungsgruppen
|
||||||
@ -82,16 +82,14 @@
|
|||||||
<th>Anmeldung bis
|
<th>Anmeldung bis
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>Gruppe 1
|
||||||
<a href="#">Gruppe 1
|
|
||||||
<td>Montag 10:00 - 12:00
|
<td>Montag 10:00 - 12:00
|
||||||
<td>N/A
|
<td>N/A
|
||||||
<td>2/10
|
<td>2/10
|
||||||
<td>Tutor1 Tutoren
|
<td>Tutor1 Tutoren
|
||||||
<td>Do 21.02.2019, 19:00
|
<td>Do 21.02.2019, 19:00
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>Gruppe 2
|
||||||
<a href="#">Gruppe 2
|
|
||||||
<td>Montag 12:00 - 14:00
|
<td>Montag 12:00 - 14:00
|
||||||
<td>N/A
|
<td>N/A
|
||||||
<td>0/10
|
<td>0/10
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
.course__registration {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
@ -13,6 +13,10 @@
|
|||||||
$with status2 <- bool status "info" (status == "")
|
$with status2 <- bool status "info" (status == "")
|
||||||
<div class="alert alert-#{status2}">#{msg}
|
<div class="alert alert-#{status2}">#{msg}
|
||||||
|
|
||||||
|
$maybe headline <- contentHeadline
|
||||||
|
<h1>
|
||||||
|
^{headline}
|
||||||
|
|
||||||
<!-- prime page actions -->
|
<!-- prime page actions -->
|
||||||
^{pageactionprime}
|
^{pageactionprime}
|
||||||
|
|
||||||
|
|||||||
@ -126,12 +126,11 @@ table {
|
|||||||
|
|
||||||
th, td {
|
th, td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 0 13px 0 7px;
|
padding: 7px;
|
||||||
vertical-align: baseline;
|
vertical-align: baseline;
|
||||||
}
|
}
|
||||||
th:first-child,
|
th:first-child,
|
||||||
td:first-child {
|
td:first-child {
|
||||||
padding-left: 0;
|
|
||||||
border-left: 0;
|
border-left: 0;
|
||||||
}
|
}
|
||||||
th {
|
th {
|
||||||
@ -189,21 +188,15 @@ button,
|
|||||||
transition: all .1s;
|
transition: all .1s;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 4px;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
|
||||||
input.btn-primary,
|
|
||||||
button.btn-primary,
|
|
||||||
a.btn.btn-primary,
|
|
||||||
.btn.btn-primary {
|
|
||||||
background-color: var(--primarybase);
|
|
||||||
}
|
|
||||||
|
|
||||||
input.btn-info,
|
a {
|
||||||
button.btn-info,
|
color: white;
|
||||||
a.btn.btn-info,
|
}
|
||||||
.btn.btn-info {
|
|
||||||
background-color: var(--infobase)
|
a:hover {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type="submit"][disabled],
|
input[type="submit"][disabled],
|
||||||
@ -226,6 +219,20 @@ a.btn:not([disabled]):hover,
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input.btn-primary,
|
||||||
|
button.btn-primary,
|
||||||
|
a.btn.btn-primary,
|
||||||
|
.btn.btn-primary {
|
||||||
|
background-color: var(--primarybase);
|
||||||
|
}
|
||||||
|
|
||||||
|
input.btn-info,
|
||||||
|
button.btn-info,
|
||||||
|
a.btn.btn-info,
|
||||||
|
.btn.btn-info {
|
||||||
|
background-color: var(--infobase)
|
||||||
|
}
|
||||||
|
|
||||||
input[type="submit"].btn-info:hover,
|
input[type="submit"].btn-info:hover,
|
||||||
input[type="button"].btn-info:hover,
|
input[type="button"].btn-info:hover,
|
||||||
button.btn-info:hover,
|
button.btn-info:hover,
|
||||||
@ -237,4 +244,3 @@ a.btn.btn-info:hover,
|
|||||||
.alert-debug {
|
.alert-debug {
|
||||||
background-color: rgb(240, 30, 240);
|
background-color: rgb(240, 30, 240);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,21 +43,3 @@
|
|||||||
^{modal ".toggler2" (Just "Test Inhalt für Modal")}
|
^{modal ".toggler2" (Just "Test Inhalt für Modal")}
|
||||||
<div .btn.toggler2>Klick mich für Content-Test
|
<div .btn.toggler2>Klick mich für Content-Test
|
||||||
<noscript>(Für Modals bitte JS aktivieren)</noscript>
|
<noscript>(Für Modals bitte JS aktivieren)</noscript>
|
||||||
|
|
||||||
<li><br>
|
|
||||||
Multi-File-Input für bereits hochgeladene Dateien:
|
|
||||||
<form>
|
|
||||||
<div .form-group>
|
|
||||||
<label .form-group__label>Datei(en)
|
|
||||||
$# file 1
|
|
||||||
<div .file-checkbox__container>
|
|
||||||
<label .file-checkbox__label.reactive-label.btn for="f2-1">Datenschutz.txt
|
|
||||||
<div .checkbox>
|
|
||||||
<input .file-checkbox id="f2-1" name="f2" value="Datenschutz.txt" type="checkbox">
|
|
||||||
<label for="f2-1">
|
|
||||||
$# file 2
|
|
||||||
<div .file-checkbox__container>
|
|
||||||
<label .file-checkbox__label.reactive-label.btn for="f2-2">fill-db.hs
|
|
||||||
<div .checkbox>
|
|
||||||
<input .file-checkbox id="f2-2" name="f2" value="fill-db.hs" type="checkbox">
|
|
||||||
<label for="f2-2">
|
|
||||||
|
|||||||
@ -6,13 +6,6 @@ $forall FileUploadInfo{..} <- fileInfos
|
|||||||
<input .file-checkbox.js-file-checkbox id=#{fuiHtmlId} name=#{fieldName} :fuiChecked:checked value=#{toPathPiece fuiId} type="checkbox">
|
<input .file-checkbox.js-file-checkbox id=#{fuiHtmlId} name=#{fieldName} :fuiChecked:checked value=#{toPathPiece fuiId} type="checkbox">
|
||||||
<label for=#{fuiHtmlId}>
|
<label for=#{fuiHtmlId}>
|
||||||
|
|
||||||
|
|
||||||
<div .file-checkbox__container.file-checkbox__container--checked>
|
|
||||||
<label .file-checkbox__label.reactive-label.btn for=fi1>file1.txt
|
|
||||||
<div .checkbox>
|
|
||||||
<input .file-checkbox.js-file-checkbox id=fi1 name=file checked value="file1.txt" type="checkbox">
|
|
||||||
<label for=fi1>
|
|
||||||
|
|
||||||
$# new files
|
$# new files
|
||||||
<input type="file" name=#{fieldName} multiple>
|
<input type="file" name=#{fieldName} multiple>
|
||||||
|
|
||||||
|
|||||||
@ -13,7 +13,7 @@ form {
|
|||||||
grid-gap: 5px;
|
grid-gap: 5px;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 10px 0;
|
margin: 17px 0;
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
border-left: 2px solid transparent;
|
border-left: 2px solid transparent;
|
||||||
}
|
}
|
||||||
@ -44,20 +44,37 @@ input[type="password"],
|
|||||||
input[type="url"],
|
input[type="url"],
|
||||||
input[type="number"],
|
input[type="number"],
|
||||||
input[type="email"] {
|
input[type="email"] {
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
/* from bulma.css */
|
||||||
padding: 7px 3px 7px;
|
background-color: #fff;
|
||||||
outline: 0;
|
border-color: #dbdbdb;
|
||||||
border: 0;
|
color: #363636;
|
||||||
border-bottom: 2px solid var(--darkbase);
|
box-shadow: inset 0 2px 3px 1px rgba(50,50,50,.1);
|
||||||
box-shadow: 0 2px 13px rgba(0, 0, 0, 0.05);
|
|
||||||
color: var(--fontbase);
|
|
||||||
transition: all .1s;
|
|
||||||
font-size: 16px;
|
|
||||||
min-width: 400px;
|
min-width: 400px;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: inline-flex;
|
||||||
|
font-size: 1rem;
|
||||||
|
height: 2.25em;
|
||||||
|
justify-content: flex-start;
|
||||||
|
line-height: 1.5;
|
||||||
|
padding-bottom: calc(.375em - 1px);
|
||||||
|
padding-left: calc(.625em - 1px);
|
||||||
|
padding-right: calc(.625em - 1px);
|
||||||
|
padding-top: calc(.375em - 1px);
|
||||||
|
position: relative;
|
||||||
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
.form-group--required {
|
.form-group--required {
|
||||||
|
|
||||||
|
.form-group__label::before {
|
||||||
|
content: '*';
|
||||||
|
position: absolute;
|
||||||
|
left: -14px;
|
||||||
|
}
|
||||||
|
|
||||||
input, textarea {
|
input, textarea {
|
||||||
border-bottom-color: var(--lighterbase);
|
border-bottom-color: var(--lighterbase);
|
||||||
}
|
}
|
||||||
@ -82,32 +99,42 @@ input[type="password"]:focus,
|
|||||||
input[type="url"]:focus,
|
input[type="url"]:focus,
|
||||||
input[type="number"]:focus,
|
input[type="number"]:focus,
|
||||||
input[type="email"]:focus {
|
input[type="email"]:focus {
|
||||||
border-bottom-color: var(--lightbase);
|
/* border-bottom-color: var(--lightbase);
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
box-shadow: 0 0 13px var(--lighterbase);
|
box-shadow: 0 0 13px var(--lighterbase); */
|
||||||
|
border-color: #3273dc;
|
||||||
|
box-shadow: 0 0 0 0.125em rgba(50,115,220,.25);
|
||||||
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* BUTTON STYLE SEE default-layout.lucius */
|
/* BUTTON STYLE SEE default-layout.lucius */
|
||||||
|
|
||||||
/* TEXTAREAS */
|
/* TEXTAREAS */
|
||||||
textarea {
|
textarea {
|
||||||
outline: 0;
|
-webkit-appearance: none;
|
||||||
border: 0;
|
border: 1px solid transparent;
|
||||||
padding: 7px 4px;
|
border-radius: 2px;
|
||||||
min-width: 400px;
|
display: inline-flex;
|
||||||
min-height: 100px;
|
font-size: 1rem;
|
||||||
font-family: var(--fontfamilybase);
|
height: 170px;
|
||||||
font-size: 16px;
|
width: 400px;
|
||||||
color: var(--fontbase);
|
line-height: 1.5;
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
padding-bottom: calc(.375em - 1px);
|
||||||
box-shadow: 0 2px 13px rgba(0, 0, 0, 0.05);
|
padding-left: calc(.625em - 1px);
|
||||||
border-bottom: 2px solid var(--darkbase);
|
padding-right: calc(.625em - 1px);
|
||||||
|
padding-top: calc(.375em - 1px);
|
||||||
|
position: relative;
|
||||||
|
vertical-align: top;
|
||||||
|
background-color: #fff;
|
||||||
|
border-color: #dbdbdb;
|
||||||
|
color: #363636;
|
||||||
|
box-shadow: inset 0 1px 2px rgba(10,10,10,.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
textarea:focus {
|
textarea:focus {
|
||||||
background-color: transparent;
|
border-color: #3273dc;
|
||||||
border-bottom-color: var(--lightbase);
|
box-shadow: 0 0 0 0.125em rgba(50,115,220,.25);
|
||||||
box-shadow: 0 0 13px var(--lighterbase);
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* CUSTOM LEGACY CHECKBOX AND RADIO BOXES */
|
/* CUSTOM LEGACY CHECKBOX AND RADIO BOXES */
|
||||||
|
|||||||
@ -1,4 +1,2 @@
|
|||||||
<div .container>
|
<div .container>
|
||||||
<h1>Semesterübersicht
|
|
||||||
|
|
||||||
^{table}
|
^{table}
|
||||||
|
|||||||
@ -8,8 +8,7 @@ $newline never
|
|||||||
$of NavbarAside (MenuItem label mIcon route _)
|
$of NavbarAside (MenuItem label mIcon route _)
|
||||||
<li .asidenav__list-item :Just route == mcurrentRoute:.asidenav__list-item--active>
|
<li .asidenav__list-item :Just route == mcurrentRoute:.asidenav__list-item--active>
|
||||||
<a .asidenav__link-wrapper href=@{route}>
|
<a .asidenav__link-wrapper href=@{route}>
|
||||||
$if isJust mIcon
|
<div .glyphicon.glyphicon--#{fromMaybe "none" mIcon}>
|
||||||
<div .glyphicon.glyphicon--#{fromMaybe "" mIcon}>
|
|
||||||
<div .asidenav__link-label>#{label}
|
<div .asidenav__link-label>#{label}
|
||||||
$of _
|
$of _
|
||||||
|
|
||||||
|
|||||||
@ -188,7 +188,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
color: var(--greybase);
|
color: var(--greybase);
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
opacity: 0.3;
|
opacity: 0.2;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
top: 0;
|
top: 0;
|
||||||
font-size: 40px;
|
font-size: 40px;
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
.page-nav-prime {
|
.page-nav-prime {
|
||||||
background-color: var(--lightgreybase);
|
background-color: rgba(200, 200, 200, 0.2);
|
||||||
padding: 13px;
|
padding: 13px;
|
||||||
|
margin-top: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-nav-prime .pagenav__list {
|
.page-nav-prime .pagenav__list {
|
||||||
margin: 7px 0 0;
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.page-nav-prime .pagenav__list-item {
|
.page-nav-prime .pagenav__list-item {
|
||||||
|
|||||||
Reference in New Issue
Block a user