Merge branch 'master' of gitlab.cip.ifi.lmu.de:jost/UniWorX

This commit is contained in:
SJost 2018-06-07 17:04:33 +02:00
commit ae64b10d5c
21 changed files with 232 additions and 143 deletions

View File

@ -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.
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

View File

@ -1,7 +1,7 @@
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE OverloadedLists #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TemplateHaskell, QuasiQuotes #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}
@ -445,11 +445,14 @@ instance Yesod UniWorX where
-- value passed to hamletToRepHtml cannot be a widget, this allows
-- you to use normal widget features in default-layout.
let
navbar :: Widget
navbar = $(widgetFile "widgets/navbar")
asidenav :: Widget
asidenav = $(widgetFile "widgets/asidenav")
contentHeadline :: Maybe Widget
contentHeadline = pageHeading =<< mcurrentRoute
breadcrumbs :: Widget
breadcrumbs = $(widgetFile "widgets/breadcrumbs")
pageactionprime :: Widget
@ -476,7 +479,7 @@ instance Yesod UniWorX where
$(widgetFile "standalone/showHide")
$(widgetFile "standalone/inputs")
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
-- The page to be redirected to when authentication is required.
authRoute _ = Just $ AuthR LoginR
@ -606,6 +609,14 @@ pageActions (TermCourseListR _) =
pageActions _ = []
pageHeading :: Route UniWorX -> Maybe Widget
pageHeading HomeR
= Just [whamlet|_{MsgHomeHeading}|]
pageHeading TermShowR
= Just [whamlet|_{MsgTermsHeading}|]
pageHeading _
= Nothing
defaultLinks :: [MenuTypes]
defaultLinks = -- Define the menu items of the header.
[ NavbarRight $ MenuItem
@ -633,21 +644,15 @@ defaultLinks = -- Define the menu items of the header.
, menuItemAccessCallback' = isJust <$> maybeAuthPair
}
, NavbarAside $ MenuItem
{ menuItemLabel = "Aktuelle Veranstaltungen"
{ menuItemLabel = "Veranstaltungen"
, menuItemIcon = Just "book"
, menuItemRoute = CourseListR -- should be CourseListActiveR or similar in the future
, menuItemAccessCallback' = return True
}
, NavbarAside $ MenuItem
{ menuItemLabel = "Alte Veranstaltungen"
, menuItemIcon = Just "book"
, menuItemRoute = CourseListR -- should be CourseListInactiveR or similar in the future
, menuItemAccessCallback' = return True
}
, NavbarAside $ MenuItem
{ menuItemLabel = "Veranstaltungen"
, menuItemIcon = Just "book"
, menuItemRoute = CourseListR
{ menuItemLabel = "Semester"
, menuItemIcon = Nothing
, menuItemRoute = CourseListR -- should be TermListR ,,,
, menuItemAccessCallback' = return True
}
, NavbarAside $ MenuItem

View File

@ -8,6 +8,7 @@
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeOperators #-}
module Handler.Sheet where
@ -154,7 +155,7 @@ getSheetList courseEnt = do
rated <- count $ (SubmissionRatingTime !=. Nothing):sheetsub
return (sid, sheet, (submissions, rated))
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 bis" $ toWgt . formatTimeGerWD . sheetActiveTo . 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
[ headed "Korrigiert" $ toWgt . snd . trd3
, headed "Eingereicht" $ toWgt . fst . trd3
, headed "" $ \s -> linkButton "Edit" BCLink $ CSheetR tid csh (sheetName $ snd3 s) SEditR
, headed "" $ \s -> linkButton "Delete" BCLink $ CSheetR tid csh (sheetName $ snd3 s) SDelR
, headed "" $ \s -> simpleLink "Edit" $ CSheetR tid csh (sheetName $ snd3 s) SEditR
, headed "" $ \s -> simpleLink "Delete" $ CSheetR tid csh (sheetName $ snd3 s) SDelR
]
showAdmin <- case sheets of
((_,firstSheet,_):_) -> do
@ -209,10 +210,10 @@ getSShowR tid csh shn = do
-- return desired columns
return $ (file E.^. FileTitle, file E.^. FileModified, sheetFile E.^. SheetFileType)
let colonnadeFiles = mconcat
[ 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))
(\(_, (E.Value fName,_,_)) -> str2widget fName)
, sortable (Just "time") "Modifikation" $ \(_, (_,E.Value modified,_)) -> stringCell $ formatTimeGerWDT modified
[ 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))
(\(E.Value fName,_,_) -> str2widget fName)
, sortable (Just "time") "Modifikation" $ \(_,E.Value modified,_) -> stringCell $ formatTimeGerWDT (modified :: UTCTime)
]
fileTable <- dbTable def $ DBTable
{ dbtSQLQuery = fileData

View File

@ -238,9 +238,9 @@ submissionHelper tid csh shn (SubmissionMode mcid) = do
-- Maybe construct a table to display uploaded archive files
let colonnadeFiles cid = mconcat
-- [ sortable (Just "type") "Typ" $ \(_,_, E.Value ftype) -> textCell $ toPathPiece ftype
[ sortable (Just "path") "Dateiname" $ anchorCell (\(_, (Entity _ File{..})) -> SubmissionDownloadSingleR cid fileTitle)
(\(_, (Entity _ File{..})) -> str2widget fileTitle)
, sortable (Just "time") "Modifikation" $ \(_, (Entity _ File{..})) -> stringCell $ formatTimeGerWDT fileModified
[ sortable (Just "path") "Dateiname" $ anchorCell (\(Entity _ File{..}) -> SubmissionDownloadSingleR cid fileTitle)
(\(Entity _ File{..}) -> str2widget fileTitle)
, sortable (Just "time") "Modifikation" $ \(Entity _ File{..}) -> stringCell $ formatTimeGerWDT fileModified
]
smid2ArchiveTable (smid,cid) = DBTable
{ dbtSQLQuery = submissionFileQuery smid
@ -254,6 +254,7 @@ submissionHelper tid csh shn (SubmissionMode mcid) = do
, SortColumn $ \(sf `E.InnerJoin` f) -> f E.^. FileModified
)
]
, dbtFilter = []
}
mFileTable <- traverse (dbTable def) . fmap smid2ArchiveTable $ (,) <$> msmid <*> mcid

View File

@ -31,10 +31,10 @@ getTermShowR = do
-- return term
--
let
termData :: E.SqlExpr (Entity Term) -> E.SqlQuery (E.SqlExpr (Entity Term), E.SqlExpr (E.Value Int64))
termData term = do
-- E.orderBy [E.desc $ term E.^. TermStart ]
let courseCount :: E.SqlExpr (E.Value Int)
courseCount = E.sub_select . E.from $ \course -> do
let courseCount = E.sub_select . E.from $ \course -> do
E.where_ $ term E.^. TermId E.==. course E.^. CourseTerm
return E.countRows
return (term, courseCount)
@ -42,7 +42,7 @@ getTermShowR = do
provideRep $ toJSON . map fst <$> runDB (E.select $ E.from termData)
provideRep $ do
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
adminLink <- handlerToWidget $ isAuthorized (TermEditExistR tid) False
[whamlet|
@ -52,22 +52,20 @@ getTermShowR = do
$else
#{termToText termName}
|]
, sortable (Just "lecture-start") "Beginn Vorlesungen" $ \(_, (Entity _ Term{..},_)) ->
, sortable (Just "lecture-start") "Beginn Vorlesungen" $ \(Entity _ Term{..},_) ->
stringCell $ formatTimeGerWD termLectureStart
, sortable (Just "lecture-end") "Ende Vorlesungen" $ \(_, (Entity _ Term{..},_)) ->
, sortable (Just "lecture-end") "Ende Vorlesungen" $ \(Entity _ Term{..},_) ->
stringCell $ formatTimeGerWD termLectureEnd
, sortable Nothing "Aktiv" $ \(_, (Entity _ Term{..},_)) ->
, sortable Nothing "Aktiv" $ \(Entity _ Term{..},_) ->
textCell $ bool "" tickmark termActive
, sortable Nothing "Kursliste" $ \(_, (Entity tid Term{..}, E.Value numCourses)) ->
cell [whamlet|
<a href=@{TermCourseListR tid}>
#{show numCourses} Kurse
|]
, sortable (Just "start") "Semesteranfang" $ \(_, (Entity _ Term{..},_)) ->
, sortable Nothing "Kursliste" $ anchorCell
(\(Entity tid _, _) -> TermCourseListR tid)
(\(_, E.Value numCourses) -> [whamlet|_{MsgNumCourses numCourses}|])
, sortable (Just "start") "Semesteranfang" $ \(Entity _ Term{..},_) ->
stringCell $ formatTimeGerWD termStart
, sortable (Just "end") "Semesterende" $ \(_, (Entity _ Term{..},_)) ->
, sortable (Just "end") "Semesterende" $ \(Entity _ Term{..},_) ->
stringCell $ formatTimeGerWD termEnd
, sortable Nothing "Feiertage im Semester" $ \(_, (Entity _ Term{..},_)) ->
, sortable Nothing "Feiertage im Semester" $ \(Entity _ Term{..},_) ->
stringCell $ (intercalate ", ") $ map formatTimeGerWD termHolidays
]
table <- dbTable def $ DBTable
@ -86,6 +84,10 @@ getTermShowR = do
, SortColumn $ \term -> term E.^. TermLectureEnd
)
]
, dbtFilter = [ ( "active"
, FilterColumn $ \term -> (term E.^. TermActive :: E.SqlExpr (E.Value Bool))
)
]
, dbtAttrs = tableDefault
, dbtIdent = "terms" :: Text
}

