widget-restructuring and new colors

This commit is contained in:
Felix Hamann 2018-03-07 21:55:01 +01:00
parent 56d949d57f
commit ca582f8e8a
22 changed files with 400 additions and 337 deletions

View File

@ -330,18 +330,20 @@ defaultMenuLayout menu widget = do
-- value passed to hamletToRepHtml cannot be a widget, this allows
-- you to use normal widget features in default-layout.
pc <- widgetToPageContent $ do
-- addStylesheet $ StaticR css_globals_lucius
$(widgetFile "default-layout")
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
where
navbar :: [MenuTypes] -> Maybe (Route UniWorX) -> Widget
navbar menuTypes mcurrentRoute = $(widgetFile "widgets/navbar")
asidenav :: [MenuTypes] -> Maybe (Route UniWorX) -> Widget
asidenav menuTypes mcurrentRoute = $(widgetFile "widgets/asidenav")
breadcrumbsList :: [(Route UniWorX, Text)] -> Text -> Widget
breadcrumbsList parents title = $(widgetFile "widgets/breadcrumbs")
let
navbar :: Widget
navbar = $(widgetFile "widgets/navbar")
asidenav :: Widget
asidenav = $(widgetFile "widgets/asidenav")
breadcrumbs :: Widget
breadcrumbs = $(widgetFile "widgets/breadcrumbs")
pc <- widgetToPageContent $ do
addStylesheetRemote "https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,800,900"
$(widgetFile "default-layout")
$(widgetFile "standalone/showHide")
$(widgetFile "standalone/sortable")
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
-- How to run database actions.
instance YesodPersist UniWorX where

View File

@ -43,12 +43,6 @@ getHomeR :: Handler Html
getHomeR = do
(btnWdgt, btnEnctype) <- generateFormPost (buttonForm :: Form CreateButton)
defaultLayout $ do
addStylesheet $ StaticR css_show_hide_css
addStylesheet $ StaticR css_sortable_css
addStylesheet $ StaticR css_reactive_input_css
addScript $ StaticR js_show_hide_js
addScript $ StaticR js_sortable_js
addScript $ StaticR js_reactive_input_js
setTitle "Willkommen zum ReWorX Test!"
$(widgetFile "home")

View File