View File

@ -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}>
simpleLink :: Widget -> Route UniWorX -> Widget
simpleLink lbl url = [whamlet| <a href=@{url}>^{lbl} |]
buttonField :: Button a => a -> Field Handler a
buttonField btn = Field {fieldParse, fieldView, fieldEnctype}

View File

@ -7,10 +7,15 @@
, LambdaCase
, ViewPatterns
, FlexibleContexts
, FlexibleInstances
, MultiParamTypeClasses
, TypeFamilies
#-}
module Handler.Utils.Table.Pagination
( SortColumn(..), SortDirection(..)
, FilterColumn(..), IsFilterColumn
, DBRow(..), DBOutput
, DBTable(..)
, PaginationSettings(..)
, PSValidator(..)
@ -36,11 +41,14 @@ import qualified Network.Wai as Wai
import Data.CaseInsensitive (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 qualified Data.Map as Map
import Colonnade hiding (bool, fromMaybe)
import Data.Profunctor (lmap)
import Colonnade hiding (bool, fromMaybe, singleton)
import Colonnade.Encode
import Yesod.Colonnade
@ -64,22 +72,65 @@ instance PathPiece SortDirection where
sqlSortDirection :: t -> (SortColumn t, SortDirection) -> E.SqlExpr E.OrderBy
sqlSortDirection t (SortColumn e, SortAsc ) = E.asc $ e t
sqlSortDirection t (SortColumn e, SortDesc) = E.desc $ e t
data DBTable = forall a r h i t.
( ToSortable h
, E.SqlSelect a r
data FilterColumn t = forall a. IsFilterColumn t a => FilterColumn a
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
, E.From E.SqlQuery E.SqlExpr E.SqlBackend t
) => DBTable
{ dbtSQLQuery :: t -> E.SqlQuery a
, dbtColonnade :: Colonnade h (Int64, r) (Cell UniWorX)
, dbtColonnade :: Colonnade h r' (Cell UniWorX)
, dbtSorting :: Map Text (SortColumn t)
, dbtFilter :: Map Text (FilterColumn t)
, dbtAttrs :: Attribute
, dbtIdent :: i
}
data PaginationSettings = PaginationSettings
{ psSorting :: [(Text, SortDirection)]
, psFilter :: Map Text [Text]
, psLimit :: Int64
, psPage :: Int64
, psShortcircuit :: Bool
@ -88,15 +139,16 @@ data PaginationSettings = PaginationSettings
instance Default PaginationSettings where
def = PaginationSettings
{ psSorting = []
, psFilter = Map.empty
, psLimit = 50
, psPage = 0
, 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
def = PSValidator $ \case
def = PSValidator $ \DBTable{..} -> \case
Nothing -> def
Just ps -> swap . (\act -> execRWS act () ps) $ do
l <- gets psLimit
@ -106,7 +158,7 @@ instance Default PSValidator where
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
sortingOptions = mkOptionList
[ Option t' (t, d) t'
@ -114,35 +166,43 @@ dbTable PSValidator{..} DBTable{ dbtIdent = (toPathPiece -> dbtIdent), .. } = do
, d <- [SortAsc, SortDesc]
, let t' = t <> "-" <> toPathPiece d
]
(_, defPS) = runPSValidator Nothing
(_, defPS) = runPSValidator dbtable Nothing
wIdent n
| not $ null dbtIdent = dbtIdent <> "-" <> n
| otherwise = n
dbtAttrs'
| not $ null dbtIdent = Html5.id (fromString $ unpack dbtIdent) <> dbtAttrs
| otherwise = dbtAttrs
multiTextField = Field
{ fieldParse = \ts _ -> return . Right $ Just ts
, fieldView = undefined
, fieldEnctype = UrlEncoded
}
psResult <- runInputGetResult $ PaginationSettings
<$> (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 (psPage defPS) <$> iopt intField (wIdent "page"))
<*> ireq checkBoxField (wIdent "table-only")
$(logDebug) . tshow $ (,,,) <$> (length . psSorting <$> psResult)
<*> (psLimit <$> psResult)
<*> (psPage <$> psResult)
<*> (psShortcircuit <$> psResult)
$(logDebug) . tshow $ (,,,,) <$> (length . psSorting <$> psResult)
<*> (Map.keys . psFilter <$> psResult)
<*> (psLimit <$> psResult)
<*> (psPage <$> psResult)
<*> (psShortcircuit <$> psResult)
let
(errs, PaginationSettings{..}) = case psResult of
FormSuccess ps -> runPSValidator $ Just ps
FormFailure errs -> first (map SomeMessage errs <>) $ runPSValidator Nothing
FormMissing -> runPSValidator Nothing
FormSuccess ps -> runPSValidator dbtable $ Just ps
FormFailure errs -> first (map SomeMessage errs <>) $ runPSValidator dbtable Nothing
FormMissing -> runPSValidator dbtable Nothing
psSorting' = map (first (dbtSorting !)) psSorting
sqlQuery' = E.from $ \t -> dbtSQLQuery t
<* E.orderBy (map (sqlSortDirection t) psSorting')
<* E.limit 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
@ -152,7 +212,7 @@ dbTable PSValidator{..} DBTable{ dbtIdent = (toPathPiece -> dbtIdent), .. } = do
rowCount
| ((_, E.Value n), _):_ <- rows' = n
| 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
getParams <- handlerToWidget $ queryToQueryText . Wai.queryString . reqWaiRequest <$> getRequest

View File

@ -12,7 +12,7 @@ import Colonnade
import Colonnade.Encode
data Sortable a = Sortable
{ sortableKey :: (Maybe Text)
{ sortableKey :: Maybe Text
, sortableContent :: a
}
@ -23,6 +23,9 @@ instance Headedness Sortable where
headednessPure = Sortable Nothing
headednessExtract = Just $ \(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}

View File

@ -32,3 +32,6 @@
.glyphicon--logout::before {
content: '\e163';
}
.glyphicon--none::before {
content: '';
}

View File

@ -1,8 +1,6 @@
.tab-group {
/* box-shadow: 0 0 0 18px white, 0 0 0 20px #b3b7c1; */
border-top: 2px solid #dcdcdc;
padding-top: 30px;
margin-top: 40px;
}
.tab-group-openers {

View File

@ -30,9 +30,13 @@
$maybe regTo <- courseRegisterTo course
\ bis #{formatTimeGerWD regTo}
<tr>
<th>
<td>
$# if allowed to register
<div .course__registration>
<a href="#">Anmelden
<div .course__registration.container>
<button class="btn btn-primary">
<a href="#">Anmelden
$# <form method=post action=@{CourseR tid csh CShow} enctype=#{regEnctype}>
$# ^{regWidget}
@ -63,11 +67,7 @@
<td>Do 18.04.18
<td>NotGraded
<tr .no-hover.no-stripe>
<td>&nbsp;
<td>&nbsp;
<td>&nbsp;
<td>&nbsp;
<td>
<td colspan="4">
<a href="/course/S2018/ffp/ex/new" #modal-toggler__new-sheet>Neues Übungsblatt anlegen
<div .tab data-tab-name="Übungsgruppen">
<h3 .tab-title>Übungsgruppen
@ -82,16 +82,14 @@
<th>Anmeldung bis
<tbody>
<tr>
<td>
<a href="#">Gruppe 1
<td>Gruppe 1
<td>Montag 10:00 - 12:00
<td>N/A
<td>2/10
<td>Tutor1 Tutoren
<td>Do 21.02.2019, 19:00
<tr>
<td>
<a href="#">Gruppe 2
<td>Gruppe 2
<td>Montag 12:00 - 14:00
<td>N/A
<td>0/10

View File

@ -0,0 +1,3 @@
.course__registration {
margin-top: 20px;
}

View File

@ -13,6 +13,10 @@
$with status2 <- bool status "info" (status == "")
<div class="alert alert-#{status2}">#{msg}
$maybe headline <- contentHeadline
<h1>
^{headline}
<!-- prime page actions -->
^{pageactionprime}

View File

@ -126,12 +126,11 @@ table {
th, td {
text-align: left;
padding: 0 13px 0 7px;
padding: 7px;
vertical-align: baseline;
}
th:first-child,
td:first-child {
padding-left: 0;
border-left: 0;
}
th {
@ -189,21 +188,15 @@ button,
transition: all .1s;
font-size: 16px;
cursor: pointer;
border-radius: 4px;
display: inline-block;
}
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)
a {
color: white;
}
a:hover {
color: white;
}
}
input[type="submit"][disabled],
@ -226,6 +219,20 @@ a.btn:not([disabled]):hover,
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="button"].btn-info:hover,
button.btn-info:hover,
@ -237,4 +244,3 @@ a.btn.btn-info:hover,
.alert-debug {
background-color: rgb(240, 30, 240);
}

View File

@ -43,21 +43,3 @@
^{modal ".toggler2" (Just "Test Inhalt für Modal")}
<div .btn.toggler2>Klick mich für Content-Test
<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">

View File

@ -6,13 +6,6 @@ $forall FileUploadInfo{..} <- fileInfos
<input .file-checkbox.js-file-checkbox id=#{fuiHtmlId} name=#{fieldName} :fuiChecked:checked value=#{toPathPiece fuiId} type="checkbox">
<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
<input type="file" name=#{fieldName} multiple>

View File

@ -13,7 +13,7 @@ form {
grid-gap: 5px;
justify-content: flex-start;
align-items: center;
margin: 10px 0;
margin: 17px 0;
padding-left: 10px;
border-left: 2px solid transparent;
}
@ -44,20 +44,37 @@ input[type="password"],
input[type="url"],
input[type="number"],
input[type="email"] {
background-color: rgba(0, 0, 0, 0.05);
padding: 7px 3px 7px;
outline: 0;
border: 0;
border-bottom: 2px solid var(--darkbase);
box-shadow: 0 2px 13px rgba(0, 0, 0, 0.05);
color: var(--fontbase);
transition: all .1s;
font-size: 16px;
/* from bulma.css */
background-color: #fff;
border-color: #dbdbdb;
color: #363636;
box-shadow: inset 0 2px 3px 1px rgba(50,50,50,.1);
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__label::before {
content: '*';
position: absolute;
left: -14px;
}
input, textarea {
border-bottom-color: var(--lighterbase);
}
@ -82,32 +99,42 @@ input[type="password"]:focus,
input[type="url"]:focus,
input[type="number"]:focus,
input[type="email"]:focus {
border-bottom-color: var(--lightbase);
/* border-bottom-color: var(--lightbase);
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 */
/* TEXTAREAS */
textarea {
outline: 0;
border: 0;
padding: 7px 4px;
min-width: 400px;
min-height: 100px;
font-family: var(--fontfamilybase);
font-size: 16px;
color: var(--fontbase);
background-color: rgba(0, 0, 0, 0.05);
box-shadow: 0 2px 13px rgba(0, 0, 0, 0.05);
border-bottom: 2px solid var(--darkbase);
-webkit-appearance: none;
border: 1px solid transparent;
border-radius: 2px;
display: inline-flex;
font-size: 1rem;
height: 170px;
width: 400px;
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;
background-color: #fff;
border-color: #dbdbdb;
color: #363636;
box-shadow: inset 0 1px 2px rgba(10,10,10,.1);
}
textarea:focus {
background-color: transparent;
border-bottom-color: var(--lightbase);
box-shadow: 0 0 13px var(--lighterbase);
border-color: #3273dc;
box-shadow: 0 0 0 0.125em rgba(50,115,220,.25);
outline: 0;
}
/* CUSTOM LEGACY CHECKBOX AND RADIO BOXES */

View File

@ -1,4 +1,2 @@
<div .container>
<h1>Semesterübersicht
^{table}

View File

@ -8,8 +8,7 @@ $newline never
$of NavbarAside (MenuItem label mIcon route _)
<li .asidenav__list-item :Just route == mcurrentRoute:.asidenav__list-item--active>
<a .asidenav__link-wrapper href=@{route}>
$if isJust mIcon
<div .glyphicon.glyphicon--#{fromMaybe "" mIcon}>
<div .glyphicon.glyphicon--#{fromMaybe "none" mIcon}>
<div .asidenav__link-label>#{label}
$of _

View File

@ -188,7 +188,7 @@
position: absolute;
color: var(--greybase);
line-height: 50px;
opacity: 0.3;
opacity: 0.2;
right: 10px;
top: 0;
font-size: 40px;

View File

@ -1,10 +1,10 @@
.page-nav-prime {
background-color: var(--lightgreybase);
background-color: rgba(200, 200, 200, 0.2);
padding: 13px;
margin-top: 30px;
}
.page-nav-prime .pagenav__list {
margin: 7px 0 0;
display: block;
}
.page-nav-prime .pagenav__list-item {