@ -8,7 +8,7 @@
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ViewPatterns #-}
module Handler.Utils.Form where
module Handler.Utils.Form where
import Import
import qualified Data.Char as Char
@ -21,7 +21,7 @@ import qualified Data.Foldable as Foldable
import qualified Data.Text as T
-- import Yesod.Form.Types
import Yesod.Form.Functions (parseHelper)
import Yesod.Form.Bootstrap3
import Yesod.Form.Bootstrap3
import qualified Text.Blaze.Internal as Blaze (null)
@ -35,7 +35,7 @@ data FormIdentifier = FIDcourse | FIDsheet
deriving (Enum, Eq, Ord, Bounded, Read, Show)
identForm :: FormIdentifier -> Form a -> Form a
identForm :: FormIdentifier -> Form a -> Form a
identForm fid = identifyForm (T.pack $ show fid)
-------------------
@ -48,7 +48,7 @@ data FormLayout = FormStandard
renderAForm :: Monad m => FormLayout -> FormRender m a
renderAForm formLayout aform fragment = do
(res, (($ []) -> views)) <- aFormToForm aform
let widget = $(widgetFile "form")
let widget = $(widgetFile "widgets/form")
return (res, widget)
----------------------------
@ -67,12 +67,12 @@ class (Enum a, Bounded a, Ord a, PathPiece a) => Button a where
cssClass :: a -> ButtonCssClass
cssClass _ = BCDefault
--Some standard Buttons useful throughout
--Some standard Buttons useful throughout
data StandardButton = BtnDelete | BtnAbort | BtnSave
deriving (Enum, Eq, Ord, Bounded, Read, Show)
instance PathPiece StandardButton where -- for displaying the button only, not really for paths
toPathPiece = showToPathPiece
fromPathPiece = readFromPathPiece
@ -81,7 +81,7 @@ instance Button StandardButton where
label BtnDelete = "Löschen"
label BtnAbort = "Abbrechen"
label BtnSave = "Speichern"
cssClass BtnDelete = BCWarning
cssClass BtnAbort = BCDefault
cssClass BtnSave = BCPrimary
@ -97,45 +97,45 @@ instance Button SubmitButton where
label BtnSubmit = "Submit"
cssClass BtnSubmit = BCPrimary
-- -- Looks like a button, but is just a link (e.g. for create course, etc.)
-- -- Looks like a button, but is just a link (e.g. for create course, etc.)
-- data LinkButton = LinkButton (Route UniWorX)
-- deriving (Enum, Eq, Ord, Bounded, Read, Show)
--
--
-- instance PathPiece LinkButton where
-- LinkButton route = ???
linkButton :: Widget -> ButtonCssClass -> Route UniWorX -> Widget
linkButton lbl cls url = [whamlet| <a href=@{url} .btn .#{bcc2txt cls} role=button>^{lbl} |]
-- [whamlet|
-- <form method=post action=@{url}>
-- <form method=post action=@{url}>
-- <input type="hidden" name="_formid" value="identify-linkButton">
-- <button .btn .#{bcc2txt cls} type=submit value="Link to @{url}">^{lbl}
-- |]
-- <input .btn .#{bcc2txt cls} type="submit" value=^{lbl}>
-- |]
-- <input .btn .#{bcc2txt cls} type="submit" value=^{lbl}>
buttonField :: Button a => a -> Field Handler a
buttonField btn = Field {fieldParse, fieldView, fieldEnctype}
where
where
fieldEnctype = UrlEncoded
fieldView fid name attrs _val _ =
fieldView fid name attrs _val _ =
[whamlet|
<button .btn .#{bcc2txt $ cssClass btn} type=submit name=#{name} value=#{toPathPiece btn} *{attrs} ##{fid}>^{label btn}
<button .button .#{bcc2txt $ cssClass btn} type=submit name=#{name} value=#{toPathPiece btn} *{attrs} ##{fid}>^{label btn}
|]
fieldParse [] _ = return $ Right Nothing
fieldParse [str] _
fieldParse [str] _
| str == toPathPiece btn = return $ Right $ Just btn
| otherwise = return $ Left "Wrong button value"
fieldParse _ _ = return $ Left "Multiple button values"
combinedButtonField1 :: Button a => [a] -> AForm Handler [Maybe a]
combinedButtonField1 btns = traverse b2f btns
where
b2f b = aopt (buttonField b) "" Nothing
b2f b = aopt (buttonField b) "" Nothing
submitButton :: AForm Handler ()
submitButton = void $ combinedButtonField1 [BtnSubmit]
@ -144,10 +144,10 @@ submitButton = void $ combinedButtonField1 [BtnSubmit]
combinedButtonField :: Button a => [a] -> Form m -> Form (a,m)
combinedButtonField btns inner csrf = do
buttonIdent <- newFormIdent
let button b = mopt (buttonField b) ("n/a"{ fsName = Just buttonIdent }) Nothing
let button b = mopt (buttonField b) ("n/a"{ fsName = Just buttonIdent }) Nothing
(results, btnViews) <- unzip <$> mapM button [minBound..maxBound]
(innerRes,innerWdgt) <- inner
let widget = do
let widget = do
[whamlet|
#{csrf}
^{innerWdgt}
@ -169,14 +169,14 @@ combinedButtonField btns inner csrf = do
accResult' _ x@(FormSuccess _) = x --SJ: Is this safe? Shouldn't Failure override Success?
accResult' (FormSuccess Nothing) x = x
accResult' FormMissing _ = FormMissing
accResult' (FormFailure errs) _ = FormFailure errs
accResult' (FormFailure errs) _ = FormFailure errs
-}
-- buttonForm :: Button a => Markup -> MForm (HandlerT UniWorX IO) (FormResult a, (WidgetT UniWorX IO ()))
buttonForm :: (Button a) => Form a
buttonForm csrf = do
buttonIdent <- newFormIdent
let button b = mopt (buttonField b) ("n/a"{ fsName = Just buttonIdent }) Nothing
let button b = mopt (buttonField b) ("n/a"{ fsName = Just buttonIdent }) Nothing
(results, btnViews) <- unzip <$> mapM button [minBound..maxBound]
let widget = do
[whamlet|
@ -197,7 +197,7 @@ buttonForm csrf = do
accResult' FormMissing _ = FormMissing
accResult' (FormFailure errs) _ = FormFailure errs
---------------------------------------
-- Buttons (old version, deprecated) --
---------------------------------------
@ -233,8 +233,8 @@ postButtonForm lblId = identifyForm lblId buttonF
buttonF = renderAForm FormStandard $ pure () <* bootstrapSubmit bProps
bProps :: BootstrapSubmit Text
bProps = fromString $ unpack lblId
------------
-- Fields --
------------
@ -271,7 +271,7 @@ sheetTypeAFormReq d (Just (Normal p)) =
utcTimeField :: (Monad m, RenderMessage (HandlerSite m) FormMessage) => Field m UTCTime
-- StackOverflow: dayToUTC <$> (areq (jqueryDayField def {...}) settings Nothing)
utcTimeField = Field
utcTimeField = Field
{ fieldParse = parseHelper $ readTime
, fieldView = \theId name attrs val isReq ->
[whamlet|
@ -280,42 +280,42 @@ utcTimeField = Field
|]
, fieldEnctype = UrlEncoded
}
where
where
fieldTimeFormat :: String
--fieldTimeFormat = "%e.%m.%y %k:%M"
fieldTimeFormat = "%Y-%m-%eT%H:%M"
readTime :: Text -> Either FormMessage UTCTime
readTime t =
readTime t =
case parseTimeM True germanTimeLocale fieldTimeFormat (T.unpack t) of
(Just time) -> Right time
Nothing -> Left $ MsgInvalidEntry $ "Datum/Zeit Format: tt.mm.yy hh:mm " ++ t
showTime :: UTCTime -> Text
showTime :: UTCTime -> Text
showTime = fromString . (formatTime germanTimeLocale fieldTimeFormat)
fsb :: Text -> FieldSettings site
fsb = bfs -- Just to avoid annoying Ambiguous Type Errors
fsb :: Text -> FieldSettings site
fsb = bfs -- Just to avoid annoying Ambiguous Type Errors
addAttr :: Text -> Text -> FieldSettings site -> FieldSettings site
addAttr attr valu fs = fs { fsAttrs=newAttrs (fsAttrs fs) }
where
where
newAttrs :: [(Text,Text)] -> [(Text,Text)]
newAttrs [] = [(attr,valu)]
newAttrs (p@(a,v):t)
newAttrs (p@(a,v):t)
| attr==a = (a,T.append valu $ cons ' ' v):t
| otherwise = p:(newAttrs t)
| otherwise = p:(newAttrs t)
addAttrs :: Text -> [Text] -> FieldSettings site -> FieldSettings site
addAttrs attr valus fs = fs { fsAttrs=newAttrs (fsAttrs fs) }
where
where
newAttrs :: [(Text,Text)] -> [(Text,Text)]
newAttrs [] = [(attr,T.intercalate " " valus)]
newAttrs (p@(a,v):t)
newAttrs (p@(a,v):t)
| attr==a = (a,T.intercalate " " (v:valus)):t
| otherwise = p:(newAttrs t)
| otherwise = p:(newAttrs t)
addClass :: Text -> FieldSettings site -> FieldSettings site
addClass = addAttr "class"
@ -332,7 +332,7 @@ addIdClass :: Text -> Text -> FieldSettings site -> FieldSettings site
addIdClass gId gClass fs = fs { fsId= Just gId, fsAttrs=("class",gClass):(fsAttrs fs) }
setClass :: FieldSettings site -> Text -> FieldSettings site -- deprecated
setClass :: FieldSettings site -> Text -> FieldSettings site -- deprecated
setClass fs c = fs { fsAttrs=("class",c):(fsAttrs fs) }
setNameClass :: FieldSettings site -> Text -> Text -> FieldSettings site -- deprecated
@ -342,4 +342,3 @@ setTooltip :: String -> FieldSettings site -> FieldSettings site
setTooltip tt fs
| null tt = fs { fsTooltip = Nothing }
| otherwise = fs { fsTooltip = Just $ fromString tt }

View File

@ -4,5 +4,5 @@ module Handler.Utils.Templates where
import Import.NoFoundation
lipsum :: WidgetT site IO ()
lipsum = $(widgetFile "widgets/lipsum")
-- lipsum :: WidgetT site IO ()
-- lipsum = $(widgetFile "widgets/lipsum")

View File

@ -16,3 +16,6 @@ import Data.Fixed as Import
import CryptoID as Import
import Data.UUID as Import (UUID)
import Text.Lucius as Import

View File

@ -1,21 +0,0 @@
.reactive-label {
cursor: text;
color: #333;
transform: translate(0, 0);
transition: all .1s;
}
.reactive-label.small {
cursor: default;
color: #888;
}
@media (max-width: 768px) {
.reactive-label {
position: absolute;
left: 4px;
top: 8px;
}
.reactive-label.small {
transform: translate(0, -120%);
font-size: 12px;
}
}

View File

@ -1,15 +1,16 @@
<!-- navigation -->
^{navbar menuTypes mcurrentRoute}
<div .navbar-container>
^{navbar}
<div .main>
<aside .main__aside>
^{asidenav menuTypes mcurrentRoute}
^{asidenav}
<div .main__content>
<!-- breadcrumbs -->
$if not $ Just HomeR == mcurrentRoute
^{breadcrumbsList parents title}
^{breadcrumbs}
<!-- alerts -->
$forall (status, msg) <- mmsgs
@ -19,9 +20,6 @@
<!-- actual content -->
^{widget}
<!-- a little lorem ipsum for waste of vertical space -->
^{lipsum}
<!-- footer -->
<footer>
#{appCopyright $ appSettings master}

View File

@ -12,7 +12,24 @@
--sec-font-color: #eaf2ff;
--box-bg-color: #dddddd;
/* THEME 3 */
--base00: rebeccapurple;
--darkbase: #364B60;
--lightbase: #2490E8;
--lighterbase: #60C2FF;
--whitebase: #FCFFFA;
--greybase: #B1B5C0;
--fontbase: #34303a;
/* THEME INDEPENDENT COLORS */
--errorbase: red;
/* FONTS */
--fontfamilybase: "Source Sans Pro", Helvetica, sans-serif;
/* DIMENSIONS */
--header-height: 60px;
--header-height-collapsed: 50px;
}
@ -26,8 +43,8 @@
body {
background-color: white;
color: #333;
font-family: "Source Sans Pro", Helvetica, sans-serif;
color: var(--fontbase);
font-family: var(--fontfamilybase);
font-weight: 400;
font-size: 16px;
overflow-y: scroll;
@ -35,13 +52,13 @@ body {
a,
a:visited {
color: rebeccapurple;
color: var(--darkbase);
text-decoration: none;
font-weight: 600;
transition: color .2s ease, background-color .2s ease;
}
a:hover {
color: #422063;
color: var(--lightbase);
}
ul {
@ -80,19 +97,29 @@ th, td {
/* LAYOUT */
.main {
display: flex;
padding: 0 10vw;
padding-right: 5vw;
min-height: calc(100vh - var(--header-height));
}
.main__aside {
flex: 0 0 200px;
margin-right: 40px;
width: 300px;
padding-right: 20px;
padding-left: 4vw;
background-color: var(--darkbase);
/*background: -moz-linear-gradient(right, var(--darkbase) 0%, #395069 100%); /* FF3.6-15 */*/
/*background: -webkit-linear-gradient(right, var(--darkbase) 0%, #395069 100%); /* Chrome10-25,Safari5.1-6 */*/
/*background: linear-gradient(to left, var(--darkbase) 0%, #395069 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */*/
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
z-index: 1;
}
.main__content {
/*padding: 0 10vw;*/
background-color: white;
padding: 20px 40px;
flex: 1;
z-index: 0;
div {
> div {
margin: 20px 0;
}
@ -100,126 +127,3 @@ th, td {
margin: 10px 0;
}
}
/* FORMS */
input[type="text"],
input[type="password"],
input[type="url"],
input[type="number"],
input[type="email"] {
background-color: rgba(0, 0, 0, 0.05);
padding: 7px 3px 7px;
border: none;
outline: 0;
border-bottom: 2px solid rebeccapurple;
color: var(--base-font-color);
transition: all .1s;
font-size: 16px;
min-width: 300px;
}
input[type="text"]:focus,
input[type="password"]:focus,
input[type="url"]:focus,
input[type="number"]:focus,
input[type="email"]:focus {
border-bottom-color: red;
background-color: rgba(0, 0, 0, 0.02);
}
input[type="submit"],
input[type="button"],
button {
outline: 0;
border: 0;
box-shadow: 0;
background-color: var(--base00);
color: white;
padding: 7px 13px;
border: 1px solid rebeccapurple;
transition: all .1s;
font-size: 16px;
cursor: pointer;
}
input[type="submit"][disabled],
input[type="button"][disabled],
button[disabled] {
opacity: 0.3;
border: 1px solid transparent;
cursor: default;
}
input[type="submit"]:not([disabled]):hover,
input[type="button"]:not([disabled]):hover,
button:not([disabled]):hover {
background-color: var(--base-bg-color);
color: var(--base-font-color);
}
.form-group {
position: relative;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(100px, max-content));
align-items: center;
}
/*CUSTOM CHECKBOXES AND RADIO BOXES*/
.checkbox,
.radio {
position: relative;
}
.checkbox > [type="checkbox"],
.radio > [type="radio"] {
display: none;
}
.checkbox > label,
.radio > label {
padding: 7px 13px 7px 30px;
background-color: rebeccapurple;
border-radius: 4px;
color: white;
cursor: pointer;
}
.checkbox > label::before,
.radio > label::before,
.checkbox > label::after,
.radio > label::after {
content: '';
position: absolute;
top: 7px;
left: 4px;
display: block;
width: 20px;
height: 20px;
background-color: white;
transform: scale(0.2, 0.2);
transition: all .2s;
}
.radio > label::before,
.radio > label::after {
transform: scale(0.01, 0.01);
}
.checkbox > label::before,
.radio > label::before {
width: 20px;
height: 2px;
}
.checkbox > label::after,
.radio > label::after {
width: 20px;
height: 2px;
}
.checkbox > :checked + label,
.radio > :checked + label {
background-color: #451477;
text-decoration: underline;
}
.checkbox > :checked + label::before,
.radio > :checked + label::before {
transform: rotate(45deg);
}
.checkbox > :checked + label::after,
.radio > :checked + label::after {
transform: rotate(-45deg);
}

View File

@ -1,9 +0,0 @@
$newline never
#{fragment}
$case formLayout
$of FormStandard
$forall view <- views
<div :fvRequired view:.required :not $ fvRequired view:.optional :isJust $ fvErrors view:.has-error>
$if not (Blaze.null $ fvLabel view)
<label for=#{fvId view}>#{fvLabel view}
^{fvInput view}

View File

@ -8,7 +8,6 @@
<p .alert .alert-danger>Das System ist noch nicht produktiv einsetzbar
<!-- SHOW-HIDE-TEST -->
<hr>
<div .js-show-hide>
<h2 .js-show-hide__toggle>Teilweise funktionierende Abschnitte
@ -58,69 +57,6 @@
<td>T2C2
<td>35
<hr>
<div .js-show-hide.js-show-hide--collapsed>
<h2 .js-show-hide__toggle>Formulare
<p>(Senden-Button wird aktiviert, sobald alle benötigten Felder ausgefüllt sind.)
<form method=post action=@{HomeR}>
<div .form-group>
<label .reactive-label for=text>Vorname*
<input type=text id=text required=true>
<div .form-group>
<label .reactive-label for=password>Passwort*
<input type=password id=password required=true>
<div .form-group>
<label .reactive-label for=email>Email*
<input type=email id=email required=true>
<div .form-group>
<label for=date>Geburtsdatum:
<input type=date id=date>
<div .form-group>
<div>
<input type=submit value="Senden" id=submit-btn>
<div .form-group>
<textarea>No content yet
<p>Bitte wähle aus (auch mehrere):
<div .form-group>
<div .checkbox>
<input type=checkbox id=chkbox1>
<label for=chkbox1>Opt A
<div .checkbox>
<input type=checkbox id=chkbox2>
<label for=chkbox2>Opt B
<div .checkbox>
<input type=checkbox id=chkbox3>
<label for=chkbox3>Opt C
<div .checkbox>
<input type=checkbox id=chkbox4>
<label for=chkbox4>Opt D
<p>Wähle aus diesen Optionen eines aus:
<div .form-group>
<div .radio>
<input type=radio name=group1[] id=rdbtn1>
<label for=rdbtn1>Opt A
<div .radio>
<input type=radio name=group1[] id=rdbtn2>
<label for=rdbtn2>Opt B
<div .radio>
<input type=radio name=group1[] id=rdbtn3>
<label for=rdbtn3>Opt C
<p>Wähle eines aus der Liste aus:
<div .form-group>
<select required=true>
<option>Option 1
<option>Option 2
<option>Option 3
<div .form-group>
<h3>Test-Button. Does nothing.
<input type=button value="Test">
<hr>
<div>
<h2>Funktionen zum Testen

View File

@ -0,0 +1 @@
<!-- only here to be able to include showHide using `toWidget` -->

View File

@ -24,12 +24,12 @@
left: -28px;
top: 10px;
border-left: 8px solid transparent;
border-top: 8px solid rebeccapurple;
border-top: 8px solid var(--lightbase);
}
.js-show-hide__toggle:hover::before,
.js-show-hide--collapsed .js-show-hide__toggle::before {
border-left: 8px solid rebeccapurple;
border-left: 8px solid var(--lightbase);
border-top: 8px solid transparent;
top: 5px;
left: -22px;

View File

@ -0,0 +1 @@
<!-- only here to be able to include sortable using `toWidget` -->

View File

@ -6,25 +6,26 @@ table.js-sortable th {
table.js-sortable th.sorted-asc,
table.js-sortable th.sorted-desc {
color: rebeccapurple;
color: var(--darkbase);
}
table.js-sortable th.sorted-asc::after,
table.js-sortable th.sorted-desc::after {
content: '';
position: absolute;
right: 0;
left: 0;
top: 0;
width: 0;
height: 0;
top: 3px;
transform: translateY(-100%);
border-left: 8px solid transparent;
border-right: 8px solid transparent;
}
table.js-sortable th.sorted-asc::after {
border-top: 8px solid rebeccapurple;
border-bottom: 8px solid var(--lightbase);
}
table.js-sortable th.sorted-desc::after {
border-bottom: 8px solid rebeccapurple;
border-top: 8px solid var(--lightbase);
}

View File

@ -1,20 +1,26 @@
.asidenav {
margin-top: 20px;
color: white;
}
.asidenav__box {
margin: 10px 0;
padding: 10px;
border-bottom: 4px solid rebeccapurple;
border-bottom: 4px solid var(--darkbase);
}
.asidenav__box-title {
margin-left: -10px;
}
.asidenav__link {
padding: 4px 7px;
.asidenav .asidenav__link {
display: block;
padding: 4px 7px;
border-radius: 2px;
margin: 4px 0;
color: var(--darkbase);
background-color: white;
}
.asidenav__link:hover {
.asidenav .asidenav__link:hover {
color: white;
background-color: rebeccapurple;
background-color: var(--darkbase);
}

View File

@ -0,0 +1,9 @@
$newline never
#{fragment}
$case formLayout
$of FormStandard
$forall view <- views
<div .form-group :fvRequired view:.form-group--required :not $ fvRequired view:.form-group--optional :isJust $ fvErrors view:.form-group--has-error>
$if not (Blaze.null $ fvLabel view)
<label form-group__label .reactive-label for=#{fvId view}>#{fvLabel view}
^{fvInput view}

View File

@ -6,16 +6,19 @@ document.addEventListener('DOMContentLoaded', function() {
// makes <label> smaller if <input> is focussed
window.utils.reactiveInputLabel = function(input, label) {
if (input.value.length > 0) {
label.classList.add('reactive-label--small');
}
input.addEventListener('focus', function() {
label.classList.add('small');
label.classList.add('reactive-label--small');
});
label.addEventListener('click', function() {
label.classList.add('small');
label.classList.add('reactive-label--small');
input.focus();
});
input.addEventListener('blur', function() {
if (input.value.length < 1) {
label.classList.remove('small');
label.classList.remove('reactive-label--small');
}
});
};

View File

@ -0,0 +1,238 @@
/* GENERAL STYLES FOR FORMS */
/* FORMS */
input[type="text"],
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;
min-width: 300px;
}
input[type="text"]:focus,
input[type="password"]:focus,
input[type="url"]:focus,
input[type="number"]:focus,
input[type="email"]:focus {
border-bottom-color: var(--lightbase);
background-color: transparent;
}
input[type="submit"],
input[type="button"],
button {
outline: 0;
border: 0;
box-shadow: 0;
background-color: var(--lightbase);
color: white;
padding: 10px 17px;
min-width: 100px;
transition: all .1s;
font-size: 16px;
cursor: pointer;
border-radius: 4px;
}
input[type="submit"][disabled],
input[type="button"][disabled],
button[disabled] {
opacity: 0.3;
border: 1px solid transparent;
background-color: var(--greybase);
cursor: default;
}
input[type="submit"]:not([disabled]):hover,
input[type="button"]:not([disabled]):hover,
button:not([disabled]):hover {
background-color: var(--lighterbase);
}
textarea {
outline: 0;
border: 0;
padding: 7px 4px;
min-width: 300px;
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);
}
textarea:focus {
background-color: transparent;
border-bottom-color: var(--lightbase);
}
.form-group {
position: relative;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, max-content));
align-items: center;
margin: 10px 0;
margin-left: -20px;
padding-left: 10px;
border-left: 8px solid transparent;
}
.form-group--required {
border-left: 8px solid var(--lightbase);
}
.form-group--optional {
border-left: 8px solid var(--greybase);
}
.form-group--has-error {
border-left: 8px solid var(--errorbase) !important;
}
/* CUSTOM LEGACY CHECKBOX AND RADIO BOXES */
input[type="checkbox"] {
position: relative;
height: 20px;
width: 20px;
-webkit-appearance: none;
cursor: pointer;
}
input[type="checkbox"]::before {
content: '';
position: absolute;
width: 20px;
height: 20px;
background-color: var(--lighterbase);
display: flex;
align-items: center;
justify-content: center;
border-radius: 2px;
}
input[type="checkbox"]:checked::before {
background-color: var(--lightbase);
}
input[type="checkbox"]:checked::after {
content: '✓';
position: absolute;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 20px;
}
/* CUSTOM CHECKBOXES AND RADIO BOXES */
/* Completely replaces legacy checkbox and radiobox */
.checkbox,
.radio {
position: relative;
margin: 3px;
> [type="checkbox"],
> [type="radio"] {
display: none;
}
> label {
display: block;
padding: 7px 13px 7px 30px;
background-color: var(--darkbase);
border-radius: 4px;
color: white;
cursor: pointer;
}
> label::before,
> label::after {
content: '';
position: absolute;
top: 15px;
left: 4px;
display: block;
width: 20px;
height: 20px;
background-color: white;
transition: all .2s;
}
> label::before {
width: 20px;
height: 2px;
transform: scale(0.8, 0.1);
}
> label::after {
width: 20px;
height: 2px;
transform: scale(0.8, 0.1);
}
> :checked + label {
background-color: var(--lightbase);
text-decoration: underline;
}
&:hover > label::before,
> :checked + label::before {
transform: scale(1, 1) rotate(45deg);
}
&:hover > label::after,
> :checked + label::after {
transform: scale(1, 1) rotate(-45deg);
}
}
.radio > label::before {
transform: scale(0.01, 0.01) rotate(45deg);
}
.radio > label::after {
transform: scale(0.01, 0.01) rotate(-45deg);
}
.radio::before {
content: '';
position: absolute;
top: 2px;
left: 2px;
right: 2px;
bottom: 2px;
border-radius: 4px;
border: 2px solid white;
z-index: -1;
}
/* REACTIVE LABELS */
.reactive-label {
cursor: text;
color: #888;
transform: translate(0, 0);
transition: all .1s;
}
.reactive-label--small {
cursor: default;
color: var(--fontbase);
}
@media (max-width: 768px) {
.reactive-label {
position: absolute;
left: 4px;
top: 8px;
}
.reactive-label--small {
transform: translate(0, -120%);
font-size: 12px;
}
}

View File

@ -4,10 +4,10 @@
$forall menuType <- menuTypes
$case menuType
$of NavbarLeft (MenuItem label route _)
<li :Just route == mcurrentRoute:.navbar__list-item--active>
<li .navbar__list-item :Just route == mcurrentRoute:.navbar__list-item--active>
<a .navbar__link href=@{route}>#{label}
$of NavbarRight (MenuItem label route _)
<li :Just route == mcurrentRoute:.navbar__list-item--active>
<li .navbar__list-item :Just route == mcurrentRoute:.navbar__list-item--active>
<a .navbar__link href=@{route}>#{label}
$of _

View File

@ -1,8 +1,3 @@
:root {
--header-height: 60px;
--header-height-collapsed: 50px;
}
.navbar {
position: relative;
display: flex;
@ -12,13 +7,14 @@
width: 100%;
height: var(--header-height);
line-height: var(--header-height);
padding: 0 10vw;
background: #663399; /* Old browsers */
background: -moz-linear-gradient(bottom, #663399 0%, #734e99 100%); /* FF3.6-15 */
background: -webkit-linear-gradient(bottom, #663399 0%,#734e99 100%); /* Chrome10-25,Safari5.1-6 */
background: linear-gradient(to top, #663399 0%,#734e99 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
padding: 0 5vw;
background: var(--darkbase); /* Old browsers */
background: -moz-linear-gradient(bottom, var(--darkbase) 0%, #425d79 100%); /* FF3.6-15 */
background: -webkit-linear-gradient(bottom, var(--darkbase) 0%,#425d79 100%); /* Chrome10-25,Safari5.1-6 */
background: linear-gradient(to top, var(--darkbase) 0%,#425d79 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
color: white;
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.3);
box-shadow: 0 1px 10px rgba(0, 0, 0, 0.1);
z-index: 10;
}
.navbar .navbar__link {
@ -26,15 +22,16 @@
height: 100%;
padding: 0 13px;
color: white;
text-transform: uppercase;
}
.navbar .navbar__link:hover {
.navbar__list-item--active > .navbar__link {
background-color: white;
color: rebeccapurple;
color: var(--darkbase);
}
.navbar__list-item--active {
background-color: #422063;
.navbar .navbar__list-item > .navbar__link:hover {
background-color: var(--darkbase);
}
.navbar--sticky {
@ -48,6 +45,7 @@
}
.navbar__pushdown {
display: none;
background-color: var(--darkbase);
height: var(--header-height);
}
.navbar--sticky + .navbar__pushdown {