├── .gitignore ├── README.md ├── css ├── index.css └── prism-nord.css ├── elm.json ├── index.html ├── js ├── custom │ └── highlight.js └── index.js ├── netlify.toml ├── package.json └── src ├── Assets.elm ├── Components.elm ├── Components ├── Feedback │ ├── Loader.elm │ ├── ProgressBar.elm │ ├── RadialProgressBar.elm │ └── Tooltip.elm ├── Input │ ├── CustomCheckbox.elm │ ├── CustomRadio.elm │ ├── Dropdown.elm │ ├── FloatingLabel.elm │ ├── RadioButtonGroup.elm │ ├── Rating.elm │ └── SearchBox.elm ├── Layout │ ├── Card.elm │ ├── HolyGrail.elm │ ├── SameHeightColumns.elm │ ├── Sidebar.elm │ ├── SplitScreen.elm │ ├── StickyFooter.elm │ └── StickyHeader.elm ├── Misc │ ├── StickyColumnsTable.elm │ ├── StickyHeadersTable.elm │ └── Timeline.elm └── Navigation │ ├── Breadcrumb.elm │ ├── Drawer.elm │ ├── Pagination.elm │ ├── Split.elm │ └── Tab.elm ├── Main.elm ├── Pages ├── Feedback.elm ├── Feedback │ ├── Loader.elm │ ├── ProgressBar.elm │ ├── RadialProgressBar.elm │ └── Tooltip.elm ├── Home_.elm ├── Input.elm ├── Input │ ├── CustomCheckbox.elm │ ├── CustomRadio.elm │ ├── Dropdown.elm │ ├── FloatingLabel.elm │ ├── RadioButtonGroup.elm │ ├── Rating.elm │ └── SearchBox.elm ├── Layout.elm ├── Layout │ ├── Card.elm │ ├── HolyGrail.elm │ ├── SameHeightColumns.elm │ ├── Sidebar.elm │ ├── SplitScreen.elm │ ├── StickyFooter.elm │ └── StickyHeader.elm ├── Misc.elm ├── Misc │ ├── StickyColumnsTable.elm │ ├── StickyHeadersTable.elm │ └── Timeline.elm ├── Navigation.elm ├── Navigation │ ├── Breadcrumb.elm │ ├── Drawer.elm │ ├── Pagination.elm │ ├── Split.elm │ └── Tab.elm └── NotFound.elm ├── Shared.elm ├── Styles.elm ├── Styles ├── Animations.elm ├── Breakpoints.elm └── Colors.elm └── View.elm /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist 3 | .cache 4 | /elm-stuff 5 | /public 6 | .elm-spa/ 7 | package-lock.json 8 | 9 | # Local Netlify folder 10 | .netlify 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elm-css patterns 2 | 3 | [![Netlify Status](https://api.netlify.com/api/v1/badges/e783ee87-62d1-4e5f-8b83-c3f88341ff7f/deploy-status)](https://app.netlify.com/sites/elm-css-patterns/deploys) 4 | 5 | Common CSS patterns done in [elm](https://elm-lang.org/) and [elm-css](https://github.com/rtfeldman/elm-css). Powered by [elm-spa](https://github.com/ryannhg/elm-spa). Inspired by [csslayout](https://github.com/phuoc-ng/csslayout). 6 | -------------------------------------------------------------------------------- /css/index.css: -------------------------------------------------------------------------------- 1 | /* Box sizing rules */ 2 | *, 3 | *::before, 4 | *::after { 5 | box-sizing: border-box; 6 | } 7 | 8 | /* Remove default padding */ 9 | ul[class], 10 | ol[class] { 11 | padding: 0; 12 | } 13 | 14 | /* Remove default margin */ 15 | body, 16 | h1, 17 | h2, 18 | h3, 19 | h4, 20 | p, 21 | ul[class], 22 | ol[class], 23 | li, 24 | figure, 25 | figcaption, 26 | blockquote, 27 | dl, 28 | dd { 29 | margin: 0; 30 | } 31 | 32 | /* Set core body defaults */ 33 | body { 34 | min-height: 100vh; 35 | scroll-behavior: smooth; 36 | text-rendering: optimizeSpeed; 37 | line-height: 1.5; 38 | } 39 | 40 | /* Remove list styles on ul, ol elements with a class attribute */ 41 | ul[class], 42 | ol[class] { 43 | list-style: none; 44 | } 45 | 46 | /* A elements that don't have a class get default styles */ 47 | a:not([class]) { 48 | text-decoration-skip-ink: auto; 49 | } 50 | 51 | /* Make images easier to work with */ 52 | img { 53 | max-width: 100%; 54 | display: block; 55 | } 56 | 57 | /* Natural flow and rhythm in articles by default */ 58 | article > * + * { 59 | margin-top: 1em; 60 | } 61 | 62 | /* Inherit fonts for inputs and buttons */ 63 | input, 64 | button, 65 | textarea, 66 | select { 67 | font: inherit; 68 | } 69 | 70 | /* Remove all animations and transitions for people that prefer not to see them */ 71 | @media (prefers-reduced-motion: reduce) { 72 | * { 73 | animation-duration: 0.01ms !important; 74 | animation-iteration-count: 1 !important; 75 | transition-duration: 0.01ms !important; 76 | scroll-behavior: auto !important; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /css/prism-nord.css: -------------------------------------------------------------------------------- 1 | /* Generated with http://k88hudson.github.io/syntax-highlighting-theme-generator/www */ 2 | 3 | /********************************************************* 4 | * General 5 | */ 6 | pre[class*="language-"], 7 | code[class*="language-"] { 8 | color: #d8dee9; 9 | font-size: 1em; 10 | text-shadow: none; 11 | direction: ltr; 12 | text-align: left; 13 | white-space: pre-wrap; 14 | word-spacing: normal; 15 | word-break: normal; 16 | line-height: 1.5; 17 | -moz-tab-size: 4; 18 | -o-tab-size: 4; 19 | tab-size: 4; 20 | -webkit-hyphens: none; 21 | -moz-hyphens: none; 22 | -ms-hyphens: none; 23 | hyphens: none; 24 | } 25 | pre[class*="language-"]::selection, 26 | code[class*="language-"]::selection, 27 | pre[class*="language-"]::mozselection, 28 | code[class*="language-"]::mozselection { 29 | text-shadow: none; 30 | background: none; 31 | } 32 | @media print { 33 | pre[class*="language-"], 34 | code[class*="language-"] { 35 | text-shadow: none; 36 | } 37 | } 38 | pre[class*="language-"] { 39 | padding: 1em; 40 | margin: .5em 0; 41 | overflow: auto; 42 | background: #2e3440; 43 | } 44 | :not(pre) > code[class*="language-"] { 45 | padding: .1em; 46 | border-radius: .3em; 47 | color: #d8dee9; 48 | background: #2e3440; 49 | } 50 | /********************************************************* 51 | * Tokens 52 | */ 53 | .namespace { 54 | opacity: .7; 55 | } 56 | .token.comment, 57 | .token.prolog, 58 | .token.doctype, 59 | .token.cdata { 60 | color: #606e87; 61 | } 62 | .token.punctuation { 63 | color: #81a1c1; 64 | } 65 | .token.property, 66 | .token.tag, 67 | .token.boolean, 68 | .token.number, 69 | .token.constant, 70 | .token.symbol, 71 | .token.deleted { 72 | color: #b48ead; 73 | } 74 | .token.selector, 75 | .token.attr-name, 76 | .token.string, 77 | .token.char, 78 | .token.builtin, 79 | .token.inserted { 80 | color: #a2bf8c; 81 | } 82 | .token.operator, 83 | .token.entity, 84 | .token.url, 85 | .language-css .token.string, 86 | .style .token.string { 87 | color: #80a2c1; 88 | background: none; 89 | } 90 | .token.atrule, 91 | .token.attr-value, 92 | .token.keyword { 93 | color: #81a1c1; 94 | } 95 | .token.function { 96 | color: #8fbcbc; 97 | } 98 | .token.regex, 99 | .token.important, 100 | .token.variable { 101 | color: #ee9900; 102 | } 103 | .token.important, 104 | .token.bold { 105 | font-weight: bold; 106 | } 107 | .token.italic { 108 | font-style: italic; 109 | } 110 | .token.entity { 111 | cursor: help; 112 | } 113 | /********************************************************* 114 | * Line highlighting 115 | */ 116 | pre[data-line] { 117 | position: relative; 118 | } 119 | pre[class*="language-"] > code[class*="language-"] { 120 | position: relative; 121 | z-index: 1; 122 | } 123 | .line-highlight { 124 | position: absolute; 125 | left: 0; 126 | right: 0; 127 | padding: inherit 0; 128 | margin-top: 1em; 129 | background: #3b4251; 130 | box-shadow: inset 5px 0 0 #d8dee9; 131 | z-index: 0; 132 | pointer-events: none; 133 | line-height: inherit; 134 | white-space: pre; 135 | } 136 | -------------------------------------------------------------------------------- /elm.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "application", 3 | "source-directories": [ 4 | "src", 5 | ".elm-spa/defaults", 6 | ".elm-spa/generated" 7 | ], 8 | "elm-version": "0.19.1", 9 | "dependencies": { 10 | "direct": { 11 | "bigardone/elm-css-placeholders": "2.0.1", 12 | "elm/browser": "1.0.2", 13 | "elm/core": "1.0.5", 14 | "elm/json": "1.1.3", 15 | "elm/time": "1.0.0", 16 | "elm/url": "1.0.0", 17 | "rtfeldman/elm-css": "16.1.1", 18 | "ryannhg/elm-spa": "6.0.0" 19 | }, 20 | "indirect": { 21 | "elm/html": "1.0.0", 22 | "elm/random": "1.0.0", 23 | "elm/virtual-dom": "1.0.2", 24 | "elm-community/random-extra": "3.2.0", 25 | "rtfeldman/elm-hex": "1.0.0" 26 | } 27 | }, 28 | "test-dependencies": { 29 | "direct": {}, 30 | "indirect": {} 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /js/custom/highlight.js: -------------------------------------------------------------------------------- 1 | import '@webcomponents/custom-elements'; 2 | import Prism from 'prismjs'; 3 | import 'prismjs/components/prism-elm'; 4 | import '../../css/prism-nord.css'; 5 | 6 | 7 | export default class Highlight extends HTMLElement { 8 | constructor() { super(); } 9 | 10 | static get observedAttributes() { 11 | return ['content']; 12 | } 13 | 14 | connectedCallback() { 15 | const content = this.getAttribute('content'); 16 | 17 | const pre = document.createElement('pre'); 18 | const code = document.createElement('code'); 19 | code.setAttribute('class', 'language-elm'); 20 | code.innerHTML = content; 21 | 22 | pre.appendChild(code); 23 | this.appendChild(pre); 24 | 25 | Prism.highlightAll(); 26 | } 27 | } 28 | 29 | if (!customElements.get('c-highlight')) { 30 | customElements.define('c-highlight', Highlight); 31 | } 32 | -------------------------------------------------------------------------------- /js/index.js: -------------------------------------------------------------------------------- 1 | import '../css/index.css'; 2 | import './custom/highlight'; 3 | 4 | import { Elm } from '../src/Main.elm'; 5 | 6 | 7 | Elm.Main.init({ 8 | node: document.querySelector('main'), 9 | }); 10 | 11 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "npm run build" 3 | publish = "dist" 4 | 5 | [[redirects]] 6 | from = "/*" 7 | to = "/" 8 | status = 200 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elm-spa-parcel", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npm install && npm run build && npm run dev", 8 | "build": "npm run build:elm-spa && npm run build:elm", 9 | "build:elm-spa": "elm-spa build .", 10 | "build:elm": "parcel build index.html", 11 | "dev": "concurrently --raw --kill-others \"npm run dev:elm-spa\" \"npm run dev:elm\"", 12 | "dev:elm-spa": "chokidar src/Pages -c \"npm run build:elm-spa\"", 13 | "dev:elm": "parcel index.html" 14 | }, 15 | "keywords": [], 16 | "author": "", 17 | "license": "ISC", 18 | "devDependencies": { 19 | "chokidar-cli": "^2.1.0", 20 | "concurrently": "^6.0.0", 21 | "elm": "^0.19.1-3", 22 | "elm-hot": "^1.1.4", 23 | "elm-spa": "^6.0.0", 24 | "node-elm-compiler": "^5.0.4", 25 | "parcel-bundler": "^1.12.4" 26 | }, 27 | "dependencies": { 28 | "@webcomponents/custom-elements": "^1.4.1", 29 | "prismjs": "^1.20.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Assets.elm: -------------------------------------------------------------------------------- 1 | module Assets exposing 2 | ( barsIcon 3 | , closeIcon 4 | , githubIcon 5 | , linkIcon 6 | ) 7 | 8 | import Svg.Styled as SS 9 | import Svg.Styled.Attributes as SSA 10 | 11 | 12 | githubIcon : SS.Svg msg 13 | githubIcon = 14 | SS.svg 15 | [ SSA.viewBox "0 0 20 20" 16 | , SSA.width "1.2em" 17 | , SSA.height "1.2em" 18 | ] 19 | [ SS.path 20 | [ SSA.fill "currentColor" 21 | , SSA.d "M10 0a10 10 0 0 0-3.16 19.49c.5.1.68-.22.68-.48l-.01-1.7c-2.78.6-3.37-1.34-3.37-1.34-.46-1.16-1.11-1.47-1.11-1.47-.9-.62.07-.6.07-.6 1 .07 1.53 1.03 1.53 1.03.9 1.52 2.34 1.08 2.91.83.1-.65.35-1.09.63-1.34-2.22-.25-4.55-1.11-4.55-4.94 0-1.1.39-1.99 1.03-2.69a3.6 3.6 0 0 1 .1-2.64s.84-.27 2.75 1.02a9.58 9.58 0 0 1 5 0c1.91-1.3 2.75-1.02 2.75-1.02.55 1.37.2 2.4.1 2.64.64.7 1.03 1.6 1.03 2.69 0 3.84-2.34 4.68-4.57 4.93.36.31.68.92.68 1.85l-.01 2.75c0 .26.18.58.69.48A10 10 0 0 0 10 0" 22 | ] 23 | [] 24 | ] 25 | 26 | 27 | linkIcon : SS.Svg msg 28 | linkIcon = 29 | SS.svg 30 | [ SSA.viewBox "0 0 512 512" 31 | , SSA.width "12px" 32 | , SSA.height "12px" 33 | ] 34 | [ SS.path 35 | [ SSA.fill "currentColor" 36 | , SSA.d "M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z" 37 | ] 38 | [] 39 | ] 40 | 41 | 42 | barsIcon : SS.Svg msg 43 | barsIcon = 44 | SS.svg 45 | [ SSA.viewBox "0 0 448 512" 46 | , SSA.width "1.2em" 47 | , SSA.height "1.2em" 48 | ] 49 | [ SS.path 50 | [ SSA.fill "currentColor" 51 | , SSA.d "M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z" 52 | ] 53 | [] 54 | ] 55 | 56 | 57 | closeIcon : SS.Svg msg 58 | closeIcon = 59 | SS.svg 60 | [ SSA.viewBox "0 0 352 512" 61 | , SSA.width "1.2em" 62 | , SSA.height "1.2em" 63 | ] 64 | [ SS.path 65 | [ SSA.fill "currentColor" 66 | , SSA.d "M242.72 256l100.07-100.07c12.28-12.28 12.28-32.19 0-44.48l-22.24-22.24c-12.28-12.28-32.19-12.28-44.48 0L176 189.28 75.93 89.21c-12.28-12.28-32.19-12.28-44.48 0L9.21 111.45c-12.28 12.28-12.28 32.19 0 44.48L109.28 256 9.21 356.07c-12.28 12.28-12.28 32.19 0 44.48l22.24 22.24c12.28 12.28 32.2 12.28 44.48 0L176 322.72l100.07 100.07c12.28 12.28 32.2 12.28 44.48 0l22.24-22.24c12.28-12.28 12.28-32.19 0-44.48L242.72 256z" 67 | ] 68 | [] 69 | ] 70 | -------------------------------------------------------------------------------- /src/Components.elm: -------------------------------------------------------------------------------- 1 | module Components exposing 2 | ( feedbackNavItems 3 | , inputNavItems 4 | , layoutNavItems 5 | , miscNavItems 6 | , navItem 7 | , navigationNavItems 8 | , pageBody 9 | ) 10 | 11 | import Assets 12 | import Gen.Route as Route exposing (Route) 13 | import Html.Styled as Html exposing (Html) 14 | import Html.Styled.Attributes as Html 15 | import Html.Styled.Keyed as HtmlKeyed 16 | 17 | 18 | pageBody : { header : String, content : Html msg, code : String, componentUrl : String } -> List (Html msg) 19 | pageBody { header, content, code, componentUrl } = 20 | let 21 | id = 22 | header 23 | |> String.split " " 24 | |> List.map String.toLower 25 | |> String.concat 26 | in 27 | [ Html.header 28 | [ Html.class "header" ] 29 | [ Html.h1 30 | [] 31 | [ Html.text header ] 32 | , Html.a 33 | [ Html.href componentUrl 34 | , Html.target "_blank" 35 | , Html.class "cool" 36 | ] 37 | [ Html.text "Get the code" 38 | , Assets.linkIcon 39 | ] 40 | ] 41 | , HtmlKeyed.node "div" 42 | [ Html.class "content" ] 43 | [ ( id 44 | , Html.div 45 | [ Html.class "content__example" ] 46 | [ content ] 47 | ) 48 | ] 49 | , HtmlKeyed.node "div" 50 | [ Html.class "code" ] 51 | [ ( id ++ "-code" 52 | , Html.node "c-highlight" 53 | [ Html.attribute "content" code ] 54 | [] 55 | ) 56 | ] 57 | ] 58 | 59 | 60 | layoutNavItems : List ( Route, String ) 61 | layoutNavItems = 62 | [ ( Route.Layout__Card, "Card" ) 63 | , ( Route.Layout__HolyGrail, "Holy grail" ) 64 | , ( Route.Layout__SameHeightColumns, "Same height columns" ) 65 | , ( Route.Layout__Sidebar, "Sidebar" ) 66 | , ( Route.Layout__SplitScreen, "Split screen" ) 67 | , ( Route.Layout__StickyFooter, "Sticky footer" ) 68 | , ( Route.Layout__StickyHeader, "Sticky header" ) 69 | ] 70 | 71 | 72 | navigationNavItems : List ( Route, String ) 73 | navigationNavItems = 74 | [ ( Route.Navigation__Breadcrumb, "Breadcrumb" ) 75 | , ( Route.Navigation__Drawer, "Drawer" ) 76 | , ( Route.Navigation__Pagination, "Pagination" ) 77 | , ( Route.Navigation__Split, "Split navigation" ) 78 | , ( Route.Navigation__Tab, "Tab" ) 79 | ] 80 | 81 | 82 | inputNavItems : List ( Route, String ) 83 | inputNavItems = 84 | [ ( Route.Input__CustomCheckbox, "Custom checkbox" ) 85 | , ( Route.Input__CustomRadio, "Custom radio" ) 86 | , ( Route.Input__Dropdown, "Dropdown" ) 87 | , ( Route.Input__FloatingLabel, "Floating label" ) 88 | , ( Route.Input__RadioButtonGroup, "Radio button group" ) 89 | , ( Route.Input__Rating, "Rating" ) 90 | , ( Route.Input__SearchBox, "Search box" ) 91 | ] 92 | 93 | 94 | feedbackNavItems : List ( Route, String ) 95 | feedbackNavItems = 96 | [ ( Route.Feedback__Loader, "Loader" ) 97 | , ( Route.Feedback__Tooltip, "Tooltip" ) 98 | , ( Route.Feedback__ProgressBar, "Progress bar" ) 99 | , ( Route.Feedback__RadialProgressBar, "Radial progress bar" ) 100 | ] 101 | 102 | 103 | miscNavItems : List ( Route, String ) 104 | miscNavItems = 105 | [ ( Route.Misc__StickyColumnsTable, "Sticky columns table" ) 106 | , ( Route.Misc__StickyHeadersTable, "Sticky headers table" ) 107 | , ( Route.Misc__Timeline, "Timeline" ) 108 | ] 109 | 110 | 111 | navItem : ( Route, String ) -> ( String, Html msg ) 112 | navItem ( route, text ) = 113 | ( text 114 | , Html.li 115 | [] 116 | [ Html.a 117 | [ Html.href <| Route.toHref route ] 118 | [ Html.text text ] 119 | ] 120 | ) 121 | -------------------------------------------------------------------------------- /src/Components/Feedback/Loader.elm: -------------------------------------------------------------------------------- 1 | module Components.Feedback.Loader exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Animations 9 | import Css.Global 10 | import Html.Styled as Html exposing (Html) 11 | import Html.Styled.Attributes as Html 12 | import Styles.Colors as Colors 13 | 14 | 15 | 16 | -- MODEL 17 | 18 | 19 | type alias Model = 20 | () 21 | 22 | 23 | init : Model 24 | init = 25 | () 26 | 27 | 28 | 29 | -- VIEW 30 | 31 | 32 | view : Model -> Html msg 33 | view _ = 34 | Html.div 35 | [ Html.css css 36 | ] 37 | [ Html.div 38 | [ Html.class "loader" ] 39 | [] 40 | ] 41 | 42 | 43 | 44 | -- STYLES 45 | 46 | 47 | css : List Css.Style 48 | css = 49 | [ Css.width <| Css.pct 100 50 | , Css.height <| Css.px 400 51 | , Css.displayFlex 52 | , Css.alignItems Css.center 53 | , Css.justifyContent Css.center 54 | , Css.flexDirection Css.column 55 | , Css.Global.descendants 56 | [ Css.Global.selector ".loader" 57 | [ Css.borderRadius <| Css.pct 50 58 | , Css.height <| Css.rem 5 59 | , Css.width <| Css.rem 5 60 | , Css.position Css.relative 61 | , Css.border3 (Css.rem 0.5) Css.solid Colors.greyLighter 62 | , Css.borderLeft3 (Css.rem 0.5) Css.solid Colors.grey 63 | , Css.transform <| Css.translateZ Css.zero 64 | , Css.animationName load 65 | , Css.animationDuration <| Css.sec 1.1 66 | , Css.property "animation-timing-function" "linear" 67 | , Css.property "animation-iteration-count" "infinite" 68 | ] 69 | ] 70 | ] 71 | 72 | 73 | load : Css.Animations.Keyframes {} 74 | load = 75 | Css.Animations.keyframes 76 | [ ( 0, [ Css.Animations.transform [ Css.rotate <| Css.deg 0 ] ] ) 77 | , ( 100, [ Css.Animations.transform [ Css.rotate <| Css.deg 360 ] ] ) 78 | ] 79 | -------------------------------------------------------------------------------- /src/Components/Feedback/ProgressBar.elm: -------------------------------------------------------------------------------- 1 | module Components.Feedback.ProgressBar exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Styles.Colors as Colors 12 | 13 | 14 | 15 | -- MODEL 16 | 17 | 18 | type alias Model = 19 | { percentage : Int } 20 | 21 | 22 | init : Int -> Model 23 | init percentage = 24 | Model percentage 25 | 26 | 27 | 28 | -- VIEW 29 | 30 | 31 | view : Model -> Html msg 32 | view { percentage } = 33 | Html.div 34 | [ Html.css css ] 35 | [ Html.div 36 | [ Html.class "progress-bar" ] 37 | [ Html.div 38 | [ Html.class "progress-bar__inner" 39 | , Html.style "width" <| String.fromInt percentage ++ "%" 40 | ] 41 | [ Html.text <| String.fromInt percentage ++ "%" ] 42 | ] 43 | ] 44 | 45 | 46 | 47 | -- STYLES 48 | 49 | 50 | css : List Css.Style 51 | css = 52 | [ Css.width <| Css.pct 100 53 | , Css.height <| Css.px 400 54 | , Css.displayFlex 55 | , Css.alignItems Css.center 56 | , Css.justifyContent Css.center 57 | , Css.flexDirection Css.column 58 | , Css.Global.descendants 59 | [ Css.Global.selector ".progress-bar" 60 | [ Css.backgroundColor Colors.greyLighter 61 | , Css.borderRadius <| Css.px 9999 62 | , Css.width <| Css.pct 80 63 | , Css.Global.descendants 64 | [ Css.Global.selector ".progress-bar__inner" 65 | [ Css.displayFlex 66 | , Css.alignItems Css.center 67 | , Css.justifyContent Css.center 68 | , Css.backgroundColor Colors.blueLight 69 | , Css.color Colors.white 70 | , Css.borderRadius <| Css.px 9999 71 | , Css.overflow Css.hidden 72 | ] 73 | ] 74 | ] 75 | ] 76 | ] 77 | 78 | -------------------------------------------------------------------------------- /src/Components/Feedback/RadialProgressBar.elm: -------------------------------------------------------------------------------- 1 | module Components.Feedback.RadialProgressBar exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Styles.Colors as Colors 12 | 13 | 14 | 15 | -- MODEL 16 | 17 | 18 | type alias Model = 19 | { percentage : Int } 20 | 21 | 22 | init : Int -> Model 23 | init percentage = 24 | Model percentage 25 | 26 | 27 | 28 | -- VIEW 29 | 30 | 31 | view : Model -> Html msg 32 | view { percentage } = 33 | Html.div 34 | [ Html.css css ] 35 | [ Html.div 36 | [ Html.class "progress-bar" ] 37 | [ Html.div 38 | [ Html.class "progress-bar__percentage" ] 39 | [ Html.text <| String.fromInt percentage ++ "%" ] 40 | , Html.div 41 | [ Html.classList 42 | [ ( "progress-bar__inner", True ) 43 | , ( "progress-bar__inner--ge-50", percentage >= 50 ) 44 | ] 45 | ] 46 | [ Html.div 47 | [ Html.class "progress-bar__inner__1" 48 | , Html.style "transform" <| "rotate(" ++ String.fromInt (percentage * 360 // 100) ++ "deg)" 49 | ] 50 | [] 51 | , Html.div 52 | [ Html.classList 53 | [ ( "progress-bar__inner__2", True ) 54 | , ( "progress-bar__inner__2--ge-50", percentage >= 50 ) 55 | ] 56 | ] 57 | [] 58 | ] 59 | ] 60 | ] 61 | 62 | 63 | 64 | -- STYLES 65 | 66 | 67 | css : List Css.Style 68 | css = 69 | [ Css.width <| Css.pct 100 70 | , Css.height <| Css.px 400 71 | , Css.displayFlex 72 | , Css.alignItems Css.center 73 | , Css.justifyContent Css.center 74 | , Css.flexDirection Css.column 75 | , Css.Global.descendants 76 | [ Css.Global.selector ".progress-bar" 77 | [ Css.position Css.relative 78 | , Css.Global.descendants 79 | [ Css.Global.selector ".progress-bar__percentage" 80 | [ Css.displayFlex 81 | , Css.alignItems Css.center 82 | , Css.justifyContent Css.center 83 | , Css.border3 (Css.px 12) Css.solid Colors.greyLighter 84 | , Css.borderRadius <| Css.px 9999 85 | , Css.height <| Css.px 128 86 | , Css.width <| Css.px 128 87 | ] 88 | , Css.Global.selector ".progress-bar__inner" 89 | [ Css.position Css.absolute 90 | , Css.top Css.zero 91 | , Css.left Css.zero 92 | , Css.height <| Css.pct 100 93 | , Css.width <| Css.pct 100 94 | , Css.property "clip" "rect(0px, 128px, 128px, 64px)" 95 | , Css.Global.withClass "progress-bar__inner--ge-50" 96 | [ Css.property "clip" "rect(auto, auto, auto, auto)" ] 97 | ] 98 | , Css.Global.selector ".progress-bar__inner__1" 99 | [ Css.position Css.absolute 100 | , Css.height <| Css.pct 100 101 | , Css.width <| Css.pct 100 102 | , Css.border3 (Css.px 12) Css.solid Colors.blueLight 103 | , Css.borderRadius <| Css.px 9999 104 | , Css.property "clip" "rect(0px, 64px, 128px, 0px)" 105 | ] 106 | , Css.Global.selector ".progress-bar__inner__2" 107 | [ Css.position Css.absolute 108 | , Css.height <| Css.pct 100 109 | , Css.width <| Css.pct 100 110 | , Css.border3 (Css.px 12) Css.solid Colors.blueLight 111 | , Css.borderRadius <| Css.px 9999 112 | , Css.property "clip" "rect(0px, 64px, 128px, 0px)" 113 | , Css.transform <| Css.rotate <| Css.deg 0 114 | , Css.Global.withClass "progress-bar__inner__2--ge-50" 115 | [ Css.transform <| Css.rotate <| Css.deg 180 ] 116 | ] 117 | ] 118 | ] 119 | ] 120 | ] 121 | -------------------------------------------------------------------------------- /src/Components/Feedback/Tooltip.elm: -------------------------------------------------------------------------------- 1 | module Components.Feedback.Tooltip exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Css.Transitions 10 | import Html.Styled as Html exposing (Html) 11 | import Html.Styled.Attributes as Html 12 | import Placeholders.Block exposing (Block) 13 | import Placeholders.Rectangle exposing (Rectangle) 14 | import Styles.Colors as Colors 15 | 16 | 17 | 18 | -- MODEL 19 | 20 | 21 | type alias Model = 22 | { rectangle : Rectangle 23 | , block : Block 24 | } 25 | 26 | 27 | init : Model 28 | init = 29 | { rectangle = 30 | Placeholders.Rectangle.default 31 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 32 | |> Placeholders.Rectangle.withHeight (Css.px 4) 33 | , block = 34 | Placeholders.Block.default 35 | |> Placeholders.Block.withBackgroundColor Colors.grey 36 | } 37 | 38 | 39 | 40 | -- VIEW 41 | 42 | 43 | view : Model -> Html msg 44 | view { rectangle, block } = 45 | Html.div 46 | [ Html.css css 47 | ] 48 | [ Html.div 49 | [ Html.class "tooltip" ] 50 | [ Html.div 51 | [ Html.class "tooltip__content" ] 52 | [ Placeholders.Block.view block ] 53 | , Html.div 54 | [ Html.class "tooltip__trigger" ] 55 | [ Placeholders.Rectangle.view rectangle 56 | ] 57 | ] 58 | ] 59 | 60 | 61 | 62 | -- STYLES 63 | 64 | 65 | css : List Css.Style 66 | css = 67 | [ Css.width <| Css.pct 100 68 | , Css.height <| Css.px 400 69 | , Css.displayFlex 70 | , Css.alignItems Css.center 71 | , Css.justifyContent Css.center 72 | , Css.flexDirection Css.column 73 | , Css.Global.descendants 74 | [ Css.Global.selector ".tooltip" 75 | [ Css.position Css.relative 76 | , Css.hover 77 | [ Css.Global.descendants 78 | [ Css.Global.selector ".tooltip__content" 79 | [ Css.opacity <| Css.num 1 80 | , Css.pointerEventsAll 81 | ] 82 | ] 83 | ] 84 | ] 85 | , Css.Global.selector ".tooltip__content" 86 | [ Css.opacity Css.zero 87 | , Css.position Css.absolute 88 | , Css.backgroundColor Colors.blackLight 89 | , Css.width <| Css.px 200 90 | , Css.color Colors.white 91 | , Css.bottom <| Css.pct 100 92 | , Css.left <| Css.pct 50 93 | , Css.transform <| Css.translate2 (Css.pct -50) (Css.px -8) 94 | , Css.pointerEvents Css.none 95 | , Css.padding <| Css.rem 1 96 | , Css.borderRadius <| Css.px 4 97 | , Css.Transitions.transition 98 | [ Css.Transitions.opacity 200 ] 99 | , Css.after 100 | [ Css.property "content" "\" \"" 101 | , Css.position Css.absolute 102 | , Css.border3 (Css.px 8) Css.solid Css.transparent 103 | , Css.borderTopColor Colors.blackLight 104 | , Css.bottom Css.zero 105 | , Css.left <| Css.pct 50 106 | , Css.transform <| Css.translate2 (Css.pct -50) (Css.px 16) 107 | , Css.height Css.zero 108 | , Css.width Css.zero 109 | , Css.Transitions.transition 110 | [ Css.Transitions.opacity 200 ] 111 | ] 112 | ] 113 | , Css.Global.selector ".tooltip__trigger" 114 | [ Css.backgroundColor Colors.white 115 | , Css.padding <| Css.rem 1 116 | , Css.width <| Css.px 200 117 | , Css.border3 (Css.px 1) Css.solid Colors.grey 118 | , Css.borderRadius <| Css.px 4 119 | ] 120 | ] 121 | ] 122 | -------------------------------------------------------------------------------- /src/Components/Input/CustomCheckbox.elm: -------------------------------------------------------------------------------- 1 | module Components.Input.CustomCheckbox exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Html.Styled.Keyed 12 | import Placeholders.Rectangle exposing (Rectangle) 13 | import Styles.Colors as Colors 14 | 15 | 16 | 17 | -- MODEL 18 | 19 | 20 | type alias Model = 21 | { rectangle : Rectangle } 22 | 23 | 24 | init : Model 25 | init = 26 | { rectangle = 27 | Placeholders.Rectangle.default 28 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 29 | |> Placeholders.Rectangle.withHeight (Css.px 4) 30 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 31 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 32 | } 33 | 34 | 35 | 36 | -- VIEW 37 | 38 | 39 | view : Model -> Html msg 40 | view { rectangle } = 41 | Html.div 42 | [ Html.css css 43 | ] 44 | [ List.range 1 3 45 | |> List.map (checkBoxView rectangle) 46 | |> Html.Styled.Keyed.node "div" [] 47 | ] 48 | 49 | 50 | checkBoxView : Rectangle -> Int -> ( String, Html msg ) 51 | checkBoxView rectangle index = 52 | let 53 | id = 54 | "customCheckbox" ++ String.fromInt index 55 | in 56 | ( id 57 | , Html.label 58 | [ Html.class "custom-checkbox" 59 | , Html.for id 60 | ] 61 | [ Html.input 62 | [ Html.type_ "checkbox" 63 | , Html.id id 64 | , Html.class "custom-checkbox__input" 65 | ] 66 | [] 67 | , Html.div 68 | [ Html.class "custom-checkbox__icon" ] 69 | [ Html.div 70 | [ Html.class "custom-checkbox__inner-icon" ] 71 | [] 72 | ] 73 | , Placeholders.Rectangle.view rectangle 74 | ] 75 | ) 76 | 77 | 78 | 79 | -- STYLES 80 | 81 | 82 | css : List Css.Style 83 | css = 84 | [ Css.width <| Css.pct 100 85 | , Css.height <| Css.px 400 86 | , Css.displayFlex 87 | , Css.alignItems Css.center 88 | , Css.justifyContent Css.center 89 | , Css.flexDirection Css.column 90 | , Css.Global.descendants 91 | [ Css.Global.selector ".custom-checkbox" 92 | [ Css.displayFlex 93 | , Css.alignItems Css.center 94 | , Css.width <| Css.px 200 95 | , Css.cursor Css.pointer 96 | , Css.marginBottom <| Css.rem 1 97 | ] 98 | , Css.Global.selector ".custom-checkbox__input" 99 | [ Css.display Css.none 100 | , Css.checked 101 | [ Css.Global.generalSiblings 102 | [ Css.Global.selector ".custom-checkbox__icon > .custom-checkbox__inner-icon" 103 | [ Css.backgroundColor Colors.blue ] 104 | ] 105 | ] 106 | ] 107 | , Css.Global.selector ".custom-checkbox__icon" 108 | [ Css.border3 (Css.px 1) Css.solid Colors.grey 109 | , Css.borderRadius <| Css.px 4 110 | , Css.marginRight <| Css.rem 0.4 111 | , Css.padding <| Css.px 2 112 | ] 113 | , Css.Global.selector ".custom-checkbox__inner-icon" 114 | [ Css.borderRadius <| Css.px 4 115 | , Css.height <| Css.rem 0.8 116 | , Css.width <| Css.rem 0.8 117 | ] 118 | ] 119 | ] 120 | 121 | -------------------------------------------------------------------------------- /src/Components/Input/CustomRadio.elm: -------------------------------------------------------------------------------- 1 | module Components.Input.CustomRadio exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Html.Styled.Keyed 12 | import Placeholders.Rectangle exposing (Rectangle) 13 | import Styles.Colors as Colors 14 | 15 | 16 | 17 | -- MODEL 18 | 19 | 20 | type alias Model = 21 | { rectangle : Rectangle } 22 | 23 | 24 | init : Model 25 | init = 26 | { rectangle = 27 | Placeholders.Rectangle.default 28 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 29 | |> Placeholders.Rectangle.withHeight (Css.px 4) 30 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 31 | } 32 | 33 | 34 | 35 | -- VIEW 36 | 37 | 38 | view : Model -> Html msg 39 | view { rectangle } = 40 | Html.div 41 | [ Html.css css ] 42 | [ List.range 1 3 43 | |> List.map (radioView rectangle) 44 | |> Html.Styled.Keyed.node "div" [] 45 | ] 46 | 47 | 48 | radioView : Rectangle -> Int -> ( String, Html msg ) 49 | radioView rectangle index = 50 | let 51 | id = 52 | "customRadio" ++ String.fromInt index 53 | in 54 | ( id 55 | , Html.label 56 | [ Html.class "custom-radio" 57 | , Html.for id 58 | ] 59 | [ Html.input 60 | [ Html.type_ "radio" 61 | , Html.id id 62 | , Html.class "custom-radio__input" 63 | , Html.name "radio" 64 | ] 65 | [] 66 | , Html.div 67 | [ Html.class "custom-radio__icon" ] 68 | [ Html.div 69 | [ Html.class "custom-radio__inner-icon" ] 70 | [] 71 | ] 72 | , Placeholders.Rectangle.view rectangle 73 | ] 74 | ) 75 | 76 | 77 | 78 | -- STYLES 79 | 80 | 81 | css : List Css.Style 82 | css = 83 | [ Css.width <| Css.pct 100 84 | , Css.height <| Css.px 400 85 | , Css.displayFlex 86 | , Css.alignItems Css.center 87 | , Css.justifyContent Css.center 88 | , Css.flexDirection Css.column 89 | , Css.Global.descendants 90 | [ Css.Global.selector ".custom-radio" 91 | [ Css.displayFlex 92 | , Css.alignItems Css.center 93 | , Css.width <| Css.px 200 94 | , Css.cursor Css.pointer 95 | , Css.marginBottom <| Css.rem 1 96 | ] 97 | , Css.Global.selector ".custom-radio__input" 98 | [ Css.display Css.none 99 | , Css.checked 100 | [ Css.Global.generalSiblings 101 | [ Css.Global.selector ".custom-radio__icon > .custom-radio__inner-icon" 102 | [ Css.backgroundColor Colors.blue ] 103 | ] 104 | ] 105 | ] 106 | , Css.Global.selector ".custom-radio__icon" 107 | [ Css.border3 (Css.px 1) Css.solid Colors.grey 108 | , Css.borderRadius <| Css.pct 100 109 | , Css.marginRight <| Css.rem 0.4 110 | , Css.padding <| Css.px 2 111 | ] 112 | , Css.Global.selector ".custom-radio__inner-icon" 113 | [ Css.borderRadius <| Css.pct 100 114 | , Css.height <| Css.rem 0.8 115 | , Css.width <| Css.rem 0.8 116 | ] 117 | ] 118 | ] 119 | 120 | -------------------------------------------------------------------------------- /src/Components/Input/Dropdown.elm: -------------------------------------------------------------------------------- 1 | module Components.Input.Dropdown exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Block exposing (Block) 12 | import Placeholders.Rectangle exposing (Rectangle) 13 | import Placeholders.Triangle exposing (Triangle) 14 | import Styles.Colors as Colors 15 | 16 | 17 | 18 | -- MODEL 19 | 20 | 21 | type alias Model = 22 | { rectangle : Rectangle 23 | , triangle : Triangle 24 | , block : Block 25 | , smallBlock : Block 26 | } 27 | 28 | 29 | init : Model 30 | init = 31 | { rectangle = 32 | Placeholders.Rectangle.default 33 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 34 | |> Placeholders.Rectangle.withHeight (Css.px 4) 35 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 36 | , triangle = 37 | Placeholders.Triangle.default 38 | |> Placeholders.Triangle.withBottomCorner 39 | |> Placeholders.Triangle.withBackgroundColor Colors.grey 40 | |> Placeholders.Triangle.withSize (Css.px 8) 41 | , block = 42 | Placeholders.Block.default 43 | |> Placeholders.Block.withBackgroundColor Colors.grey 44 | |> Placeholders.Block.withItems [ 1, 2, 3, 2, 3, 4, 5, 2, 1, 2, 4, 2, 5, 3 ] 45 | , smallBlock = 46 | Placeholders.Block.default 47 | |> Placeholders.Block.withBackgroundColor Colors.grey 48 | |> Placeholders.Block.withItems [ 1, 2, 3, 2, 3, 2, 1, 3, 2 ] 49 | } 50 | 51 | 52 | 53 | -- VIEW 54 | 55 | 56 | view : Model -> Html msg 57 | view { rectangle, triangle, block, smallBlock } = 58 | Html.div 59 | [ Html.css css 60 | ] 61 | [ Html.div 62 | [ Html.class "dropdown" ] 63 | [ Html.div 64 | [ Html.class "button" ] 65 | [ Placeholders.Rectangle.view rectangle 66 | , Placeholders.Triangle.view triangle 67 | ] 68 | , Html.div 69 | [ Html.class "dropdown__content" ] 70 | [ Placeholders.Block.view smallBlock ] 71 | ] 72 | , Html.div 73 | [ Html.class "other-content" ] 74 | [ Placeholders.Block.view block ] 75 | ] 76 | 77 | 78 | 79 | -- STYLES 80 | 81 | 82 | css : List Css.Style 83 | css = 84 | [ Css.width <| Css.pct 100 85 | , Css.height <| Css.px 400 86 | , Css.displayFlex 87 | , Css.alignItems Css.center 88 | , Css.justifyContent Css.center 89 | , Css.flexDirection Css.column 90 | , Css.Global.descendants 91 | [ Css.Global.selector ".dropdown" 92 | [ Css.position Css.relative 93 | , Css.marginBottom <| Css.rem 1 94 | , Css.hover 95 | [ Css.Global.descendants 96 | [ Css.Global.selector ".dropdown__content" 97 | [ Css.display Css.block ] 98 | ] 99 | ] 100 | ] 101 | , Css.Global.selector ".button" 102 | [ Css.padding <| Css.rem 1 103 | , Css.width <| Css.px 200 104 | , Css.border3 (Css.px 1) Css.solid Colors.grey 105 | , Css.displayFlex 106 | , Css.alignItems Css.center 107 | , Css.justifyContent Css.spaceBetween 108 | , Css.borderRadius <| Css.px 4 109 | , Css.cursor Css.pointer 110 | ] 111 | , Css.Global.selector ".dropdown__content" 112 | [ Css.backgroundColor Colors.white 113 | , Css.padding <| Css.rem 1 114 | , Css.position Css.absolute 115 | , Css.top <| Css.pct 100 116 | , Css.right Css.zero 117 | , Css.border3 (Css.px 1) Css.solid Colors.grey 118 | , Css.borderRadius <| Css.px 4 119 | , Css.width <| Css.px 250 120 | , Css.marginTop <| Css.px 2 121 | , Css.display Css.none 122 | , Css.zIndex <| Css.int 9999 123 | ] 124 | , Css.Global.selector ".other-content" 125 | [ Css.width <| Css.pct 60 ] 126 | ] 127 | ] 128 | -------------------------------------------------------------------------------- /src/Components/Input/FloatingLabel.elm: -------------------------------------------------------------------------------- 1 | module Components.Input.FloatingLabel exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Css.Transitions 10 | import Html.Styled as Html exposing (Html) 11 | import Html.Styled.Attributes as Html 12 | import Styles.Colors as Colors 13 | 14 | 15 | 16 | -- MODEL 17 | 18 | 19 | type alias Model = 20 | () 21 | 22 | 23 | init : Model 24 | init = 25 | () 26 | 27 | 28 | 29 | -- VIEW 30 | 31 | 32 | view : Model -> Html msg 33 | view _ = 34 | Html.div 35 | [ Html.css css ] 36 | [ Html.div 37 | [ Html.class "floating-label" ] 38 | [ Html.input 39 | [ Html.class "floating-label__input" 40 | , Html.placeholder "Placeholder" 41 | , Html.autofocus True 42 | ] 43 | [] 44 | , Html.label 45 | [ Html.class "floating-label__label" ] 46 | [ Html.text "Placeholder" ] 47 | ] 48 | ] 49 | 50 | 51 | 52 | -- STYLES 53 | 54 | 55 | css : List Css.Style 56 | css = 57 | [ Css.width <| Css.pct 100 58 | , Css.height <| Css.px 400 59 | , Css.displayFlex 60 | , Css.alignItems Css.center 61 | , Css.justifyContent Css.center 62 | , Css.flexDirection Css.column 63 | , Css.Global.descendants 64 | [ Css.Global.selector ".floating-label" 65 | [ Css.position Css.relative 66 | , Css.Global.descendants 67 | [ Css.Global.selector ".floating-label__input" 68 | [ Css.padding <| Css.px 8 69 | , Css.borderRadius <| Css.px 4 70 | , Css.border3 (Css.px 1) Css.solid Colors.grey 71 | , Css.outline Css.none 72 | ] 73 | , Css.Global.selector ".floating-label__input:not(:placeholder-shown) + label" 74 | [ Css.backgroundColor Colors.white 75 | , Css.transform <| Css.translate2 Css.zero (Css.pct -50) 76 | , Css.opacity <| Css.num 1 77 | ] 78 | , Css.Global.selector ".floating-label__label" 79 | [ Css.position Css.absolute 80 | , Css.left <| Css.px 8 81 | , Css.top <| Css.px 0 82 | , Css.opacity Css.zero 83 | , Css.pointerEvents Css.none 84 | , Css.Transitions.transition 85 | [ Css.Transitions.opacity 200 86 | , Css.Transitions.transform 200 87 | ] 88 | ] 89 | ] 90 | ] 91 | ] 92 | ] 93 | -------------------------------------------------------------------------------- /src/Components/Input/RadioButtonGroup.elm: -------------------------------------------------------------------------------- 1 | module Components.Input.RadioButtonGroup exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Html.Styled.Keyed 12 | import Placeholders.Rectangle exposing (Rectangle) 13 | import Styles.Breakpoints as Breakpoints 14 | import Styles.Colors as Colors 15 | 16 | 17 | 18 | -- MODEL 19 | 20 | 21 | type alias Model = 22 | { rectangle : Rectangle } 23 | 24 | 25 | init : Model 26 | init = 27 | { rectangle = 28 | Placeholders.Rectangle.default 29 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 30 | |> Placeholders.Rectangle.withHeight (Css.px 4) 31 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 32 | } 33 | 34 | 35 | 36 | -- VIEW 37 | 38 | 39 | view : Model -> Html msg 40 | view { rectangle } = 41 | Html.div 42 | [ Html.css css ] 43 | [ List.range 1 3 44 | |> List.map (radioView rectangle) 45 | |> Html.Styled.Keyed.node "div" 46 | [ Html.class "radio-button-group" ] 47 | ] 48 | 49 | 50 | radioView : Rectangle -> Int -> ( String, Html msg ) 51 | radioView rectangle index = 52 | let 53 | id = 54 | "radioButton" ++ String.fromInt index 55 | 56 | checked = 57 | index == 1 58 | in 59 | ( id 60 | , Html.div 61 | [ Html.class "radio-button" ] 62 | [ Html.input 63 | [ Html.type_ "radio" 64 | , Html.id id 65 | , Html.class "radio-button__input" 66 | , Html.name "radio" 67 | , Html.checked checked 68 | ] 69 | [] 70 | , Html.label 71 | [ Html.class "radio-button__label" 72 | , Html.for id 73 | ] 74 | [ Placeholders.Rectangle.view rectangle ] 75 | ] 76 | ) 77 | 78 | 79 | 80 | -- STYLES 81 | 82 | 83 | css : List Css.Style 84 | css = 85 | [ Css.width <| Css.pct 100 86 | , Css.height <| Css.px 400 87 | , Css.displayFlex 88 | , Css.alignItems Css.center 89 | , Css.justifyContent Css.center 90 | , Css.flexDirection Css.column 91 | , Css.Global.descendants 92 | [ Css.Global.selector ".radio-button-group" 93 | [ Css.displayFlex 94 | , Css.border3 (Css.px 1) Css.solid Colors.grey 95 | , Css.borderRadius <| Css.px 4 96 | ] 97 | , Css.Global.selector ".radio-button" 98 | [ Css.displayFlex 99 | , Css.flex <| Css.int 1 100 | ] 101 | , Css.Global.selector ".radio-button__label" 102 | [ Css.displayFlex 103 | , Css.alignItems Css.center 104 | , Css.justifyContent Css.center 105 | , Css.flex <| Css.int 1 106 | , Css.padding <| Css.rem 0.8 107 | , Css.width <| Css.px 150 108 | , Css.cursor Css.pointer 109 | , Breakpoints.small 110 | [ Css.width <| Css.px 80 ] 111 | ] 112 | , Css.Global.selector ".radio-button:not(:last-of-type)" 113 | [ Css.borderRight3 (Css.px 1) Css.solid Colors.grey ] 114 | , Css.Global.selector ".radio-button__input" 115 | [ Css.display Css.none 116 | , Css.checked 117 | [ Css.Global.generalSiblings 118 | [ Css.Global.selector ".radio-button__label" 119 | [ Css.backgroundColor Colors.blue ] 120 | ] 121 | ] 122 | ] 123 | ] 124 | ] 125 | -------------------------------------------------------------------------------- /src/Components/Input/Rating.elm: -------------------------------------------------------------------------------- 1 | module Components.Input.Rating exposing 2 | ( Model 3 | , Msg 4 | , init 5 | , update 6 | , view 7 | ) 8 | 9 | import Css 10 | import Css.Global 11 | import Html.Styled as Html exposing (Html) 12 | import Html.Styled.Attributes as Html 13 | import Html.Styled.Events as Html 14 | import Html.Styled.Keyed 15 | import Styles.Colors as Colors 16 | 17 | 18 | 19 | -- MODEL 20 | 21 | 22 | type alias Model = 23 | { score : Int } 24 | 25 | 26 | init : Model 27 | init = 28 | { score = 1 } 29 | 30 | 31 | 32 | -- UPDATE 33 | 34 | 35 | type Msg 36 | = OnStarClick Int 37 | 38 | 39 | update : Msg -> Model -> Model 40 | update msg model = 41 | case msg of 42 | OnStarClick score -> 43 | { model | score = score } 44 | 45 | 46 | 47 | -- VIEW 48 | 49 | 50 | view : Model -> Html Msg 51 | view { score } = 52 | Html.div 53 | [ Html.css css 54 | ] 55 | [ List.range 1 5 56 | |> List.reverse 57 | |> List.map (starView score) 58 | |> Html.Styled.Keyed.node "div" [ Html.class "rating" ] 59 | ] 60 | 61 | 62 | starView : Int -> Int -> ( String, Html Msg ) 63 | starView index score = 64 | ( "star_" ++ String.fromInt index 65 | , Html.span 66 | [ Html.classList 67 | [ ( "rating__star", True ) 68 | , ( "rating__star--active", index == score ) 69 | ] 70 | , Html.onClick <| OnStarClick score 71 | ] 72 | [ Html.text "★" ] 73 | ) 74 | 75 | 76 | 77 | -- STYLES 78 | 79 | 80 | css : List Css.Style 81 | css = 82 | [ Css.width <| Css.pct 100 83 | , Css.height <| Css.px 400 84 | , Css.displayFlex 85 | , Css.alignItems Css.center 86 | , Css.justifyContent Css.center 87 | , Css.flexDirection Css.column 88 | , Css.Global.descendants 89 | [ Css.Global.selector ".rating" 90 | [ Css.displayFlex 91 | , Css.alignItems Css.center 92 | , Css.flexDirection Css.rowReverse 93 | ] 94 | , Css.Global.selector ".rating__star" 95 | [ Css.backgroundColor Css.transparent 96 | , Css.color Colors.grey 97 | , Css.fontSize Css.larger 98 | , Css.cursor Css.pointer 99 | ] 100 | , Css.Global.selector ".rating__star:hover" 101 | [ Css.color Colors.blue ] 102 | , Css.Global.selector ".rating__star--active" 103 | [ Css.color Colors.blue ] 104 | , Css.Global.selector ".rating__star:hover ~ .rating__star" 105 | [ Css.color Colors.blue ] 106 | , Css.Global.selector ".rating__star--active ~ .rating__star" 107 | [ Css.color Colors.blue ] 108 | ] 109 | ] 110 | 111 | -------------------------------------------------------------------------------- /src/Components/Input/SearchBox.elm: -------------------------------------------------------------------------------- 1 | module Components.Input.SearchBox exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Circle exposing (Circle) 12 | import Styles.Colors as Colors 13 | 14 | 15 | 16 | -- MODEL 17 | 18 | 19 | type alias Model = 20 | { circle : Circle } 21 | 22 | 23 | init : Model 24 | init = 25 | { circle = 26 | Placeholders.Circle.default 27 | |> Placeholders.Circle.withSize (Css.px 16) 28 | |> Placeholders.Circle.withBackgroundColor Colors.grey 29 | } 30 | 31 | 32 | 33 | -- VIEW 34 | 35 | 36 | view : Model -> Html msg 37 | view { circle } = 38 | Html.div 39 | [ Html.css css ] 40 | [ Html.div 41 | [ Html.class "search-box" ] 42 | [ Placeholders.Circle.view circle 43 | , Html.input 44 | [ Html.class "search-box__input" 45 | , Html.placeholder "Search" 46 | , Html.autofocus True 47 | ] 48 | [] 49 | ] 50 | ] 51 | 52 | 53 | 54 | -- STYLES 55 | 56 | 57 | css : List Css.Style 58 | css = 59 | [ Css.width <| Css.pct 100 60 | , Css.height <| Css.px 400 61 | , Css.displayFlex 62 | , Css.alignItems Css.center 63 | , Css.justifyContent Css.center 64 | , Css.flexDirection Css.column 65 | , Css.Global.descendants 66 | [ Css.Global.selector ".search-box" 67 | [ Css.displayFlex 68 | , Css.alignItems Css.center 69 | , Css.border3 (Css.px 1) Css.solid Colors.grey 70 | , Css.padding <| Css.px 8 71 | , Css.borderRadius <| Css.px 4 72 | , Css.Global.descendants 73 | [ Css.Global.selector ".search-box__input" 74 | [ Css.border <| Css.px 0 75 | , Css.flex <| Css.int 1 76 | , Css.paddingLeft <| Css.rem 0.5 77 | , Css.outline Css.none 78 | ] 79 | ] 80 | ] 81 | ] 82 | ] 83 | -------------------------------------------------------------------------------- /src/Components/Layout/Card.elm: -------------------------------------------------------------------------------- 1 | module Components.Layout.Card exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Html.Styled.Keyed 12 | import Placeholders.Square exposing (Square) 13 | import Styles.Colors as Colors 14 | 15 | 16 | 17 | -- MODEL 18 | 19 | 20 | type alias Model = 21 | { square : Square } 22 | 23 | 24 | init : Model 25 | init = 26 | { square = 27 | Placeholders.Square.default 28 | |> Placeholders.Square.withBackgroundColor Colors.grey 29 | |> Placeholders.Square.withSize (Css.px 112) 30 | } 31 | 32 | 33 | 34 | -- VIEW 35 | 36 | 37 | view : Model -> Html msg 38 | view { square } = 39 | List.range 1 12 40 | |> List.map (cardView square) 41 | |> Html.Styled.Keyed.node "div" 42 | [ Html.css css ] 43 | 44 | 45 | cardView : Square -> Int -> ( String, Html msg ) 46 | cardView square index = 47 | ( "card" ++ String.fromInt index 48 | , Html.div 49 | [] 50 | [ Placeholders.Square.view square ] 51 | ) 52 | 53 | 54 | 55 | -- STYLES 56 | 57 | 58 | css : List Css.Style 59 | css = 60 | [ Css.displayFlex 61 | , Css.flexWrap Css.wrap 62 | , Css.margin2 Css.zero (Css.px -8) 63 | , Css.width <| Css.pct 100 64 | , Css.paddingTop <| Css.rem 1 65 | , Css.Global.descendants 66 | [ Css.Global.selector "> div" 67 | [ Css.flexBasis <| Css.pct 25 68 | , Css.padding2 Css.zero (Css.px 8) 69 | , Css.marginBottom <| Css.rem 1 70 | ] 71 | , Css.Global.selector "> div > div" 72 | [ Css.width <| Css.pct 100 73 | ] 74 | ] 75 | ] 76 | -------------------------------------------------------------------------------- /src/Components/Layout/HolyGrail.elm: -------------------------------------------------------------------------------- 1 | module Components.Layout.HolyGrail exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Block exposing (Block) 12 | import Placeholders.Rectangle exposing (Rectangle) 13 | import Styles.Colors as Colors 14 | 15 | 16 | 17 | -- MODEL 18 | 19 | 20 | type alias Model = 21 | { leftBlock : Block 22 | , rightBlock : Block 23 | , mainBlock : Block 24 | , rectangle : Rectangle 25 | } 26 | 27 | 28 | init : Model 29 | init = 30 | { leftBlock = 31 | Placeholders.Block.default 32 | |> Placeholders.Block.withBackgroundColor Colors.grey 33 | |> Placeholders.Block.withItems [ 2, 1, 3, 2, 1, 3 ] 34 | , rightBlock = 35 | Placeholders.Block.default 36 | |> Placeholders.Block.withBackgroundColor Colors.grey 37 | |> Placeholders.Block.withItems [ 2, 1, 3, 2 ] 38 | , mainBlock = 39 | Placeholders.Block.default 40 | |> Placeholders.Block.withBackgroundColor Colors.grey 41 | |> Placeholders.Block.withItems [ 1, 2, 3, 2, 3, 4, 5, 2, 1, 2, 4, 2, 5, 3 ] 42 | , rectangle = 43 | Placeholders.Rectangle.default 44 | |> Placeholders.Rectangle.withHeight (Css.px 8) 45 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 46 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 47 | } 48 | 49 | 50 | 51 | -- VIEW 52 | 53 | 54 | view : Model -> Html msg 55 | view { leftBlock, rightBlock, mainBlock, rectangle } = 56 | Html.div 57 | [ Html.css css 58 | ] 59 | [ Html.header 60 | [] 61 | [ Placeholders.Rectangle.view rectangle ] 62 | , Html.main_ 63 | [] 64 | [ Html.aside 65 | [] 66 | [ Placeholders.Block.view leftBlock ] 67 | , List.range 1 3 68 | |> List.map (\_ -> Placeholders.Block.view mainBlock) 69 | |> Html.article [] 70 | , Html.nav 71 | [] 72 | [ Placeholders.Block.view rightBlock ] 73 | ] 74 | , Html.footer 75 | [] 76 | [ Placeholders.Rectangle.view rectangle ] 77 | ] 78 | 79 | 80 | 81 | -- STYLES 82 | 83 | 84 | css : List Css.Style 85 | css = 86 | [ Css.displayFlex 87 | , Css.flexDirection Css.column 88 | , Css.width <| Css.pct 100 89 | , Css.height <| Css.px 400 90 | , Css.Global.descendants 91 | [ Css.Global.selector "> header" 92 | [ Css.displayFlex 93 | , Css.alignItems Css.center 94 | , Css.padding <| Css.rem 1 95 | , Css.borderBottom3 (Css.px 1) Css.solid Colors.greyLighter 96 | ] 97 | , Css.Global.selector "main" 98 | [ Css.flexGrow <| Css.int 1 99 | , Css.displayFlex 100 | , Css.flexDirection Css.row 101 | , Css.Global.descendants 102 | [ Css.Global.selector "> div" 103 | [ Css.marginBottom <| Css.rem 1 ] 104 | ] 105 | ] 106 | , Css.Global.selector "article" 107 | [ Css.flexGrow <| Css.int 1 108 | , Css.padding <| Css.rem 1 109 | ] 110 | , Css.Global.selector "aside" 111 | [ Css.width <| Css.pct 25 112 | , Css.borderRight3 (Css.px 1) Css.solid Colors.greyLighter 113 | , Css.padding <| Css.rem 1 114 | ] 115 | , Css.Global.selector "nav" 116 | [ Css.width <| Css.pct 20 117 | , Css.borderLeft3 (Css.px 1) Css.solid Colors.greyLighter 118 | , Css.padding <| Css.rem 1 119 | ] 120 | , Css.Global.selector "> footer" 121 | [ Css.displayFlex 122 | , Css.alignItems Css.center 123 | , Css.padding <| Css.rem 1 124 | , Css.borderTop3 (Css.px 1) Css.solid Colors.greyLighter 125 | ] 126 | ] 127 | ] 128 | -------------------------------------------------------------------------------- /src/Components/Layout/SameHeightColumns.elm: -------------------------------------------------------------------------------- 1 | module Components.Layout.SameHeightColumns exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Block exposing (Block) 12 | import Styles.Colors as Colors 13 | 14 | 15 | 16 | -- MODEL 17 | 18 | 19 | type alias Model = 20 | { block : Block 21 | , smallBlock : Block 22 | , largeBlock : Block 23 | } 24 | 25 | 26 | init : Model 27 | init = 28 | { block = 29 | Placeholders.Block.default 30 | |> Placeholders.Block.withBackgroundColor Colors.grey 31 | , smallBlock = 32 | Placeholders.Block.default 33 | |> Placeholders.Block.withBackgroundColor Colors.grey 34 | |> Placeholders.Block.withItems [ 3 ] 35 | , largeBlock = 36 | Placeholders.Block.default 37 | |> Placeholders.Block.withBackgroundColor Colors.grey 38 | |> Placeholders.Block.withItems [ 1, 2, 3, 2, 3, 4, 5, 2, 1, 2, 4, 2, 5, 3 ] 39 | } 40 | 41 | 42 | 43 | -- VIEW 44 | 45 | 46 | view : Model -> Html msg 47 | view { block, smallBlock, largeBlock } = 48 | Html.div 49 | [ Html.css css ] 50 | [ Html.div 51 | [ Html.class "equal-height" ] 52 | [ Html.div 53 | [ Html.class "equal-height__column" ] 54 | [ Placeholders.Block.view block ] 55 | , Html.div 56 | [ Html.class "equal-height__column" ] 57 | [ Placeholders.Block.view smallBlock ] 58 | , Html.div 59 | [ Html.class "equal-height__column" ] 60 | [ Placeholders.Block.view largeBlock ] 61 | ] 62 | ] 63 | 64 | 65 | 66 | -- STYLES 67 | 68 | 69 | css : List Css.Style 70 | css = 71 | [ Css.displayFlex 72 | , Css.width <| Css.pct 100 73 | , Css.height <| Css.px 400 74 | , Css.Global.descendants 75 | [ Css.Global.selector ".equal-height" 76 | [ Css.padding <| Css.rem 1 77 | , Css.displayFlex 78 | , Css.width <| Css.pct 100 79 | ] 80 | , Css.Global.selector ".equal-height__column" 81 | [ Css.flex <| Css.int 1 82 | , Css.margin2 Css.zero (Css.px 8) 83 | , Css.padding <| Css.rem 1 84 | , Css.border3 (Css.px 1) Css.solid Colors.greyLighter 85 | , Css.borderRadius <| Css.px 4 86 | ] 87 | , Css.Global.selector ".equal-height__column:not(:last-of-type)" 88 | [ Css.marginRight <| Css.rem 1 ] 89 | ] 90 | ] 91 | -------------------------------------------------------------------------------- /src/Components/Layout/Sidebar.elm: -------------------------------------------------------------------------------- 1 | module Components.Layout.Sidebar exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Block exposing (Block) 12 | import Styles.Colors as Colors 13 | 14 | 15 | 16 | -- MODEL 17 | 18 | 19 | type alias Model = 20 | { block : Block 21 | , singleBlock : Block 22 | } 23 | 24 | 25 | init : Model 26 | init = 27 | { block = 28 | Placeholders.Block.default 29 | |> Placeholders.Block.withBackgroundColor Colors.grey 30 | |> Placeholders.Block.withItems [ 1, 2, 3, 2, 3, 4, 5, 2, 1, 2, 4, 2, 5, 3 ] 31 | , singleBlock = 32 | Placeholders.Block.default 33 | |> Placeholders.Block.withBackgroundColor Colors.grey 34 | |> Placeholders.Block.withItems [ 3 ] 35 | } 36 | 37 | 38 | 39 | -- VIEW 40 | 41 | 42 | view : Model -> Html msg 43 | view { block, singleBlock } = 44 | Html.div 45 | [ Html.css css ] 46 | [ Html.aside 47 | [] 48 | [ Html.div 49 | [] 50 | [ Placeholders.Block.view singleBlock 51 | , Placeholders.Block.view singleBlock 52 | , Placeholders.Block.view singleBlock 53 | ] 54 | , Html.div 55 | [] 56 | [ Placeholders.Block.view singleBlock ] 57 | ] 58 | , List.range 1 6 59 | |> List.map (\_ -> Placeholders.Block.view block) 60 | |> Html.main_ 61 | [] 62 | ] 63 | 64 | 65 | 66 | -- STYLES 67 | 68 | 69 | css : List Css.Style 70 | css = 71 | [ Css.displayFlex 72 | , Css.width <| Css.pct 100 73 | , Css.height <| Css.px 400 74 | , Css.Global.descendants 75 | [ Css.Global.selector "aside" 76 | [ Css.width <| Css.pct 30 77 | , Css.padding <| Css.rem 1 78 | , Css.borderRight3 (Css.px 1) Css.solid Colors.greyLighter 79 | , Css.displayFlex 80 | , Css.flexDirection Css.column 81 | , Css.justifyContent Css.spaceBetween 82 | ] 83 | , Css.Global.selector "main" 84 | [ Css.flex <| Css.int 1 85 | , Css.overflow Css.auto 86 | , Css.padding <| Css.rem 1 87 | , Css.Global.descendants 88 | [ Css.Global.selector "> div" 89 | [ Css.marginBottom <| Css.rem 1 ] 90 | ] 91 | ] 92 | ] 93 | ] 94 | -------------------------------------------------------------------------------- /src/Components/Layout/SplitScreen.elm: -------------------------------------------------------------------------------- 1 | module Components.Layout.SplitScreen exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Block exposing (Block) 12 | import Placeholders.Circle exposing (Circle) 13 | import Placeholders.Rectangle exposing (Rectangle) 14 | import Styles.Colors as Colors 15 | 16 | 17 | 18 | -- MODEL 19 | 20 | 21 | type alias Model = 22 | { block : Block 23 | , circle : Circle 24 | , rectangle : Rectangle 25 | } 26 | 27 | 28 | init : Model 29 | init = 30 | { block = 31 | Placeholders.Block.default 32 | |> Placeholders.Block.withBackgroundColor Colors.grey 33 | , circle = 34 | Placeholders.Circle.default 35 | |> Placeholders.Circle.withBackgroundColor Colors.grey 36 | , rectangle = 37 | Placeholders.Rectangle.default 38 | |> Placeholders.Rectangle.withHeight (Css.px 8) 39 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 40 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 41 | } 42 | 43 | 44 | 45 | -- VIEW 46 | 47 | 48 | view : Model -> Html msg 49 | view { block, circle, rectangle } = 50 | Html.div 51 | [ Html.css css ] 52 | [ Html.div 53 | [] 54 | [ Html.div 55 | [ Html.class "inner-wrapper inner-wrapper--center" ] 56 | [ Placeholders.Circle.view circle 57 | , Placeholders.Rectangle.view rectangle 58 | ] 59 | ] 60 | , Html.div 61 | [] 62 | [ Placeholders.Rectangle.view rectangle 63 | , List.range 1 6 64 | |> List.map (\_ -> Placeholders.Block.view block) 65 | |> Html.div 66 | [ Html.class "inner-wrapper" ] 67 | ] 68 | ] 69 | 70 | 71 | 72 | -- STYLES 73 | 74 | 75 | css : List Css.Style 76 | css = 77 | [ Css.displayFlex 78 | , Css.width <| Css.pct 100 79 | , Css.height <| Css.px 400 80 | , Css.Global.descendants 81 | [ Css.Global.selector "> div" 82 | [ Css.flex <| Css.int 1 83 | , Css.displayFlex 84 | , Css.flexDirection Css.column 85 | , Css.alignItems Css.center 86 | , Css.justifyContent Css.center 87 | , Css.padding <| Css.rem 1 88 | , Css.firstOfType 89 | [ Css.borderRight3 (Css.px 1) Css.solid Colors.greyLighter 90 | ] 91 | ] 92 | , Css.Global.selector ".inner-wrapper" 93 | [ Css.width <| Css.pct 100 94 | , Css.Global.descendants 95 | [ Css.Global.selector "> div" 96 | [ Css.marginBottom <| Css.rem 1 ] 97 | ] 98 | ] 99 | , Css.Global.selector ".inner-wrapper--center" 100 | [ Css.displayFlex 101 | , Css.alignItems Css.center 102 | , Css.flexDirection Css.column 103 | ] 104 | , Css.Global.selector ".placeholder-rectangle" 105 | [ Css.marginBottom <| Css.em 1 ] 106 | ] 107 | ] 108 | -------------------------------------------------------------------------------- /src/Components/Layout/StickyFooter.elm: -------------------------------------------------------------------------------- 1 | module Components.Layout.StickyFooter exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Block exposing (Block) 12 | import Placeholders.Rectangle exposing (Rectangle) 13 | import Styles.Colors as Colors 14 | 15 | 16 | 17 | -- MODEL 18 | 19 | 20 | type alias Model = 21 | { block : Block 22 | , rectangle : Rectangle 23 | } 24 | 25 | 26 | init : Model 27 | init = 28 | { block = 29 | Placeholders.Block.default 30 | |> Placeholders.Block.withBackgroundColor Colors.grey 31 | , rectangle = 32 | Placeholders.Rectangle.default 33 | |> Placeholders.Rectangle.withHeight (Css.px 8) 34 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 35 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 36 | } 37 | 38 | 39 | 40 | -- VIEW 41 | 42 | 43 | view : Model -> Html msg 44 | view { block, rectangle } = 45 | Html.div 46 | [ Html.css css ] 47 | [ Html.header 48 | [] 49 | [ Placeholders.Rectangle.view rectangle ] 50 | , List.range 1 3 51 | |> List.map (\_ -> Placeholders.Block.view block) 52 | |> Html.main_ [] 53 | , Html.footer 54 | [] 55 | [ Placeholders.Rectangle.view rectangle ] 56 | ] 57 | 58 | 59 | 60 | -- STYLES 61 | 62 | 63 | css : List Css.Style 64 | css = 65 | [ Css.displayFlex 66 | , Css.flexDirection Css.column 67 | , Css.width <| Css.pct 100 68 | , Css.height <| Css.px 400 69 | , Css.Global.descendants 70 | [ Css.Global.selector "> header" 71 | [ Css.displayFlex 72 | , Css.flexShrink <| Css.int 0 73 | , Css.alignItems Css.center 74 | , Css.padding <| Css.rem 1 75 | , Css.borderBottom3 (Css.px 1) Css.solid Colors.greyLighter 76 | ] 77 | , Css.Global.selector "main" 78 | [ Css.width <| Css.pct 100 79 | , Css.padding <| Css.rem 1 80 | , Css.overflow Css.auto 81 | , Css.flexGrow <| Css.int 1 82 | , Css.Global.descendants 83 | [ Css.Global.selector "> div" 84 | [ Css.marginBottom <| Css.rem 1 ] 85 | ] 86 | ] 87 | , Css.Global.selector "> footer" 88 | [ Css.displayFlex 89 | , Css.flexShrink <| Css.int 0 90 | , Css.alignItems Css.center 91 | , Css.padding <| Css.rem 1 92 | , Css.borderTop3 (Css.px 1) Css.solid Colors.greyLighter 93 | ] 94 | ] 95 | ] 96 | -------------------------------------------------------------------------------- /src/Components/Layout/StickyHeader.elm: -------------------------------------------------------------------------------- 1 | module Components.Layout.StickyHeader exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Block exposing (Block) 12 | import Placeholders.Rectangle exposing (Rectangle) 13 | import Styles.Colors as Colors 14 | 15 | 16 | 17 | -- MODEL 18 | 19 | 20 | type alias Model = 21 | { block : Block 22 | , rectangle : Rectangle 23 | } 24 | 25 | 26 | init : Model 27 | init = 28 | { block = 29 | Placeholders.Block.default 30 | |> Placeholders.Block.withBackgroundColor Colors.grey 31 | |> Placeholders.Block.withItems [ 3, 2, 1, 4, 5, 4, 3, 1, 3, 4, 5, 3, 2, 1, 2, 1, 4, 5 ] 32 | , rectangle = 33 | Placeholders.Rectangle.default 34 | |> Placeholders.Rectangle.withHeight (Css.px 8) 35 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 36 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 37 | } 38 | 39 | 40 | 41 | -- VIEW 42 | 43 | 44 | view : Model -> Html msg 45 | view { block, rectangle } = 46 | Html.div 47 | [ Html.css css ] 48 | [ Html.header 49 | [] 50 | [ Placeholders.Rectangle.view rectangle ] 51 | , List.range 1 6 52 | |> List.map (\_ -> Placeholders.Block.view block) 53 | |> Html.main_ [] 54 | ] 55 | 56 | 57 | 58 | -- STYLES 59 | 60 | 61 | css : List Css.Style 62 | css = 63 | [ Css.displayFlex 64 | , Css.flexDirection Css.column 65 | , Css.width <| Css.pct 100 66 | , Css.height <| Css.px 400 67 | , Css.Global.descendants 68 | [ Css.Global.selector "> header" 69 | [ Css.displayFlex 70 | , Css.alignItems Css.center 71 | , Css.padding <| Css.rem 1 72 | , Css.borderBottom3 (Css.px 1) Css.solid Colors.greyLighter 73 | ] 74 | , Css.Global.selector "main" 75 | [ Css.width <| Css.pct 100 76 | , Css.padding <| Css.rem 1 77 | , Css.overflow Css.auto 78 | , Css.Global.descendants 79 | [ Css.Global.selector "> div" 80 | [ Css.marginBottom <| Css.rem 1 ] 81 | ] 82 | ] 83 | ] 84 | ] 85 | -------------------------------------------------------------------------------- /src/Components/Misc/StickyColumnsTable.elm: -------------------------------------------------------------------------------- 1 | module Components.Misc.StickyColumnsTable exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Html.Styled.Keyed 12 | import List 13 | import Placeholders.Rectangle exposing (Rectangle) 14 | import Styles.Breakpoints as Breakpoints 15 | import Styles.Colors as Colors 16 | 17 | 18 | 19 | -- MODEL 20 | 21 | 22 | type alias Model = 23 | { rectangle : Rectangle } 24 | 25 | 26 | init : Model 27 | init = 28 | { rectangle = 29 | Placeholders.Rectangle.default 30 | |> Placeholders.Rectangle.withHeight (Css.px 8) 31 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 32 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 33 | } 34 | 35 | 36 | 37 | -- VIEW 38 | 39 | 40 | view : Model -> Html msg 41 | view { rectangle } = 42 | Html.div 43 | [ Html.css css ] 44 | [ Html.div 45 | [ Html.class "sticky-columns-table" ] 46 | [ Html.table 47 | [ Html.class "sticky-columns-table__table" ] 48 | [ List.range 1 5 49 | |> List.map (trView rectangle) 50 | |> Html.Styled.Keyed.node "tbody" [] 51 | ] 52 | ] 53 | ] 54 | 55 | 56 | trView : Rectangle -> Int -> ( String, Html msg ) 57 | trView rectangle index = 58 | ( "tr_" ++ String.fromInt index 59 | , Html.tr 60 | [] 61 | [ Html.td 62 | [ Html.class "sticky-columns-table__th" ] 63 | [ Placeholders.Rectangle.view rectangle ] 64 | , Html.td 65 | [ Html.class "sticky-columns-table__td" ] 66 | [ Placeholders.Rectangle.view rectangle ] 67 | , Html.td 68 | [ Html.class "sticky-columns-table__td" ] 69 | [ Placeholders.Rectangle.view rectangle ] 70 | , Html.td 71 | [ Html.class "sticky-columns-table__td" ] 72 | [ Placeholders.Rectangle.view rectangle ] 73 | , Html.td 74 | [ Html.class "sticky-columns-table__td" ] 75 | [ Placeholders.Rectangle.view rectangle ] 76 | , Html.td 77 | [ Html.class "sticky-columns-table__td" ] 78 | [ Placeholders.Rectangle.view rectangle ] 79 | , Html.td 80 | [ Html.class "sticky-columns-table__td" ] 81 | [ Placeholders.Rectangle.view rectangle ] 82 | ] 83 | ) 84 | 85 | 86 | 87 | -- STYLES 88 | 89 | 90 | css : List Css.Style 91 | css = 92 | [ Css.displayFlex 93 | , Css.flexDirection Css.column 94 | , Css.alignItems Css.center 95 | , Css.justifyContent Css.center 96 | , Css.width <| Css.pct 100 97 | , Css.height <| Css.px 400 98 | , Css.Global.descendants 99 | [ Css.Global.selector ".sticky-columns-table" 100 | [ Css.width <| Css.px 550 101 | , Css.border3 (Css.px 1) Css.solid Colors.greyLight 102 | , Css.overflow Css.scroll 103 | , Css.position Css.relative 104 | , Breakpoints.small 105 | [ Css.width <| Css.px 250 ] 106 | ] 107 | , Css.Global.selector ".sticky-columns-table__table" 108 | [ Css.borderCollapse Css.collapse 109 | , Css.width <| Css.pct 100 110 | ] 111 | , Css.Global.selector ".sticky-columns-table__th" 112 | [ Css.padding <| Css.rem 1 113 | , Css.backgroundColor Colors.greyLighter 114 | , Css.position Css.sticky 115 | , Css.left Css.zero 116 | , Css.zIndex <| Css.int 9999 117 | ] 118 | , Css.Global.selector ".sticky-columns-table__td" 119 | [ Css.padding <| Css.rem 1 ] 120 | , Css.Global.selector ".placeholder-rectangle" 121 | [ Css.width <| Css.px 150 122 | , Breakpoints.small 123 | [ Css.width <| Css.px 50 ] 124 | ] 125 | ] 126 | ] 127 | -------------------------------------------------------------------------------- /src/Components/Misc/StickyHeadersTable.elm: -------------------------------------------------------------------------------- 1 | module Components.Misc.StickyHeadersTable exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Html.Styled.Keyed 12 | import List 13 | import Placeholders.Rectangle exposing (Rectangle) 14 | import Styles.Colors as Colors 15 | 16 | 17 | 18 | -- MODEL 19 | 20 | 21 | type alias Model = 22 | { rectangle : Rectangle } 23 | 24 | 25 | init : Model 26 | init = 27 | { rectangle = 28 | Placeholders.Rectangle.default 29 | |> Placeholders.Rectangle.withHeight (Css.px 8) 30 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 31 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 32 | } 33 | 34 | 35 | 36 | -- VIEW 37 | 38 | 39 | view : Model -> Html msg 40 | view { rectangle } = 41 | Html.div 42 | [ Html.css css ] 43 | [ Html.div 44 | [ Html.class "sticky-headers-table" ] 45 | [ Html.table 46 | [ Html.class "sticky-headers-table__table" ] 47 | [ Html.thead 48 | [] 49 | [ List.range 1 4 50 | |> List.map (thView rectangle) 51 | |> Html.Styled.Keyed.node "tr" [] 52 | ] 53 | , List.range 1 10 54 | |> List.map (trView rectangle) 55 | |> Html.Styled.Keyed.node "tbody" [] 56 | ] 57 | ] 58 | ] 59 | 60 | 61 | thView : Rectangle -> Int -> ( String, Html msg ) 62 | thView rectangle index = 63 | ( "th_" ++ String.fromInt index 64 | , Html.th 65 | [ Html.class "sticky-headers-table__th" ] 66 | [ Placeholders.Rectangle.view rectangle ] 67 | ) 68 | 69 | 70 | trView : Rectangle -> Int -> ( String, Html msg ) 71 | trView rectangle index = 72 | ( "tr_" ++ String.fromInt index 73 | , Html.tr 74 | [] 75 | [ Html.td 76 | [ Html.class "sticky-headers-table__td" ] 77 | [ Placeholders.Rectangle.view rectangle ] 78 | , Html.td 79 | [ Html.class "sticky-headers-table__td" ] 80 | [ Placeholders.Rectangle.view rectangle ] 81 | , Html.td 82 | [ Html.class "sticky-headers-table__td" ] 83 | [ Placeholders.Rectangle.view rectangle ] 84 | , Html.td 85 | [ Html.class "sticky-headers-table__td" ] 86 | [ Placeholders.Rectangle.view rectangle ] 87 | ] 88 | ) 89 | 90 | 91 | 92 | -- STYLES 93 | 94 | 95 | css : List Css.Style 96 | css = 97 | [ Css.displayFlex 98 | , Css.flexDirection Css.column 99 | , Css.alignItems Css.center 100 | , Css.justifyContent Css.center 101 | , Css.width <| Css.pct 100 102 | , Css.height <| Css.px 400 103 | , Css.Global.descendants 104 | [ Css.Global.selector ".sticky-headers-table" 105 | [ Css.width <| Css.pct 80 106 | , Css.height <| Css.pct 80 107 | , Css.border3 (Css.px 1) Css.solid Colors.greyLight 108 | , Css.overflow Css.auto 109 | ] 110 | , Css.Global.selector ".sticky-headers-table__table" 111 | [ Css.position Css.relative 112 | , Css.width <| Css.pct 100 113 | , Css.borderCollapse Css.collapse 114 | ] 115 | , Css.Global.selector ".sticky-headers-table__th" 116 | [ Css.padding <| Css.rem 1 117 | , Css.backgroundColor Colors.greyLighter 118 | , Css.position Css.sticky 119 | , Css.top Css.zero 120 | , Css.zIndex <| Css.int 9999 121 | ] 122 | , Css.Global.selector ".sticky-headers-table__td" 123 | [ Css.padding <| Css.rem 1 124 | , Css.borderTop3 (Css.px 1) Css.solid Colors.greyLight 125 | ] 126 | ] 127 | ] 128 | -------------------------------------------------------------------------------- /src/Components/Misc/Timeline.elm: -------------------------------------------------------------------------------- 1 | module Components.Misc.Timeline exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Html.Styled.Keyed as KHtml 12 | import Placeholders.Block exposing (Block) 13 | import Placeholders.Circle exposing (Circle) 14 | import Placeholders.Rectangle exposing (Rectangle) 15 | import Styles.Colors as Colors 16 | 17 | 18 | 19 | -- MODEL 20 | 21 | 22 | type alias Model = 23 | { block : Block 24 | , circle : Circle 25 | , rectangle : Rectangle 26 | } 27 | 28 | 29 | init : Model 30 | init = 31 | { block = 32 | Placeholders.Block.default 33 | |> Placeholders.Block.withBackgroundColor Colors.grey 34 | |> Placeholders.Block.withItems [ 1, 2, 3, 2, 3, 2, 4, 2, 5 ] 35 | , circle = 36 | Placeholders.Circle.default 37 | |> Placeholders.Circle.withSize (Css.px 32) 38 | |> Placeholders.Circle.withBackgroundColor Colors.grey 39 | , rectangle = 40 | Placeholders.Rectangle.default 41 | |> Placeholders.Rectangle.withHeight (Css.px 8) 42 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 43 | |> Placeholders.Rectangle.withWidth (Css.pct 80) 44 | } 45 | 46 | 47 | 48 | -- VIEW 49 | 50 | 51 | view : Model -> Html msg 52 | view { block, circle, rectangle } = 53 | Html.div 54 | [ Html.css css ] 55 | [ Html.div 56 | [ Html.class "timeline" ] 57 | [ Html.div 58 | [ Html.class "timeline__vertical-line" ] 59 | [] 60 | , KHtml.node "div" 61 | [] 62 | [ ( "item-1" 63 | , Html.div 64 | [ Html.class "timeline__item" ] 65 | [ Html.header 66 | [ Html.class "timeline__header" ] 67 | [ Placeholders.Circle.view circle 68 | , Placeholders.Rectangle.view rectangle 69 | ] 70 | , Html.div 71 | [ Html.class "timeline__content" ] 72 | [ Placeholders.Block.view block ] 73 | ] 74 | ) 75 | , ( "item-2" 76 | , Html.div 77 | [ Html.class "timeline__item" ] 78 | [ Html.header 79 | [ Html.class "timeline__header" ] 80 | [ Placeholders.Circle.view circle 81 | , Placeholders.Rectangle.view rectangle 82 | ] 83 | , Html.div 84 | [ Html.class "timeline__content" ] 85 | [ Placeholders.Block.view block ] 86 | ] 87 | ) 88 | , ( "item-3" 89 | , Html.div 90 | [ Html.class "timeline__item" ] 91 | [ Html.header 92 | [ Html.class "timeline__header" ] 93 | [ Placeholders.Circle.view circle 94 | , Placeholders.Rectangle.view rectangle 95 | ] 96 | , Html.div 97 | [ Html.class "timeline__content" ] 98 | [ Placeholders.Block.view block ] 99 | ] 100 | ) 101 | ] 102 | ] 103 | ] 104 | 105 | 106 | 107 | -- STYLES 108 | 109 | 110 | css : List Css.Style 111 | css = 112 | [ Css.displayFlex 113 | , Css.flexDirection Css.column 114 | , Css.alignItems Css.center 115 | , Css.justifyContent Css.center 116 | , Css.width <| Css.pct 100 117 | , Css.height <| Css.px 400 118 | , Css.Global.descendants 119 | [ Css.Global.selector ".timeline" 120 | [ Css.position Css.relative 121 | , Css.width <| Css.pct 60 122 | ] 123 | , Css.Global.selector ".timeline__vertical-line" 124 | [ Css.borderRight3 (Css.px 2) Css.solid Colors.grey 125 | , Css.position Css.absolute 126 | , Css.top Css.zero 127 | , Css.left <| Css.px 16 128 | , Css.height <| Css.pct 100 129 | ] 130 | , Css.Global.selector ".timeline__item:not(:last-of-type)" 131 | [ Css.marginBottom <| Css.rem 1 ] 132 | , Css.Global.selector ".timeline__header" 133 | [ Css.displayFlex 134 | , Css.alignItems Css.center 135 | , Css.marginBottom <| Css.rem 0.5 136 | , Css.Global.children 137 | [ Css.Global.selector ".placeholder-rectangle" 138 | [ Css.marginLeft <| Css.px 16 139 | , Css.flex <| Css.int 1 140 | ] 141 | ] 142 | ] 143 | , Css.Global.selector ".timeline__content" 144 | [ Css.marginLeft <| Css.px 48 ] 145 | ] 146 | ] 147 | -------------------------------------------------------------------------------- /src/Components/Navigation/Breadcrumb.elm: -------------------------------------------------------------------------------- 1 | module Components.Navigation.Breadcrumb exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Rectangle exposing (Rectangle) 12 | import Styles.Colors as Colors 13 | 14 | 15 | 16 | -- MODEL 17 | 18 | 19 | type alias Model = 20 | { rectangle : Rectangle } 21 | 22 | 23 | init : Model 24 | init = 25 | { rectangle = 26 | Placeholders.Rectangle.default 27 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 28 | |> Placeholders.Rectangle.withHeight (Css.px 4) 29 | } 30 | 31 | 32 | 33 | -- VIEW 34 | 35 | 36 | view : Model -> Html msg 37 | view { rectangle } = 38 | Html.div 39 | [ Html.css css ] 40 | [ Html.div 41 | [ Html.class "breadcrumb" ] 42 | [ Html.a 43 | [ Html.class "breadcrumb__item" ] 44 | [ Placeholders.Rectangle.view rectangle ] 45 | , Html.a 46 | [ Html.class "breadcrumb__item" ] 47 | [ Placeholders.Rectangle.view rectangle ] 48 | , Html.a 49 | [ Html.class "breadcrumb__item" ] 50 | [ Placeholders.Rectangle.view rectangle ] 51 | ] 52 | ] 53 | 54 | 55 | 56 | -- STYLES 57 | 58 | 59 | css : List Css.Style 60 | css = 61 | [ Css.width <| Css.pct 100 62 | , Css.height <| Css.px 400 63 | , Css.displayFlex 64 | , Css.alignItems Css.center 65 | , Css.justifyContent Css.center 66 | , Css.Global.descendants 67 | [ Css.Global.selector ".breadcrumb" 68 | [ Css.displayFlex 69 | , Css.alignItems Css.center 70 | , Css.justifyContent Css.center 71 | ] 72 | , Css.Global.selector ".breadcrumb__item" 73 | [ Css.displayFlex 74 | , Css.alignItems Css.center 75 | , Css.minWidth <| Css.rem 6 76 | ] 77 | , Css.Global.selector ".breadcrumb__item:not(:last-of-type)" 78 | [ Css.after 79 | [ Css.property "content" "\"/\"" 80 | , Css.margin2 Css.zero (Css.em 0.5) 81 | ] 82 | ] 83 | ] 84 | ] 85 | 86 | -------------------------------------------------------------------------------- /src/Components/Navigation/Drawer.elm: -------------------------------------------------------------------------------- 1 | module Components.Navigation.Drawer exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Block exposing (Block) 12 | import Styles.Breakpoints as Breakpoints 13 | import Styles.Colors as Colors 14 | 15 | 16 | 17 | -- MODEL 18 | 19 | 20 | type alias Model = 21 | { block : Block } 22 | 23 | 24 | init : Model 25 | init = 26 | { block = 27 | Placeholders.Block.default 28 | |> Placeholders.Block.withBackgroundColor Colors.grey 29 | |> Placeholders.Block.withItems [ 1, 2, 3, 2, 3, 4, 5, 2, 1, 2, 4, 2, 5, 3 ] 30 | } 31 | 32 | 33 | 34 | -- VIEW 35 | 36 | 37 | view : Model -> Html msg 38 | view { block } = 39 | Html.div 40 | [ Html.css css ] 41 | [ Html.div 42 | [ Html.class "drawer__overlay" ] 43 | [] 44 | , Html.div 45 | [ Html.class "drawer__content" ] 46 | [ Placeholders.Block.view block ] 47 | ] 48 | 49 | 50 | 51 | -- STYLES 52 | 53 | 54 | css : List Css.Style 55 | css = 56 | [ Css.width <| Css.pct 100 57 | , Css.height <| Css.px 400 58 | , Css.position Css.relative 59 | , Css.Global.descendants 60 | [ Css.Global.selector ".drawer__overlay" 61 | [ Css.height <| Css.pct 100 62 | , Css.position Css.absolute 63 | , Css.left Css.zero 64 | , Css.top Css.zero 65 | , Css.backgroundColor Colors.black 66 | , Css.opacity <| Css.num 0.8 67 | , Css.width <| Css.pct 100 68 | ] 69 | , Css.Global.selector ".drawer__content" 70 | [ Css.height <| Css.pct 100 71 | , Css.position Css.absolute 72 | , Css.backgroundColor Colors.white 73 | , Css.left Css.zero 74 | , Css.top Css.zero 75 | , Css.padding <| Css.rem 1 76 | , Css.Global.descendants 77 | [ Css.Global.selector ".placeholder-block" 78 | [ Css.marginBottom <| Css.rem 1 79 | , Breakpoints.small 80 | [ Css.marginBottom <| Css.rem 0.5 ] 81 | ] 82 | ] 83 | , Breakpoints.small 84 | [ Css.width <| Css.pct 25 ] 85 | ] 86 | ] 87 | ] 88 | -------------------------------------------------------------------------------- /src/Components/Navigation/Pagination.elm: -------------------------------------------------------------------------------- 1 | module Components.Navigation.Pagination exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Circle exposing (Circle) 12 | import Placeholders.Rectangle exposing (Rectangle) 13 | import Styles.Colors as Colors 14 | 15 | 16 | 17 | -- MODEL 18 | 19 | 20 | type alias Model = 21 | { rectangle : Rectangle 22 | , circle : Circle 23 | } 24 | 25 | 26 | init : Model 27 | init = 28 | { rectangle = 29 | Placeholders.Rectangle.default 30 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 31 | |> Placeholders.Rectangle.withHeight (Css.px 12) 32 | , circle = 33 | Placeholders.Circle.default 34 | |> Placeholders.Circle.withBackgroundColor Colors.grey 35 | |> Placeholders.Circle.withSize (Css.px 12) 36 | } 37 | 38 | 39 | 40 | -- VIEW 41 | 42 | 43 | view : Model -> Html msg 44 | view { circle, rectangle } = 45 | Html.div 46 | [ Html.css css ] 47 | [ Html.div 48 | [ Html.class "pagination" ] 49 | [ Html.div 50 | [ Html.class "pagination__item" ] 51 | [ Placeholders.Rectangle.view rectangle ] 52 | , Html.div 53 | [ Html.class "pagination__item" ] 54 | [ Placeholders.Circle.view circle ] 55 | , Html.div 56 | [ Html.class "pagination__item" ] 57 | [ Placeholders.Circle.view circle ] 58 | , Html.div 59 | [ Html.class "pagination__item" ] 60 | [ Placeholders.Circle.view circle ] 61 | , Html.div 62 | [ Html.class "pagination__item" ] 63 | [ Placeholders.Circle.view circle ] 64 | , Html.div 65 | [ Html.class "pagination__item" ] 66 | [ Placeholders.Circle.view circle ] 67 | , Html.div 68 | [ Html.class "pagination__item" ] 69 | [ Placeholders.Rectangle.view rectangle ] 70 | ] 71 | ] 72 | 73 | 74 | 75 | -- STYLES 76 | 77 | 78 | css : List Css.Style 79 | css = 80 | [ Css.width <| Css.pct 100 81 | , Css.height <| Css.px 400 82 | , Css.displayFlex 83 | , Css.alignItems Css.center 84 | , Css.justifyContent Css.center 85 | , Css.Global.descendants 86 | [ Css.Global.selector ".pagination" 87 | [ Css.displayFlex 88 | , Css.alignItems Css.center 89 | , Css.justifyContent Css.center 90 | , Css.border3 (Css.px 1) Css.solid Colors.grey 91 | , Css.borderRadius <| Css.px 4 92 | , Css.Global.descendants 93 | [ Css.Global.selector ".pagination__item" 94 | [ Css.displayFlex 95 | , Css.alignItems Css.center 96 | , Css.justifyContent Css.center 97 | , Css.borderRight3 (Css.px 1) Css.solid Colors.grey 98 | , Css.padding <| Css.rem 0.5 99 | , Css.lastOfType 100 | [ Css.borderRight <| Css.px 0 ] 101 | ] 102 | , Css.Global.selector ".placeholder-rectangle" 103 | [ Css.width <| Css.rem 5 ] 104 | ] 105 | ] 106 | ] 107 | ] 108 | -------------------------------------------------------------------------------- /src/Components/Navigation/Split.elm: -------------------------------------------------------------------------------- 1 | module Components.Navigation.Split exposing 2 | ( Model 3 | , init 4 | , view 5 | ) 6 | 7 | import Css 8 | import Css.Global 9 | import Html.Styled as Html exposing (Html) 10 | import Html.Styled.Attributes as Html 11 | import Placeholders.Rectangle exposing (Rectangle) 12 | import Styles.Breakpoints as Breakpoints 13 | import Styles.Colors as Colors 14 | 15 | 16 | 17 | -- MODEL 18 | 19 | 20 | type alias Model = 21 | { rectangle : Rectangle } 22 | 23 | 24 | init : Model 25 | init = 26 | { rectangle = 27 | Placeholders.Rectangle.default 28 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 29 | |> Placeholders.Rectangle.withHeight (Css.px 12) 30 | } 31 | 32 | 33 | 34 | -- VIEW 35 | 36 | 37 | view : Model -> Html msg 38 | view { rectangle } = 39 | Html.div 40 | [ Html.css css ] 41 | [ Html.ul 42 | [ Html.class "navigation" ] 43 | [ Html.li 44 | [ Html.class "navigation__item" ] 45 | [ Placeholders.Rectangle.view rectangle ] 46 | , Html.li 47 | [ Html.class "navigation__item" ] 48 | [ Placeholders.Rectangle.view rectangle ] 49 | , Html.li 50 | [ Html.class "navigation__item" ] 51 | [ Placeholders.Rectangle.view rectangle ] 52 | , Html.li 53 | [ Html.class "navigation__item" ] 54 | [ Placeholders.Rectangle.view rectangle ] 55 | ] 56 | ] 57 | 58 | 59 | 60 | -- STYLES 61 | 62 | 63 | css : List Css.Style 64 | css = 65 | [ Css.width <| Css.pct 100 66 | , Css.height <| Css.px 400 67 | , Css.displayFlex 68 | , Css.alignItems Css.center 69 | , Css.justifyContent Css.center 70 | , Css.Global.descendants 71 | [ Css.Global.selector ".navigation" 72 | [ Css.displayFlex 73 | , Css.alignItems Css.center 74 | , Css.listStyle Css.none 75 | , Css.margin Css.zero 76 | , Css.border3 (Css.px 1) Css.solid Colors.grey 77 | , Css.borderRadius <| Css.px 4 78 | , Css.width <| Css.pct 80 79 | , Css.Global.descendants 80 | [ Css.Global.selector ".navigation__item" 81 | [ Css.padding <| Css.rem 0.7 82 | , Css.lastOfType 83 | [ Css.marginLeft Css.auto ] 84 | , Breakpoints.small 85 | [ Css.padding <| Css.rem 0.3 ] 86 | ] 87 | , Css.Global.selector ".placeholder-rectangle" 88 | [ Css.width <| Css.rem 5 89 | , Breakpoints.small 90 | [ Css.width <| Css.rem 3 ] 91 | ] 92 | ] 93 | ] 94 | ] 95 | ] 96 | -------------------------------------------------------------------------------- /src/Components/Navigation/Tab.elm: -------------------------------------------------------------------------------- 1 | module Components.Navigation.Tab exposing 2 | ( Model 3 | , Msg 4 | , init 5 | , update 6 | , view 7 | ) 8 | 9 | import Css 10 | import Css.Global 11 | import Html.Styled as Html exposing (Html) 12 | import Html.Styled.Attributes as Html 13 | import Html.Styled.Events as Html 14 | import Html.Styled.Keyed 15 | import List 16 | import Placeholders.Rectangle exposing (Rectangle) 17 | import Styles.Breakpoints as Breakpoints 18 | import Styles.Colors as Colors 19 | 20 | 21 | 22 | -- MODEL 23 | 24 | 25 | type TabItem 26 | = FirstItem 27 | | SecondItem 28 | | ThirdItem 29 | 30 | 31 | type alias Model = 32 | { rectangle : Rectangle 33 | , selectedItem : TabItem 34 | } 35 | 36 | 37 | init : Model 38 | init = 39 | { rectangle = 40 | Placeholders.Rectangle.default 41 | |> Placeholders.Rectangle.withBackgroundColor Colors.grey 42 | |> Placeholders.Rectangle.withHeight (Css.px 4) 43 | , selectedItem = FirstItem 44 | } 45 | 46 | 47 | 48 | -- UPDATE 49 | 50 | 51 | type Msg 52 | = OnTabClick TabItem 53 | 54 | 55 | update : Msg -> Model -> Model 56 | update msg model = 57 | case msg of 58 | OnTabClick tabItem -> 59 | { model | selectedItem = tabItem } 60 | 61 | 62 | 63 | -- VIEW 64 | 65 | 66 | view : Model -> Html Msg 67 | view { rectangle, selectedItem } = 68 | Html.div 69 | [ Html.css css ] 70 | [ [ FirstItem, SecondItem, ThirdItem ] 71 | |> List.indexedMap (itemView rectangle selectedItem) 72 | |> Html.Styled.Keyed.node "div" 73 | [ Html.class "tabs" ] 74 | ] 75 | 76 | 77 | itemView : Rectangle -> TabItem -> Int -> TabItem -> ( String, Html Msg ) 78 | itemView rectangle selectedItem index item = 79 | ( "tab_" ++ String.fromInt index 80 | , Html.div 81 | [ Html.classList 82 | [ ( "tabs__item", True ) 83 | , ( "tabs__item--active", item == selectedItem ) 84 | ] 85 | , Html.onClick <| OnTabClick item 86 | ] 87 | [ Placeholders.Rectangle.view rectangle ] 88 | ) 89 | 90 | 91 | 92 | -- STYLES 93 | 94 | 95 | css : List Css.Style 96 | css = 97 | [ Css.width <| Css.pct 100 98 | , Css.height <| Css.px 400 99 | , Css.displayFlex 100 | , Css.alignItems Css.center 101 | , Css.justifyContent Css.center 102 | , Css.Global.descendants 103 | [ Css.Global.selector ".tabs" 104 | [ Css.displayFlex 105 | , Css.alignItems Css.center 106 | , Css.justifyContent Css.center 107 | ] 108 | , Css.Global.selector ".tabs__item" 109 | [ Css.borderBottom3 (Css.px 1) Css.solid Colors.grey 110 | , Css.padding <| Css.rem 1 111 | , Css.width <| Css.rem 10 112 | , Css.cursor Css.pointer 113 | , Breakpoints.small 114 | [ Css.width <| Css.rem 6 ] 115 | ] 116 | , Css.Global.selector ".tabs__item--active" 117 | [ Css.border3 (Css.px 1) Css.solid Colors.grey 118 | , Css.borderBottomColor Css.transparent 119 | , Css.borderTopLeftRadius <| Css.px 2 120 | , Css.borderTopRightRadius <| Css.px 2 121 | , Css.cursor Css.default 122 | ] 123 | ] 124 | ] 125 | -------------------------------------------------------------------------------- /src/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (main) 2 | 3 | import Browser 4 | import Browser.Navigation as Nav exposing (Key) 5 | import Effect 6 | import Gen.Model 7 | import Gen.Pages as Pages 8 | import Gen.Route as Route 9 | import Request 10 | import Shared 11 | import Url exposing (Url) 12 | import View 13 | 14 | 15 | main : Program Shared.Flags Model Msg 16 | main = 17 | Browser.application 18 | { init = init 19 | , update = update 20 | , view = view 21 | , subscriptions = subscriptions 22 | , onUrlChange = ChangedUrl 23 | , onUrlRequest = ClickedLink 24 | } 25 | 26 | 27 | 28 | -- INIT 29 | 30 | 31 | type alias Model = 32 | { url : Url 33 | , key : Key 34 | , shared : Shared.Model 35 | , page : Pages.Model 36 | , showSidebar : Bool 37 | } 38 | 39 | 40 | init : Shared.Flags -> Url -> Key -> ( Model, Cmd Msg ) 41 | init flags url key = 42 | let 43 | ( shared, sharedCmd ) = 44 | Shared.init (Request.create () url key) flags 45 | 46 | ( page, effect ) = 47 | Pages.init (Route.fromUrl url) shared url key 48 | in 49 | ( Model url key shared page False 50 | , Cmd.batch 51 | [ Cmd.map Shared sharedCmd 52 | , Effect.toCmd ( Shared, Page ) effect 53 | ] 54 | ) 55 | 56 | 57 | 58 | -- UPDATE 59 | 60 | 61 | type Msg 62 | = ChangedUrl Url 63 | | ClickedLink Browser.UrlRequest 64 | | Shared Shared.Msg 65 | | Page Pages.Msg 66 | | ShowSidebar 67 | 68 | 69 | update : Msg -> Model -> ( Model, Cmd Msg ) 70 | update msg ({ shared } as model) = 71 | case msg of 72 | ClickedLink (Browser.Internal url) -> 73 | ( model 74 | , Nav.pushUrl model.key (Url.toString url) 75 | ) 76 | 77 | ClickedLink (Browser.External url) -> 78 | ( model 79 | , Nav.load url 80 | ) 81 | 82 | ChangedUrl url -> 83 | if url.path /= model.url.path then 84 | let 85 | route = 86 | Route.fromUrl url 87 | 88 | ( page, effect ) = 89 | Pages.init route model.shared url model.key 90 | in 91 | ( { model 92 | | url = url 93 | , page = page 94 | , showSidebar = False 95 | } 96 | , Effect.toCmd ( Shared, Page ) effect 97 | ) 98 | 99 | else 100 | ( { model 101 | | url = url 102 | , showSidebar = False 103 | } 104 | , Cmd.none 105 | ) 106 | 107 | Shared sharedMsg -> 108 | let 109 | ( newShared, sharedCmd ) = 110 | Shared.update (Request.create () model.url model.key) sharedMsg shared 111 | 112 | ( page, effect ) = 113 | Pages.init (Route.fromUrl model.url) newShared model.url model.key 114 | in 115 | if page == Gen.Model.Redirecting_ then 116 | ( { model | shared = newShared, page = page } 117 | , Cmd.batch 118 | [ Cmd.map Shared sharedCmd 119 | , Effect.toCmd ( Shared, Page ) effect 120 | ] 121 | ) 122 | 123 | else 124 | ( { model | shared = shared } 125 | , Cmd.map Shared sharedCmd 126 | ) 127 | 128 | Page pageMsg -> 129 | let 130 | ( page, effect ) = 131 | Pages.update pageMsg model.page model.shared model.url model.key 132 | in 133 | ( { model | page = page } 134 | , Effect.toCmd ( Shared, Page ) effect 135 | ) 136 | 137 | ShowSidebar -> 138 | ( { model | showSidebar = not model.showSidebar }, Cmd.none ) 139 | 140 | 141 | 142 | -- VIEW 143 | 144 | 145 | view : Model -> Browser.Document Msg 146 | view model = 147 | Pages.view model.page model.shared model.url model.key 148 | |> View.map Page 149 | |> View.toBrowserDocument 150 | { isHomeRoute = Route.fromUrl model.url == Route.Home_ 151 | , showSidebar = model.showSidebar 152 | , onShowSidebarClick = ShowSidebar 153 | , url = model.url 154 | } 155 | 156 | 157 | 158 | -- SUBSCRIPTIONS 159 | 160 | 161 | subscriptions : Model -> Sub Msg 162 | subscriptions model = 163 | Sub.batch 164 | [ Pages.subscriptions model.page model.shared model.url model.key |> Sub.map Page 165 | , Shared.subscriptions (Request.create () model.url model.key) model.shared |> Sub.map Shared 166 | ] 167 | -------------------------------------------------------------------------------- /src/Pages/Feedback.elm: -------------------------------------------------------------------------------- 1 | module Pages.Feedback exposing (view) 2 | 3 | import Components 4 | import Html.Styled as Html 5 | import Html.Styled.Attributes as Html 6 | import Html.Styled.Keyed 7 | import View exposing (View) 8 | 9 | 10 | view : View msg 11 | view = 12 | { title = "Feedback" 13 | , body = 14 | [ Html.header 15 | [ Html.class "header" ] 16 | [ Html.h1 17 | [] 18 | [ Html.text "Feedback" ] 19 | ] 20 | , Components.feedbackNavItems 21 | |> List.map Components.navItem 22 | |> Html.Styled.Keyed.ul [ Html.class "list" ] 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/Pages/Feedback/Loader.elm: -------------------------------------------------------------------------------- 1 | module Pages.Feedback.Loader exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Feedback.Loader as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Css.Animations 40 | import Html.Styled as Html exposing (Html) 41 | import Html.Styled.Attributes as Html 42 | 43 | 44 | load : Css.Animations.Keyframes {} 45 | load = 46 | Css.Animations.keyframes 47 | [ ( 0, [ Css.Animations.transform [ Css.rotate <| Css.deg 0 ] ] ) 48 | , ( 100, [ Css.Animations.transform [ Css.rotate <| Css.deg 360 ] ] ) 49 | ] 50 | 51 | 52 | loader : Html msg 53 | loader = 54 | Html.div 55 | [ Html.css 56 | [ Css.borderRadius <| Css.pct 50 57 | , Css.height <| Css.rem 5 58 | , Css.width <| Css.rem 5 59 | , Css.position Css.relative 60 | , Css.border3 (Css.rem 0.5) Css.solid (Css.hex "efefef") 61 | , Css.borderLeft3 (Css.rem 0.5) Css.solid (Css.hex "eeeeee") 62 | , Css.transform <| Css.translateZ Css.zero 63 | , Css.animationName load 64 | , Css.animationDuration <| Css.sec 1.1 65 | , Css.property "animation-timing-function" "linear" 66 | , Css.property "animation-iteration-count" "infinite" 67 | ] 68 | ] 69 | [] 70 | """ 71 | } 72 | 73 | 74 | update : Msg -> Model -> Model 75 | update _ model = 76 | model 77 | 78 | 79 | view : Model -> View Msg 80 | view { code, component } = 81 | { title = "Loader | Feedback" 82 | , body = 83 | { header = "Loader feedback" 84 | , content = PageComponent.view component 85 | , code = code 86 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Feedback/Loader.elm" 87 | } 88 | |> Components.pageBody 89 | } 90 | -------------------------------------------------------------------------------- /src/Pages/Feedback/ProgressBar.elm: -------------------------------------------------------------------------------- 1 | module Pages.Feedback.ProgressBar exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Feedback.ProgressBar as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import Time 13 | import View exposing (View) 14 | 15 | 16 | page : Shared.Model -> Request -> Page.With Model Msg 17 | page _ _ = 18 | Page.element 19 | { init = init 20 | , update = update 21 | , view = view 22 | , subscriptions = subscriptions 23 | } 24 | 25 | 26 | type alias Model = 27 | { code : String 28 | , component : PageComponent.Model 29 | } 30 | 31 | 32 | type Msg 33 | = Tick Time.Posix 34 | 35 | 36 | init : ( Model, Cmd Msg ) 37 | init = 38 | ( { component = PageComponent.init 0 39 | , code = """ 40 | import Css 41 | import Html.Styled as Html exposing (Html) 42 | import Html.Styled.Attributes as Html 43 | 44 | 45 | progressBar : Html msg 46 | progressBar = 47 | Html.div 48 | [ Html.css 49 | [ Css.backgroundColor Colors.greyLighter 50 | , Css.borderRadius <| Css.px 9999 51 | ] 52 | ] 53 | [ Html.div 54 | [ Html.css 55 | [ Css.displayFlex 56 | , Css.alignItems Css.center 57 | , Css.justifyContent Css.center 58 | , Css.backgroundColor <| Css.hex "8fbcbb" 59 | , Css.color Colors.white 60 | , Css.borderRadius <| Css.px 9999 61 | , Css.overflow Css.hidden 62 | , Css.width <| Css.pct 50 63 | ] 64 | ] 65 | [ Html.text "50%" ] 66 | ] 67 | """ 68 | } 69 | , Cmd.none 70 | ) 71 | 72 | 73 | update : Msg -> Model -> ( Model, Cmd Msg ) 74 | update msg ({ component } as model) = 75 | let 76 | percentage = 77 | if component.percentage < 100 then 78 | component.percentage + 1 79 | 80 | else 81 | 0 82 | in 83 | ( { model | component = { component | percentage = percentage } }, Cmd.none ) 84 | 85 | 86 | subscriptions : Model -> Sub Msg 87 | subscriptions _ = 88 | Time.every 100 Tick 89 | 90 | 91 | view : Model -> View Msg 92 | view { code, component } = 93 | { title = "Progress bar | Feedback" 94 | , body = 95 | { header = "Progress bar feedback" 96 | , content = PageComponent.view component 97 | , code = code 98 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Feedback/ProgressBar.elm" 99 | } 100 | |> Components.pageBody 101 | } 102 | -------------------------------------------------------------------------------- /src/Pages/Feedback/RadialProgressBar.elm: -------------------------------------------------------------------------------- 1 | module Pages.Feedback.RadialProgressBar exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Feedback.RadialProgressBar as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import Time 13 | import View exposing (View) 14 | 15 | 16 | page : Shared.Model -> Request -> Page.With Model Msg 17 | page _ _ = 18 | Page.element 19 | { init = init 20 | , update = update 21 | , view = view 22 | , subscriptions = subscriptions 23 | } 24 | 25 | 26 | type alias Model = 27 | { code : String 28 | , component : PageComponent.Model 29 | } 30 | 31 | 32 | type Msg 33 | = Tick Time.Posix 34 | 35 | 36 | init : ( Model, Cmd Msg ) 37 | init = 38 | ( { component = PageComponent.init 0 39 | , code = """ 40 | import Css 41 | import Html.Styled as Html exposing (Html) 42 | import Html.Styled.Attributes as Html 43 | 44 | 45 | progressBar : Int -> Html msg 46 | progressBar percentage = 47 | Html.div 48 | [ Html.css 49 | [ Css.position Css.relative ] 50 | ] 51 | [ Html.div 52 | [ Html.css 53 | [ Css.displayFlex 54 | , Css.alignItems Css.center 55 | , Css.justifyContent Css.center 56 | , Css.border3 (Css.px 12) Css.solid (Css.hex "efefef") 57 | , Css.borderRadius <| Css.px 9999 58 | , Css.height <| Css.px 128 59 | , Css.width <| Css.px 128 60 | ] 61 | ] 62 | [ Html.text <| String.fromInt percentage ++ "%" ] 63 | , Html.div 64 | [ Html.classList [ ( "progress-bar__inner--ge-50", percentage >= 50 ) ] 65 | , Html.css 66 | [ Css.position Css.absolute 67 | , Css.top Css.zero 68 | , Css.left Css.zero 69 | , Css.height <| Css.pct 100 70 | , Css.width <| Css.pct 100 71 | , Css.property "clip" "rect(0px, 128px, 128px, 64px)" 72 | , Css.Global.withClass "progress-bar__inner--ge-50" 73 | [ Css.property "clip" "rect(auto, auto, auto, auto)" ] 74 | ] 75 | ] 76 | [ Html.div 77 | [ Html.css 78 | [ Css.position Css.absolute 79 | , Css.height <| Css.pct 100 80 | , Css.width <| Css.pct 100 81 | , Css.border3 (Css.px 12) Css.solid (Css.hex "8fbcbb") 82 | , Css.borderRadius <| Css.px 9999 83 | , Css.property "clip" "rect(0px, 64px, 128px, 0px)" 84 | ] 85 | , Html.style "transform" <| "rotate(" ++ String.fromInt (percentage * 360 // 100) ++ "deg)" 86 | ] 87 | [] 88 | , Html.div 89 | [ Html.classList [ ( "progress-bar__inner__2--ge-50", percentage >= 50 ) ] 90 | , Html.css 91 | [ Css.position Css.absolute 92 | , Css.height <| Css.pct 100 93 | , Css.width <| Css.pct 100 94 | , Css.border3 (Css.px 12) Css.solid ( Css.hex "8fbcbb" ) 95 | , Css.borderRadius <| Css.px 9999 96 | , Css.property "clip" "rect(0px, 64px, 128px, 0px)" 97 | , Css.transform <| Css.rotate <| Css.deg 0 98 | , Css.Global.withClass "progress-bar__inner__2--ge-50" 99 | [ Css.transform <| Css.rotate <| Css.deg 180 ] 100 | ] 101 | ] 102 | [] 103 | ] 104 | ] 105 | """ 106 | } 107 | , Cmd.none 108 | ) 109 | 110 | 111 | update : Msg -> Model -> ( Model, Cmd Msg ) 112 | update msg ({ component } as model) = 113 | let 114 | percentage = 115 | if component.percentage < 100 then 116 | component.percentage + 1 117 | 118 | else 119 | 0 120 | in 121 | ( { model | component = { component | percentage = percentage } }, Cmd.none ) 122 | 123 | 124 | subscriptions : Model -> Sub Msg 125 | subscriptions _ = 126 | Time.every 100 Tick 127 | 128 | 129 | view : Model -> View Msg 130 | view { code, component } = 131 | { title = "Radial progress bar | Feedback" 132 | , body = 133 | { header = "Radial progress bar feedback" 134 | , content = PageComponent.view component 135 | , code = code 136 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Feedback/RadialProgressBar.elm" 137 | } 138 | |> Components.pageBody 139 | } 140 | -------------------------------------------------------------------------------- /src/Pages/Feedback/Tooltip.elm: -------------------------------------------------------------------------------- 1 | module Pages.Feedback.Tooltip exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Feedback.Tooltip as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Css.Global 40 | import Css.Transitions 41 | import Html.Styled as Html exposing (Html) 42 | import Html.Styled.Attributes as Html 43 | 44 | 45 | tooltip : Html msg 46 | tooltip = 47 | Html.div 48 | [ Html.css 49 | [ Css.position Css.relative 50 | , Css.hover 51 | [ Css.Global.descendants 52 | [ Css.Global.selector ".tooltip__content" 53 | [ Css.opacity <| Css.num 1 54 | , Css.pointerEventsAll 55 | ] 56 | ] 57 | ] 58 | ] 59 | ] 60 | [ Html.div 61 | [ Html.class "tooltip__content" 62 | , Html.css 63 | [ Css.opacity Css.zero 64 | , Css.position Css.absolute 65 | , Css.backgroundColor <| Css.hex "333333" 66 | , Css.width <| Css.px 200 67 | , Css.color Colors.white 68 | , Css.bottom <| Css.pct 100 69 | , Css.left <| Css.pct 50 70 | , Css.transform <| Css.translate2 (Css.pct -50) (Css.px -8) 71 | , Css.Transitions.transition 72 | [ Css.Transitions.opacity 200 ] 73 | , Css.after 74 | [ Css.property "content" " " 75 | , Css.position Css.absolute 76 | , Css.border3 (Css.px 8) Css.solid Css.transparent 77 | , Css.borderTopColor <| Css.hex "333333" 78 | , Css.bottom Css.zero 79 | , Css.left <| Css.pct 50 80 | , Css.transform <| Css.translate2 (Css.pct -50) (Css.px 16) 81 | , Css.height Css.zero 82 | , Css.width Css.zero 83 | , Css.Transitions.transition 84 | [ Css.Transitions.opacity 200 ] 85 | ] 86 | ] 87 | ] 88 | [ Placeholders.Block.view block ] 89 | , Html.div 90 | [ Html.class "tooltip__trigger" ] 91 | [ Placeholders.Rectangle.view rectangle 92 | ] 93 | ] 94 | """ 95 | } 96 | 97 | 98 | update : Msg -> Model -> Model 99 | update _ model = 100 | model 101 | 102 | 103 | view : Model -> View Msg 104 | view { code, component } = 105 | { title = "Tooltip | Feedback" 106 | , body = 107 | { header = "Tooltip feedback" 108 | , content = PageComponent.view component 109 | , code = code 110 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Feedback/Tooltip.elm" 111 | } 112 | |> Components.pageBody 113 | } 114 | -------------------------------------------------------------------------------- /src/Pages/Home_.elm: -------------------------------------------------------------------------------- 1 | module Pages.Home_ exposing (view) 2 | 3 | import Components 4 | import Gen.Route as Route exposing (Route) 5 | import Html.Styled as Html exposing (Html) 6 | import Html.Styled.Attributes as Html 7 | import Html.Styled.Keyed 8 | import View exposing (View) 9 | 10 | 11 | view : View msg 12 | view = 13 | { title = "Home" 14 | , body = 15 | [ Html.header 16 | [ Html.class "top-header" ] 17 | [ Html.h1 18 | [] 19 | [ Html.text "elm-css patterns" ] 20 | , Html.p 21 | [ Html.class "hero" ] 22 | [ Html.text "Common CSS patterns done in " 23 | , Html.a 24 | [ Html.href "https://elm-lang.org/" 25 | , Html.target "_blank" 26 | , Html.class "cool" 27 | ] 28 | [ Html.text " elm" ] 29 | , Html.text " and " 30 | , Html.a 31 | [ Html.href "https://github.com/rtfeldman/elm-css" 32 | , Html.target "_blank" 33 | , Html.class "cool" 34 | ] 35 | [ Html.text " elm-css" ] 36 | , Html.text "." 37 | ] 38 | ] 39 | , Html.div 40 | [ Html.class "patterns" ] 41 | [ patternSection "Layout" Components.layoutNavItems 42 | , patternSection "Navigation" Components.navigationNavItems 43 | , patternSection "Input" Components.inputNavItems 44 | , patternSection "Feedback" Components.feedbackNavItems 45 | , patternSection "Misc" Components.miscNavItems 46 | ] 47 | ] 48 | } 49 | 50 | 51 | patternSection : String -> List ( Route, String ) -> Html msg 52 | patternSection title items = 53 | Html.div 54 | [ Html.class "patterns__section" ] 55 | [ Html.header 56 | [ Html.class "patterns__header" ] 57 | [ Html.h3 58 | [] 59 | [ Html.text title ] 60 | ] 61 | , items 62 | |> List.map navItem 63 | |> Html.Styled.Keyed.ul [ Html.class "list" ] 64 | ] 65 | 66 | 67 | navItem : ( Route, String ) -> ( String, Html msg ) 68 | navItem ( route, text ) = 69 | ( text 70 | , Html.li 71 | [] 72 | [ Html.a 73 | [ Html.href <| Route.toHref route ] 74 | [ Html.text text ] 75 | ] 76 | ) 77 | -------------------------------------------------------------------------------- /src/Pages/Input.elm: -------------------------------------------------------------------------------- 1 | module Pages.Input exposing (view) 2 | 3 | import Components 4 | import Html.Styled as Html 5 | import Html.Styled.Attributes as Html 6 | import Html.Styled.Keyed 7 | import View exposing (View) 8 | 9 | 10 | view : View msg 11 | view = 12 | { title = "Input" 13 | , body = 14 | [ Html.header 15 | [ Html.class "header" ] 16 | [ Html.h1 17 | [] 18 | [ Html.text "Input" ] 19 | ] 20 | , Components.inputNavItems 21 | |> List.map Components.navItem 22 | |> Html.Styled.Keyed.ul [ Html.class "list" ] 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/Pages/Input/CustomCheckbox.elm: -------------------------------------------------------------------------------- 1 | module Pages.Input.CustomCheckbox exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Input.CustomCheckbox as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Css.Global 40 | import Html.Styled as Html exposing (Html) 41 | import Html.Styled.Attributes as Html 42 | 43 | 44 | customCheckbox : Html msg 45 | customCheckbox = 46 | Html.label 47 | [ Html.for "myCustomCheckbox" 48 | , Html.css 49 | [ Css.displayFlex 50 | , Css.alignItems Css.center 51 | , Css.cursor Css.pointer 52 | ] 53 | ] 54 | [ Html.input 55 | [ Html.type_ "checkbox" 56 | , Html.id "myCustomCheckbox" 57 | , Html.css 58 | [ Css.display Css.none 59 | , Css.checked 60 | [ Css.Global.generalSiblings 61 | [ Css.Global.selector ".custom-checkbox__icon > .custom-checkbox__inner-icon" 62 | [ Css.backgroundColor <| Css.hex "88c0d0" ] 63 | ] 64 | ] 65 | ] 66 | ] 67 | [] 68 | , Html.div 69 | [ Html.class "custom-checkbox__icon" 70 | , Html.css 71 | [ Css.border3 (Css.px 1) Css.solid (Css.hex "EFEFEF") 72 | , Css.borderRadius <| Css.px 4 73 | , Css.marginRight <| Css.rem 0.4 74 | , Css.padding <| Css.px 2 75 | ] 76 | ] 77 | [ Html.div 78 | [ Html.class "custom-checkbox__inner-icon" 79 | , Html.css 80 | [ Css.borderRadius <| Css.px 4 81 | , Css.height <| Css.rem 0.8 82 | , Css.width <| Css.rem 0.8 83 | ] 84 | ] 85 | [] 86 | ] 87 | , Html.text "Some text" 88 | ] 89 | """ 90 | } 91 | 92 | 93 | update : Msg -> Model -> Model 94 | update _ model = 95 | model 96 | 97 | 98 | view : Model -> View Msg 99 | view { code, component } = 100 | { title = "Custom checkbox | Input" 101 | , body = 102 | { header = "Custom checkbox input" 103 | , content = PageComponent.view component 104 | , code = code 105 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Input/CustomCheckbox.elm" 106 | } 107 | |> Components.pageBody 108 | } 109 | -------------------------------------------------------------------------------- /src/Pages/Input/CustomRadio.elm: -------------------------------------------------------------------------------- 1 | module Pages.Input.CustomRadio exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Input.CustomRadio as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { component : PageComponent.Model 26 | , code : String 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Css.Global 40 | import Html.Styled as Html exposing (Html) 41 | import Html.Styled.Attributes as Html 42 | 43 | 44 | customRadio : Html msg 45 | customRadio = 46 | Html.label 47 | [ Html.for "myCustomRadio" 48 | , Html.css 49 | [ Css.displayFlex 50 | , Css.alignItems Css.center 51 | , Css.cursor Css.pointer 52 | ] 53 | ] 54 | [ Html.input 55 | [ Html.type_ "radio" 56 | , Html.id "myCustomRadio" 57 | , Html.css 58 | [ Css.display Css.none 59 | , Css.checked 60 | [ Css.Global.generalSiblings 61 | [ Css.Global.selector ".custom-radio__icon > .custom-radio__inner-icon" 62 | [ Css.backgroundColor <| Css.hex "88c0d0" ] 63 | ] 64 | ] 65 | ] 66 | ] 67 | [] 68 | , Html.div 69 | [ Html.class "custom-radio__icon" 70 | , Html.css 71 | [ Css.border3 (Css.px 1) Css.solid (Css.hex "EFEFEF") 72 | , Css.borderRadius <| Css.pct 100 73 | , Css.marginRight <| Css.rem 0.4 74 | , Css.padding <| Css.px 2 75 | ] 76 | ] 77 | [ Html.div 78 | [ Html.class "custom-radio__inner-icon" 79 | , Html.css 80 | [ Css.borderRadius <| Css.pct 100 81 | , Css.height <| Css.rem 0.8 82 | , Css.width <| Css.rem 0.8 83 | ] 84 | ] 85 | [] 86 | ] 87 | , Html.text "Some text" 88 | ] 89 | """ 90 | } 91 | 92 | 93 | update : Msg -> Model -> Model 94 | update _ model = 95 | model 96 | 97 | 98 | view : Model -> View Msg 99 | view { code, component } = 100 | { title = "Custom radio | Input" 101 | , body = 102 | { header = "Custom radio input" 103 | , content = PageComponent.view component 104 | , code = code 105 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Input/CustomRadio.elm" 106 | } 107 | |> Components.pageBody 108 | } 109 | -------------------------------------------------------------------------------- /src/Pages/Input/Dropdown.elm: -------------------------------------------------------------------------------- 1 | module Pages.Input.Dropdown exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Input.Dropdown as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Css.Global 40 | import Html.Styled as Html exposing (Html) 41 | import Html.Styled.Attributes as Html 42 | 43 | 44 | tab : Html msg 45 | tab = 46 | Html.div 47 | [ Html.css 48 | [ Css.position Css.relative 49 | , Css.hover 50 | [ Css.Global.descendants 51 | [ Css.Global.selector ".dropdown__content" 52 | [ Css.display Css.block ] 53 | ] 54 | ] 55 | ] 56 | ] 57 | [ Html.button 58 | [] 59 | [] 60 | , Html.div 61 | [ Html.class "dropdown__content" 62 | , Html.css 63 | [ Css.backgrounColor <| Css.hex "FFFFFF" 64 | , Css.position Css.absolute 65 | , Css.top <| Css.pct 100 66 | , Css.display Css.none 67 | , Css.marginTop <| Css.px 2 68 | , Css.width <| Css.px 250 69 | , Css.zIndex <| Css.int 9999 70 | ] 71 | ] 72 | [] 73 | ] 74 | """ 75 | } 76 | 77 | 78 | update : Msg -> Model -> Model 79 | update _ model = 80 | model 81 | 82 | 83 | view : Model -> View Msg 84 | view { code, component } = 85 | { title = "Dropdown | Input" 86 | , body = 87 | { header = "Dropdown input" 88 | , content = PageComponent.view component 89 | , code = code 90 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Input/Dropdown.elm" 91 | } 92 | |> Components.pageBody 93 | } 94 | -------------------------------------------------------------------------------- /src/Pages/Input/FloatingLabel.elm: -------------------------------------------------------------------------------- 1 | module Pages.Input.FloatingLabel exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Input.FloatingLabel as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Css.Global 40 | import Html.Styled as Html exposing (Html) 41 | import Html.Styled.Attributes as Html 42 | 43 | 44 | floatingLabel : Html msg 45 | floatingLabel = 46 | Html.div 47 | [ Html.css 48 | [ Css.position Css.relative 49 | , Css.Global.descendants 50 | [ Css.Global.selector ".floating-label__input:not(:placeholder-shown) + label" 51 | [ Css.backgroundColor <| Css.hex "ffffff" 52 | , Css.transform <| Css.translate2 Css.zero (Css.pct -50) 53 | , Css.opacity <| Css.num 1 54 | ] 55 | ] 56 | ] 57 | ] 58 | [ Html.input 59 | [ Html.class "floating-label__input" 60 | , Html.placeholder "Placeholder" 61 | , Html.css 62 | [ Css.padding <| Css.px 8 63 | , Css.borderRadius <| Css.px 4 64 | , Css.border3 (Css.px 1) Css.solid (Css.hex "efefef") 65 | ] 66 | ] 67 | [] 68 | , Html.label 69 | [ Html.class "floating-label__label" 70 | , Html.css 71 | [ Css.position Css.absolute 72 | , Css.left <| Css.px 8 73 | , Css.top <| Css.px 0 74 | , Css.opacity Css.zero 75 | , Css.pointerEvents Css.none 76 | , Css.Transitions.transition 77 | [ Css.Transitions.opacity 200 78 | , Css.Transitions.transform 200 79 | ] 80 | ] 81 | ] 82 | [ Html.text "Placeholder" ] 83 | ] 84 | """ 85 | } 86 | 87 | 88 | update : Msg -> Model -> Model 89 | update _ model = 90 | model 91 | 92 | 93 | view : Model -> View Msg 94 | view { code, component } = 95 | { title = "Floating label | Input" 96 | , body = 97 | { header = "Floating label input" 98 | , content = PageComponent.view component 99 | , code = code 100 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Input/FloatingLabel.elm" 101 | } 102 | |> Components.pageBody 103 | } 104 | -------------------------------------------------------------------------------- /src/Pages/Input/RadioButtonGroup.elm: -------------------------------------------------------------------------------- 1 | module Pages.Input.RadioButtonGroup exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Input.RadioButtonGroup as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Css.Global 40 | import Html.Styled as Html exposing (Html) 41 | import Html.Styled.Attributes as Html 42 | 43 | 44 | radioButtonGroup : Html msg 45 | radioButtonGroup = 46 | Html.div 47 | [ Html.css 48 | [ Css.displayFlex 49 | , Css.border3 (Css.px 1) Css.solid (Css.hex "efefef") 50 | , Css.borderRadius <| Css.px 4 51 | , Css.Global.descendants 52 | [ Css.Global.selector ".radio-button:not(:last-of-type)" 53 | [ Css.borderRight3 (Css.px 1) Css.solid (Css.hex "efefef") ] 54 | ] 55 | ] 56 | ] 57 | [ Html.div 58 | [ Html.css 59 | [ Css.displayFlex 60 | , Css.flex <| Css.int 1 61 | ] 62 | , Html.class "radio-button" 63 | ] 64 | [ Html.input 65 | [ Html.type_ "radio" 66 | , Html.id "myCustomRadio" 67 | , Html.css 68 | [ Css.display Css.none 69 | , Css.checked 70 | [ Css.Global.generalSiblings 71 | [ Css.Global.selector ".radio-button__label" 72 | [ Css.backgroundColor <| Css.hex "88c0d0" ] 73 | ] 74 | ] 75 | ] 76 | ] 77 | [] 78 | , Html.label 79 | [ Html.class "radio-button__label" 80 | , Html.for "myCustomRadioid" 81 | , Html.css 82 | [ Css.displayFlex 83 | , Css.alignItems Css.center 84 | , Css.justifyContent Css.center 85 | , Css.padding <| Css.rem 0.8 86 | , Css.cursor Css.pointer 87 | ] 88 | ] 89 | [ Placeholders.Rectangle.view rectangle ] 90 | ] 91 | , -- more radio buttons 92 | ] 93 | """ 94 | } 95 | 96 | 97 | update : Msg -> Model -> Model 98 | update _ model = 99 | model 100 | 101 | 102 | view : Model -> View Msg 103 | view { code, component } = 104 | { title = "Radio button group | Input" 105 | , body = 106 | { header = "Radio button group" 107 | , content = PageComponent.view component 108 | , code = code 109 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Input/RadioButtonGroup.elm" 110 | } 111 | |> Components.pageBody 112 | } 113 | -------------------------------------------------------------------------------- /src/Pages/Input/Rating.elm: -------------------------------------------------------------------------------- 1 | module Pages.Input.Rating exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Input.Rating as PageComponent 9 | import Html.Styled as Html 10 | import Page 11 | import Request exposing (Request) 12 | import Shared 13 | import View exposing (View) 14 | 15 | 16 | page : Shared.Model -> Request -> Page.With Model Msg 17 | page _ _ = 18 | Page.sandbox 19 | { init = init 20 | , update = update 21 | , view = view 22 | } 23 | 24 | 25 | type alias Model = 26 | { code : String 27 | , component : PageComponent.Model 28 | } 29 | 30 | 31 | type Msg 32 | = RatingMsg PageComponent.Msg 33 | 34 | 35 | init : Model 36 | init = 37 | { component = PageComponent.init 38 | , code = """ 39 | import Css 40 | import Css.Global 41 | import Html.Styled as Html exposing (Html) 42 | import Html.Styled.Attributes as Html 43 | import Html.Styled.Keyed 44 | 45 | 46 | rating : Int -> Html msg 47 | rating score = 48 | List.range 1 5 49 | |> List.reverse 50 | |> List.map (starView score) 51 | |> Html.Styled.Keyed.node "div" 52 | [ Css.displayFlex 53 | , Css.alignItems Css.center 54 | , Css.flexDirection Css.rowReverse 55 | , Css.Global.descendants 56 | [ Css.Global.selector ".rating__star" 57 | [ Css.backgroundColor Css.transparent 58 | , Css.color (Css.hex "efefef") 59 | , Css.cursor Css.pointer 60 | ] 61 | , Css.Global.selector ".rating__star:hover" 62 | [ Css.color (Css.hex "88c0d0") ] 63 | , Css.Global.selector ".rating__star:hover ~ .rating__star" 64 | [ Css.color (Css.hex "88c0d0") ] 65 | ] 66 | ] 67 | 68 | 69 | starView : Int -> Int -> ( String, Html Msg ) 70 | starView index score = 71 | ( "star_" ++ String.fromInt index 72 | , Html.span 73 | [ Html.class "rating__star" ] 74 | [ Html.text "★" ] 75 | ) 76 | """ 77 | } 78 | 79 | 80 | update : Msg -> Model -> Model 81 | update msg ({ component } as model) = 82 | case msg of 83 | RatingMsg subMsg -> 84 | let 85 | newComponent = 86 | PageComponent.update subMsg component 87 | in 88 | { model | component = newComponent } 89 | 90 | 91 | view : Model -> View Msg 92 | view { code, component } = 93 | { title = "Rating | Input" 94 | , body = 95 | { header = "Rating input" 96 | , content = PageComponent.view component |> Html.map RatingMsg 97 | , code = code 98 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Input/Rating.elm" 99 | } 100 | |> Components.pageBody 101 | } 102 | -------------------------------------------------------------------------------- /src/Pages/Input/SearchBox.elm: -------------------------------------------------------------------------------- 1 | module Pages.Input.SearchBox exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Input.SearchBox as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Css.Global 40 | import Html.Styled as Html exposing (Html) 41 | import Html.Styled.Attributes as Html 42 | 43 | 44 | searchBox : Html msg 45 | searchBox = 46 | Html.div 47 | [ Html.css 48 | [ Css.position Css.relative 49 | , Css.Global.descendants 50 | [ Css.Global.selector ".search-box__input:not(:placeholder-shown) + label" 51 | [ Css.displayFlex 52 | , Css.alignItems Css.center 53 | , Css.border3 (Css.px 1) Css.solid (Css.hex "efefef") 54 | , Css.padding <| Css.px 8 55 | ] 56 | ] 57 | ] 58 | ] 59 | [ Html.input 60 | [ Html.class "search-box__input" 61 | , Html.placeholder "Search" 62 | , Html.css 63 | [ Css.border <| Css.px 0 64 | , Css.flex <| Css.int 1 65 | ] 66 | ] 67 | [] 68 | ] 69 | """ 70 | } 71 | 72 | 73 | update : Msg -> Model -> Model 74 | update _ model = 75 | model 76 | 77 | 78 | view : Model -> View Msg 79 | view { code, component } = 80 | { title = "Search box | Input" 81 | , body = 82 | { header = "Search box input" 83 | , content = PageComponent.view component 84 | , code = code 85 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Input/SearchBox.elm" 86 | } 87 | |> Components.pageBody 88 | } 89 | -------------------------------------------------------------------------------- /src/Pages/Layout.elm: -------------------------------------------------------------------------------- 1 | module Pages.Layout exposing (view) 2 | 3 | import Components 4 | import Html.Styled as Html 5 | import Html.Styled.Attributes as Html 6 | import Html.Styled.Keyed 7 | import View exposing (View) 8 | 9 | 10 | view : View msg 11 | view = 12 | { title = "Layout" 13 | , body = 14 | [ Html.header 15 | [ Html.class "header" ] 16 | [ Html.h1 17 | [] 18 | [ Html.text "Layout" ] 19 | ] 20 | , Components.layoutNavItems 21 | |> List.map Components.navItem 22 | |> Html.Styled.Keyed.ul [ Html.class "list" ] 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/Pages/Layout/Card.elm: -------------------------------------------------------------------------------- 1 | module Pages.Layout.Card exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Layout.Card as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Html.Styled as Html exposing (Html) 40 | import Html.Styled.Attributes as Html 41 | 42 | 43 | card : Html msg 44 | card = 45 | Html.div 46 | [ Html.css 47 | [ Css.displayFlex 48 | , Css.flexWrap Css.wrap 49 | , Css.margin2 Css.zero (Css.px -8) 50 | ] 51 | ] 52 | [ Html.div 53 | [ Html.css 54 | [ Css.flexBasis <| Css.pct 25 55 | , Css.padding2 Css.zero (Css.px 8) 56 | ] 57 | ] 58 | [] 59 | ] 60 | 61 | """ 62 | } 63 | 64 | 65 | update : Msg -> Model -> Model 66 | update _ model = 67 | model 68 | 69 | 70 | view : Model -> View Msg 71 | view { code, component } = 72 | { title = "Card | Layout" 73 | , body = 74 | { header = "Card layout" 75 | , content = PageComponent.view component 76 | , code = code 77 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Layout/Card.elm" 78 | } 79 | |> Components.pageBody 80 | } 81 | -------------------------------------------------------------------------------- /src/Pages/Layout/HolyGrail.elm: -------------------------------------------------------------------------------- 1 | module Pages.Layout.HolyGrail exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Layout.HolyGrail as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Html.Styled as Html exposing (Html) 40 | import Html.Styled.Attributes as Html 41 | 42 | 43 | holyGrail : Html msg 44 | holyGrail = 45 | Html.div 46 | [ Html.css 47 | [ Css.displayFlex 48 | , Css.flexDirection Css.column 49 | ] 50 | ] 51 | [ Html.header 52 | [] 53 | [] 54 | , Html.main_ 55 | [ Html.css 56 | [ Css.flexGrow <| Css.int 1 57 | , Css.displayFlex 58 | , Css.flexDirection Css.row 59 | ] 60 | ] 61 | [ Html.aside 62 | [ Html.css 63 | [ Css.width <| Css.pct 25 ] 64 | ] 65 | [] 66 | , Html.article 67 | [ Html.css 68 | [ Css.flexGrow <| Css.int 1 ] 69 | ] 70 | [] 71 | , Html.nav 72 | [ Html.css 73 | [ Css.width <| Css.pct 20 ] 74 | ] 75 | [] 76 | ] 77 | , Html.footer 78 | [] 79 | [] 80 | ] 81 | """ 82 | } 83 | 84 | 85 | update : Msg -> Model -> Model 86 | update _ model = 87 | model 88 | 89 | 90 | view : Model -> View Msg 91 | view { code, component } = 92 | { title = "Holy grail | Layout" 93 | , body = 94 | { header = "Holy grail layout" 95 | , content = PageComponent.view component 96 | , code = code 97 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Layout/HolyGrail.elm" 98 | } 99 | |> Components.pageBody 100 | } 101 | -------------------------------------------------------------------------------- /src/Pages/Layout/SameHeightColumns.elm: -------------------------------------------------------------------------------- 1 | module Pages.Layout.SameHeightColumns exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Layout.SameHeightColumns as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Html.Styled as Html exposing (Html) 40 | import Html.Styled.Attributes as Html 41 | 42 | 43 | sameHeightColumns : Html msg 44 | sameHeightColumns = 45 | Html.div 46 | [ Html.css 47 | [ Css.displayFlex ] 48 | ] 49 | [ Html.div 50 | [ Html.css 51 | [ Css.flex <| Css.int 1 52 | , Css.margin2 Css.zero (Css.px 8) 53 | ] 54 | ] 55 | [] 56 | , Html.div 57 | [ Html.css 58 | [ Css.flex <| Css.int 1 59 | , Css.margin2 Css.zero (Css.px 8) 60 | ] 61 | ] 62 | [] 63 | , Html.div 64 | [ Html.css 65 | [ Css.flex <| Css.int 1 66 | , Css.margin2 Css.zero (Css.px 8) 67 | ] 68 | ] 69 | [] 70 | ] 71 | """ 72 | } 73 | 74 | 75 | update : Msg -> Model -> Model 76 | update _ model = 77 | model 78 | 79 | 80 | view : Model -> View Msg 81 | view { code, component } = 82 | { title = "Same height columns | Layout" 83 | , body = 84 | { header = "Same height columns layout" 85 | , content = PageComponent.view component 86 | , code = code 87 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Layout/SameHeightColumns.elm" 88 | } 89 | |> Components.pageBody 90 | } 91 | -------------------------------------------------------------------------------- /src/Pages/Layout/Sidebar.elm: -------------------------------------------------------------------------------- 1 | module Pages.Layout.Sidebar exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Layout.Sidebar as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Html.Styled as Html exposing (Html) 40 | import Html.Styled.Attributes as Html 41 | 42 | 43 | sidebar : Html msg 44 | sidebar = 45 | Html.div 46 | [ Html.css 47 | [ Css.displayFlex ] 48 | ] 49 | [ Html.aside 50 | [ Html.css 51 | [ Css.width <| Css.pct 30 ] 52 | ] 53 | [] 54 | , Html.main_ 55 | [ Html.css 56 | [ Css.flex <| Css.int 1 57 | , Css.overflow Css.auto 58 | ] 59 | ] 60 | [] 61 | ] 62 | """ 63 | } 64 | 65 | 66 | update : Msg -> Model -> Model 67 | update _ model = 68 | model 69 | 70 | 71 | view : Model -> View Msg 72 | view { code, component } = 73 | { title = "Sidebar | Layout" 74 | , body = 75 | { header = "Sidebar layout" 76 | , content = PageComponent.view component 77 | , code = code 78 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Layout/Sidebar.elm" 79 | } 80 | |> Components.pageBody 81 | } 82 | -------------------------------------------------------------------------------- /src/Pages/Layout/SplitScreen.elm: -------------------------------------------------------------------------------- 1 | module Pages.Layout.SplitScreen exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Layout.SplitScreen as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Html.Styled as Html exposing (Html) 40 | import Html.Styled.Attributes as Html 41 | 42 | 43 | splitScreen : Html msg 44 | splitScreen = 45 | Html.div 46 | [ Html.css 47 | [ Css.displayFlex ] 48 | ] 49 | [ Html.div 50 | [ Html.css 51 | [ Css.flex <| Css.int 1 ] 52 | ] 53 | [] 54 | , Html.div 55 | [ Html.css 56 | [ Css.flex <| Css.int 1 ] 57 | ] 58 | [] 59 | ] 60 | """ 61 | } 62 | 63 | 64 | update : Msg -> Model -> Model 65 | update _ model = 66 | model 67 | 68 | 69 | view : Model -> View Msg 70 | view { code, component } = 71 | { title = "Split screen | Layout" 72 | , body = 73 | { header = "Split screen layout" 74 | , content = PageComponent.view component 75 | , code = code 76 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Layout/SplitScreen.elm" 77 | } 78 | |> Components.pageBody 79 | } 80 | -------------------------------------------------------------------------------- /src/Pages/Layout/StickyFooter.elm: -------------------------------------------------------------------------------- 1 | module Pages.Layout.StickyFooter exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Layout.StickyFooter as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Html.Styled as Html exposing (Html) 40 | import Html.Styled.Attributes as Html 41 | 42 | 43 | stickyFooter : Html msg 44 | stickyFooter = 45 | Html.div 46 | [ Html.css 47 | [ Css.displayFlex 48 | , Css.flexDirection Css.column 49 | , Css.height <| Css.pct 100 50 | ] 51 | ] 52 | [ Html.header 53 | [ Html.css 54 | [ Css.flexShrink <| Css.int 0 ] 55 | ] 56 | [] 57 | , Html.main_ 58 | [ Html.css 59 | [ Css.flexGrow <| Css.int 1 ] 60 | ] 61 | [] 62 | , Html.footer 63 | [ Html.css 64 | [ Css.flexShrink <| Css.int 0 ] 65 | ] 66 | [] 67 | ] 68 | """ 69 | } 70 | 71 | 72 | update : Msg -> Model -> Model 73 | update _ model = 74 | model 75 | 76 | 77 | view : Model -> View Msg 78 | view { code, component } = 79 | { title = "Sticky footer | Layout" 80 | , body = 81 | { header = "Sticky footer layout" 82 | , content = PageComponent.view component 83 | , code = code 84 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Layout/StickyFooter.elm" 85 | } 86 | |> Components.pageBody 87 | } 88 | -------------------------------------------------------------------------------- /src/Pages/Layout/StickyHeader.elm: -------------------------------------------------------------------------------- 1 | module Pages.Layout.StickyHeader exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Layout.StickyHeader as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Html.Styled as Html exposing (Html) 40 | import Html.Styled.Attributes as Html 41 | 42 | 43 | stickyHeader : Html msg 44 | stickyHeader = 45 | Html.div 46 | [] 47 | [ Html.header 48 | [ Html.css 49 | [ Css.position Css.sticky 50 | , Css.top <| Css.int 0 51 | ] 52 | ] 53 | [] 54 | , Html.main_ 55 | [] 56 | [] 57 | ] 58 | """ 59 | } 60 | 61 | 62 | update : Msg -> Model -> Model 63 | update _ model = 64 | model 65 | 66 | 67 | view : Model -> View Msg 68 | view { code, component } = 69 | { title = "Sticky header | Layout" 70 | , body = 71 | { header = "Sticky header layout" 72 | , content = PageComponent.view component 73 | , code = code 74 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Layout/StickyHeader.elm" 75 | } 76 | |> Components.pageBody 77 | } 78 | -------------------------------------------------------------------------------- /src/Pages/Misc.elm: -------------------------------------------------------------------------------- 1 | module Pages.Misc exposing (view) 2 | 3 | import Components 4 | import Html.Styled as Html 5 | import Html.Styled.Attributes as Html 6 | import Html.Styled.Keyed 7 | import View exposing (View) 8 | 9 | 10 | view : View msg 11 | view = 12 | { title = "Misc" 13 | , body = 14 | [ Html.header 15 | [ Html.class "header" ] 16 | [ Html.h1 17 | [] 18 | [ Html.text "Misc" ] 19 | ] 20 | , Components.miscNavItems 21 | |> List.map Components.navItem 22 | |> Html.Styled.Keyed.ul [ Html.class "list" ] 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/Pages/Misc/StickyColumnsTable.elm: -------------------------------------------------------------------------------- 1 | module Pages.Misc.StickyColumnsTable exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Misc.StickyColumnsTable as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Html.Styled as Html exposing (Html) 40 | import Html.Styled.Attributes as Html 41 | 42 | 43 | stickyColumnsTable : Html msg 44 | stickyColumnsTable = 45 | Html.div 46 | [ Html.css 47 | [ Css.overflow Css.auto ] 48 | ] 49 | [ Html.table 50 | [ Html.css 51 | [ Css.position Css.relative ] 52 | ] 53 | [ Html.body 54 | [] 55 | [ Html.tr 56 | [] 57 | [ Html.th 58 | [ Html.css 59 | [ Css.position Css.sticky 60 | , Css.left Css.zero 61 | , Css.zIndex <| Css.int 9999 62 | ] 63 | ] 64 | [] 65 | ] 66 | ] 67 | ] 68 | ] 69 | """ 70 | } 71 | 72 | 73 | update : Msg -> Model -> Model 74 | update _ model = 75 | model 76 | 77 | 78 | view : Model -> View Msg 79 | view { code, component } = 80 | { title = "Sticky columns table | Misc" 81 | , body = 82 | { header = "Sticky columns table" 83 | , content = PageComponent.view component 84 | , code = code 85 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Misc/StickyColumnsTable.elm" 86 | } 87 | |> Components.pageBody 88 | } 89 | -------------------------------------------------------------------------------- /src/Pages/Misc/StickyHeadersTable.elm: -------------------------------------------------------------------------------- 1 | module Pages.Misc.StickyHeadersTable exposing (Model, Msg, page) 2 | 3 | import Components 4 | import Components.Misc.StickyHeadersTable as PageComponent 5 | import Page 6 | import Request exposing (Request) 7 | import Shared 8 | import View exposing (View) 9 | 10 | 11 | page : Shared.Model -> Request -> Page.With Model Msg 12 | page _ _ = 13 | Page.sandbox 14 | { init = init 15 | , update = update 16 | , view = view 17 | } 18 | 19 | 20 | type alias Model = 21 | { code : String 22 | , component : PageComponent.Model 23 | } 24 | 25 | 26 | type alias Msg = 27 | Never 28 | 29 | 30 | init : Model 31 | init = 32 | { component = PageComponent.init 33 | , code = """ 34 | import Css 35 | import Html.Styled as Html exposing (Html) 36 | import Html.Styled.Attributes as Html 37 | 38 | 39 | stickyHeadersTable : Html msg 40 | stickyHeadersTable = 41 | Html.div 42 | [ Html.css 43 | [ Css.overflow Css.auto ] 44 | ] 45 | [ Html.table 46 | [ Html.css 47 | [ Css.position Css.relative ] 48 | ] 49 | [ Html.thead 50 | [] 51 | [ Html.tr 52 | [] 53 | [ Html.th 54 | [ Html.css 55 | [ Css.position Css.sticky 56 | , Css.top Css.zero 57 | , Css.zIndex <| Css.int 9999 58 | ] 59 | ] 60 | [] 61 | ] 62 | ] 63 | ] 64 | ] 65 | """ 66 | } 67 | 68 | 69 | update : Msg -> Model -> Model 70 | update _ model = 71 | model 72 | 73 | 74 | view : Model -> View Msg 75 | view { code, component } = 76 | { title = "Sticky headers table | Misc" 77 | , body = 78 | { header = "Sticky headers table" 79 | , content = PageComponent.view component 80 | , code = code 81 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Misc/StickyHeadersTable.elm" 82 | } 83 | |> Components.pageBody 84 | } 85 | -------------------------------------------------------------------------------- /src/Pages/Misc/Timeline.elm: -------------------------------------------------------------------------------- 1 | module Pages.Misc.Timeline exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Misc.Timeline as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Html.Styled as Html exposing (Html) 40 | import Html.Styled.Attributes as Html 41 | import Html.Styled.Keyed as KHtml 42 | 43 | 44 | timeline : Html msg 45 | timeline = 46 | Html.div 47 | [ Html.css 48 | [ Css.position Css.relative ] 49 | ] 50 | [ -- The vertical line 51 | Html.div 52 | [ Html.css 53 | [ Css.borderRight3 (Css.px 2) Css.solid (Css.hex "EFEFEF") 54 | , Css.position Css.absolute 55 | , Css.top Css.zero 56 | , Css.left <| Css.px 16 57 | , Css.height <| Css.pct 100 58 | ] 59 | ] 60 | [] 61 | , KHtml.node "div" 62 | [] 63 | [ ( "item-1" 64 | , Html.div 65 | [ Html.css 66 | [ Css.marginBottom <| Css.rem 1 ] 67 | ] 68 | [ Html.header 69 | [ Html.css 70 | [ Css.displayFlex 71 | , Css.alignItems Css.center 72 | , Css.marginBottom <| Css.rem 0.5 73 | ] 74 | ] 75 | [ Placeholders.Circle.view circle 76 | , Placeholders.Rectangle.view rectangle 77 | ] 78 | , Html.div 79 | [ Html.css 80 | [ Css.marginLeft <| Css.px 48 ] 81 | ] 82 | [ Placeholders.Block.view block ] 83 | ] 84 | ) 85 | 86 | -- More items 87 | ] 88 | ] 89 | """ 90 | } 91 | 92 | 93 | update : Msg -> Model -> Model 94 | update _ model = 95 | model 96 | 97 | 98 | view : Model -> View Msg 99 | view { code, component } = 100 | { title = "Timeline | Misc" 101 | , body = 102 | { header = "Timeline" 103 | , content = PageComponent.view component 104 | , code = code 105 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Misc/Timeline.elm" 106 | } 107 | |> Components.pageBody 108 | } 109 | -------------------------------------------------------------------------------- /src/Pages/Navigation.elm: -------------------------------------------------------------------------------- 1 | module Pages.Navigation exposing (view) 2 | 3 | import Components 4 | import Html.Styled as Html 5 | import Html.Styled.Attributes as Html 6 | import Html.Styled.Keyed 7 | import View exposing (View) 8 | 9 | 10 | view : View msg 11 | view = 12 | { title = "Navigation" 13 | , body = 14 | [ Html.header 15 | [ Html.class "header" ] 16 | [ Html.h1 17 | [] 18 | [ Html.text "Navigation" ] 19 | ] 20 | , Components.navigationNavItems 21 | |> List.map Components.navItem 22 | |> Html.Styled.Keyed.ul [ Html.class "list" ] 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /src/Pages/Navigation/Breadcrumb.elm: -------------------------------------------------------------------------------- 1 | module Pages.Navigation.Breadcrumb exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Navigation.Breadcrumb as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Css.Global 40 | import Html.Styled as Html exposing (Html) 41 | import Html.Styled.Attributes as Html 42 | 43 | 44 | breadcrumb : Html msg 45 | breadcrumb = 46 | Html.div 47 | [ Html.css 48 | [ Css.displayFlex 49 | , Css.alignItems Css.center 50 | , Css.Global.descendants 51 | [ Css.Global.selector ".breadcrumb__item" 52 | [ Css.displayFlex 53 | , Css.alignItems Css.center 54 | , Css.minWidth <| Css.rem 6 55 | ] 56 | , Css.Global.selector ".breadcrumb__item:not(:last-of-type)" 57 | [ Css.after 58 | [ Css.property "content" ""/"" 59 | , Css.margin2 Css.zero (Css.em 0.5) 60 | ] 61 | ] 62 | ] 63 | ] 64 | ] 65 | [ Html.a 66 | [ Html.class "breadcrumb__item" ] 67 | [] 68 | , Html.a 69 | [ Html.class "breadcrumb__item" ] 70 | [] 71 | , Html.a 72 | [ Html.class "breadcrumb__item" ] 73 | [] 74 | ] 75 | """ 76 | } 77 | 78 | 79 | update : Msg -> Model -> Model 80 | update _ model = 81 | model 82 | 83 | 84 | view : Model -> View Msg 85 | view { code, component } = 86 | { title = "Breadcrumb | Navigation" 87 | , body = 88 | { header = "Breadcrumb navigation" 89 | , content = PageComponent.view component 90 | , code = code 91 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Navigation/Breadcrumb.elm" 92 | } 93 | |> Components.pageBody 94 | } 95 | -------------------------------------------------------------------------------- /src/Pages/Navigation/Drawer.elm: -------------------------------------------------------------------------------- 1 | module Pages.Navigation.Drawer exposing (Model, Msg, page) 2 | 3 | import Components 4 | import Components.Navigation.Drawer as PageComponent 5 | import Page 6 | import Request exposing (Request) 7 | import Shared 8 | import View exposing (View) 9 | 10 | 11 | page : Shared.Model -> Request -> Page.With Model Msg 12 | page _ _ = 13 | Page.sandbox 14 | { init = init 15 | , update = update 16 | , view = view 17 | } 18 | 19 | 20 | type alias Model = 21 | { code : String 22 | , component : PageComponent.Model 23 | } 24 | 25 | 26 | type alias Msg = 27 | Never 28 | 29 | 30 | init : Model 31 | init = 32 | { component = PageComponent.init 33 | , code = """ 34 | import Css 35 | import Html.Styled as Html exposing (Html) 36 | import Html.Styled.Attributes as Html 37 | 38 | 39 | drawer : Html msg 40 | drawer = 41 | Html.div 42 | [ Html.css 43 | [ Css.width <| Css.pct 100 44 | , Css.height <| Css.pct 100 45 | , Css.position Css.fixed 46 | , Css.left Css.zero 47 | , Css.top Css.zero 48 | , Css.zIndex <| Css.int 9999 49 | ] 50 | [ Html.div 51 | [ Html.css 52 | [ Css.width <| Css.pct 100 53 | , Css.height <| Css.pct 100 54 | , Css.position Css.fixed 55 | , Css.left Css.zero 56 | , Css.top Css.zero 57 | , Css.zIndex <| Css.int -1 58 | , Css.backgroundColor <| Css.rgba 0 0 0 0.5 59 | ] 60 | [] 61 | , Html.div 62 | [ Html.css 63 | [ Css.width <| Css.px 200 64 | , Css.height <| Css.pct 100 65 | , Css.position Css.fixed 66 | , Css.left Css.zero 67 | , Css.top Css.zero 68 | , Css.backgroundColor <| Css.hex "FFFFFF" 69 | ] 70 | ] 71 | [] 72 | ] 73 | """ 74 | } 75 | 76 | 77 | update : Msg -> Model -> Model 78 | update _ model = 79 | model 80 | 81 | 82 | view : Model -> View Msg 83 | view { code, component } = 84 | { title = "Drawer | Navigation" 85 | , body = 86 | { header = "Drawer navigation" 87 | , content = PageComponent.view component 88 | , code = code 89 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Navigation/Drawer.elm" 90 | } 91 | |> Components.pageBody 92 | } 93 | -------------------------------------------------------------------------------- /src/Pages/Navigation/Pagination.elm: -------------------------------------------------------------------------------- 1 | module Pages.Navigation.Pagination exposing (Model, Msg, page) 2 | 3 | import Components 4 | import Components.Navigation.Pagination as PageComponent 5 | import Page 6 | import Request exposing (Request) 7 | import Shared 8 | import View exposing (View) 9 | 10 | 11 | page : Shared.Model -> Request -> Page.With Model Msg 12 | page _ _ = 13 | Page.sandbox 14 | { init = init 15 | , update = update 16 | , view = view 17 | } 18 | 19 | 20 | type alias Model = 21 | { code : String 22 | , component : PageComponent.Model 23 | } 24 | 25 | 26 | type alias Msg = 27 | Never 28 | 29 | 30 | init : Model 31 | init = 32 | { component = PageComponent.init 33 | , code = """ 34 | import Css 35 | import Html.Styled as Html exposing (Html) 36 | import Html.Styled.Attributes as Html 37 | 38 | 39 | pagination : Html msg 40 | pagination = 41 | Html.div 42 | [ Html.css 43 | [ Css.displayFlex 44 | , Css.alignItems Css.center 45 | , Css.justifyContent Css.center 46 | , Css.border3 (Css.px 1) Css.solid (Css.hex "efefef") 47 | , Css.borderRadius <| Css.px 4 48 | ] 49 | ] 50 | [ Html.div 51 | [ Html.css 52 | [ Css.displayFlex 53 | , Css.alignItems Css.center 54 | , Css.justifyContent Css.center 55 | , Css.borderRight3 (Css.px 1) Css.solid (Css.hex "efefef") 56 | ] 57 | ] 58 | [] 59 | 60 | ... 61 | 62 | -- Last item 63 | 64 | , Html.div 65 | [ Html.css 66 | [ Css.displayFlex 67 | , Css.alignItems Css.center 68 | , Css.justifyContent Css.center 69 | , Css.borderRight <| Css.px 0 70 | ] 71 | ] 72 | [] 73 | ] 74 | """ 75 | } 76 | 77 | 78 | update : Msg -> Model -> Model 79 | update _ model = 80 | model 81 | 82 | 83 | view : Model -> View Msg 84 | view { code, component } = 85 | { title = "Pagination | Navigation" 86 | , body = 87 | { header = "Pagination navigation" 88 | , content = PageComponent.view component 89 | , code = code 90 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Navigation/Pagination.elm" 91 | } 92 | |> Components.pageBody 93 | } 94 | -------------------------------------------------------------------------------- /src/Pages/Navigation/Split.elm: -------------------------------------------------------------------------------- 1 | module Pages.Navigation.Split exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Navigation.Split as PageComponent 9 | import Page 10 | import Request exposing (Request) 11 | import Shared 12 | import View exposing (View) 13 | 14 | 15 | page : Shared.Model -> Request -> Page.With Model Msg 16 | page _ _ = 17 | Page.sandbox 18 | { init = init 19 | , update = update 20 | , view = view 21 | } 22 | 23 | 24 | type alias Model = 25 | { code : String 26 | , component : PageComponent.Model 27 | } 28 | 29 | 30 | type alias Msg = 31 | Never 32 | 33 | 34 | init : Model 35 | init = 36 | { component = PageComponent.init 37 | , code = """ 38 | import Css 39 | import Html.Styled as Html exposing (Html) 40 | import Html.Styled.Attributes as Html 41 | 42 | 43 | split : Html msg 44 | split = 45 | Html.ul 46 | [ Html.css 47 | [ Css.displayFlex 48 | , Css.alignItems Css.center 49 | , Css.listStyle Css.none 50 | , Css.margin Css.zero 51 | ] 52 | ] 53 | [ Html.li 54 | [] 55 | [] 56 | 57 | ... 58 | 59 | -- Last item 60 | 61 | , Html.li 62 | [ Html.css 63 | [ Css.marginLeft Css.auto ] 64 | ] 65 | [] 66 | ] 67 | """ 68 | } 69 | 70 | 71 | update : Msg -> Model -> Model 72 | update _ model = 73 | model 74 | 75 | 76 | view : Model -> View Msg 77 | view { code, component } = 78 | { title = "Split | Navigation" 79 | , body = 80 | { header = "Split navigation" 81 | , content = PageComponent.view component 82 | , code = code 83 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Navigation/Split.elm" 84 | } 85 | |> Components.pageBody 86 | } 87 | -------------------------------------------------------------------------------- /src/Pages/Navigation/Tab.elm: -------------------------------------------------------------------------------- 1 | module Pages.Navigation.Tab exposing 2 | ( Model 3 | , Msg 4 | , page 5 | ) 6 | 7 | import Components 8 | import Components.Navigation.Tab as PageComponent 9 | import Html.Styled as Html 10 | import Page 11 | import Request exposing (Request) 12 | import Shared 13 | import View exposing (View) 14 | 15 | 16 | page : Shared.Model -> Request -> Page.With Model Msg 17 | page _ _ = 18 | Page.sandbox 19 | { init = init 20 | , update = update 21 | , view = view 22 | } 23 | 24 | 25 | type alias Model = 26 | { code : String 27 | , component : PageComponent.Model 28 | } 29 | 30 | 31 | type Msg 32 | = ComponentMsg PageComponent.Msg 33 | 34 | 35 | init : Model 36 | init = 37 | { component = PageComponent.init 38 | , code = """ 39 | import Css 40 | import Html.Styled as Html exposing (Html) 41 | import Html.Styled.Attributes as Html 42 | 43 | 44 | tab : Html msg 45 | tab = 46 | Html.div 47 | [ Html.css 48 | [ Css.displayFlex 49 | , Css.alignItems Css.center 50 | , Css.justifyContent Css.center 51 | ] 52 | ] 53 | 54 | -- Actice tab 55 | 56 | [ Html.div 57 | [ Html.css 58 | [ Css.border3 (Css.px 1) Css.solid (Css.hex "efefef") 59 | , Css.borderBottomColor Css.transparent 60 | , Css.borderTopLeftRadius <| Css.px 2 61 | , Css.borderTopRightRadius <| Css.px 2 62 | ] 63 | ] 64 | [] 65 | 66 | -- Inactive tab 67 | 68 | , Html.div 69 | [ Html.css 70 | [ Css.borderBottom3 (Css.px 1) Css.solid (Css.hex "efefef") ] 71 | ] 72 | [] 73 | ] 74 | """ 75 | } 76 | 77 | 78 | update : Msg -> Model -> Model 79 | update msg ({ component } as model) = 80 | case msg of 81 | ComponentMsg subMsg -> 82 | let 83 | newComponent = 84 | PageComponent.update subMsg component 85 | in 86 | { model | component = newComponent } 87 | 88 | 89 | view : Model -> View Msg 90 | view { code, component } = 91 | { title = "Tab | Navigation" 92 | , body = 93 | { header = "Tab navigation" 94 | , content = Html.map ComponentMsg <| PageComponent.view component 95 | , code = code 96 | , componentUrl = "https://github.com/bigardone/elm-css-patterns/blob/master/src/Components/Navigation/Tab.elm" 97 | } 98 | |> Components.pageBody 99 | } 100 | -------------------------------------------------------------------------------- /src/Pages/NotFound.elm: -------------------------------------------------------------------------------- 1 | module Pages.NotFound exposing (view) 2 | 3 | import Html.Styled as Html 4 | import Html.Styled.Attributes as Html 5 | import View exposing (View) 6 | 7 | 8 | view : View msg 9 | view = 10 | { title = "Page not found" 11 | , body = 12 | [ Html.section 13 | [ Html.class "not-found" ] 14 | [ Html.h1 15 | [] 16 | [ Html.text "404: Page not found" ] 17 | , Html.p 18 | [ Html.class "hero" ] 19 | [ Html.text "The pattern that you are looking for does not exist." ] 20 | ] 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /src/Shared.elm: -------------------------------------------------------------------------------- 1 | module Shared exposing 2 | ( Flags 3 | , Model 4 | , Msg(..) 5 | , init 6 | , subscriptions 7 | , update 8 | ) 9 | 10 | import Json.Decode as Json 11 | import Request exposing (Request) 12 | 13 | 14 | type alias Flags = 15 | Json.Value 16 | 17 | 18 | type alias Model = 19 | {} 20 | 21 | 22 | type Msg 23 | = Never 24 | 25 | 26 | init : Request -> Flags -> ( Model, Cmd Msg ) 27 | init _ _ = 28 | ( {}, Cmd.none ) 29 | 30 | 31 | update : Request -> Msg -> Model -> ( Model, Cmd Msg ) 32 | update _ _ model = 33 | ( model, Cmd.none ) 34 | 35 | 36 | subscriptions : Request -> Model -> Sub Msg 37 | subscriptions _ _ = 38 | Sub.none 39 | -------------------------------------------------------------------------------- /src/Styles.elm: -------------------------------------------------------------------------------- 1 | module Styles exposing (mainContent) 2 | 3 | import Css 4 | import Css.Global 5 | import Styles.Animations as Animations 6 | import Styles.Breakpoints as Breakpoints 7 | import Styles.Colors as Colors 8 | 9 | 10 | mainContent : List Css.Style 11 | mainContent = 12 | [ Css.fontFamilies [ "Work Sans", "sans-serif" ] 13 | , Css.margin2 Css.zero Css.auto 14 | , Css.color Colors.blackLightest 15 | , Css.displayFlex 16 | , Css.flexDirection Css.column 17 | , Css.minHeight <| Css.vh 100 18 | , Css.Global.withClass "main-top" mainTop 19 | , Css.Global.withClass "show-sidebar" showSidebar 20 | , Css.Global.descendants 21 | [ Css.Global.selector ".main-content__sidebar" mainContentSidebar 22 | , Css.Global.selector ".main-content__body" mainContentBody 23 | , Css.Global.selector ".main-content__nav" mainContentNav 24 | , Css.Global.selector ".main-content__footer" mainContentFooter 25 | , Css.Global.selector ".inner" inner 26 | , Css.Global.selector ".container" 27 | [ Css.width <| Css.px 1024 28 | , Css.padding2 Css.zero (Css.rem 1) 29 | , Css.margin2 Css.zero Css.auto 30 | , Css.displayFlex 31 | ] 32 | , Css.Global.selector "a" 33 | [ Css.textDecoration Css.none 34 | , Css.color Colors.blueDarker 35 | , Css.Global.withClass "cool" 36 | [ Css.position Css.relative 37 | , Css.fontWeight <| Css.int 500 38 | , Css.after 39 | [ Css.property "content" "\" \"" 40 | , Css.backgroundColor Colors.blueLighter 41 | , Css.position Css.absolute 42 | , Css.left <| Css.em 0.6 43 | , Css.bottom <| Css.em -0.1 44 | , Css.zIndex <| Css.int -1 45 | , Css.property "width" "calc(100% - .4em)" 46 | , Css.property "height" "calc(100% - .6em)" 47 | , Css.property "transition" "0.35s cubic-bezier(0.25, 0.1, 0, 2.05)" 48 | ] 49 | , Css.hover 50 | [ Css.after 51 | [ Css.left Css.zero 52 | , Css.bottom <| Css.px -2 53 | , Css.width <| Css.pct 100 54 | , Css.height <| Css.pct 100 55 | ] 56 | ] 57 | ] 58 | ] 59 | , Css.Global.selector "h1" 60 | [ Css.fontSize <| Css.rem 1.9 61 | , Css.fontWeight <| Css.int 700 62 | , Css.color Colors.black 63 | ] 64 | ] 65 | ] 66 | 67 | 68 | mainTop : List Css.Style 69 | mainTop = 70 | [ Css.Global.descendants 71 | [ Css.Global.selector ".top-header" 72 | [ Animations.scale 73 | , Css.marginBottom <| Css.rem 5 74 | , Css.textAlign Css.center 75 | , Css.padding2 (Css.rem 5) Css.zero 76 | , Breakpoints.small 77 | [ Css.padding Css.zero ] 78 | ] 79 | , Css.Global.selector ".main-content__sidebar" 80 | [ Css.display Css.none ] 81 | , Css.Global.selector "h1" 82 | [ Css.fontSize <| Css.rem 3.4 83 | , Css.marginBottom <| Css.em 1 84 | , Breakpoints.small 85 | [ Css.fontSize <| Css.rem 2.6 ] 86 | ] 87 | , Css.Global.selector ".hero" 88 | [ Css.fontSize <| Css.rem 1.8 89 | , Breakpoints.small 90 | [ Css.fontSize <| Css.rem 1.4 ] 91 | ] 92 | , Css.Global.selector ".patterns" 93 | [ Css.displayFlex 94 | , Css.width <| Css.pct 85 95 | , Css.margin2 Css.zero Css.auto 96 | , Css.justifyContent Css.spaceBetween 97 | , Css.alignItems Css.flexStart 98 | , Css.Global.descendants 99 | [ Css.Global.selector ".patterns__section" 100 | [ Css.flex <| Css.int 1 ] 101 | , Css.Global.selector ".patterns__header" 102 | [ Css.marginBottom <| Css.rem 1 ] 103 | ] 104 | , Breakpoints.small 105 | [ Css.width <| Css.pct 100 106 | , Css.display Css.block 107 | , Css.Global.descendants 108 | [ Css.Global.selector ".patterns__section" 109 | [ Css.marginBottom <| Css.rem 2 110 | , Css.textAlign Css.center 111 | ] 112 | ] 113 | ] 114 | ] 115 | ] 116 | ] 117 | 118 | 119 | showSidebar : List Css.Style 120 | showSidebar = 121 | [ Css.height <| Css.vh 100 122 | , Css.overflow Css.hidden 123 | , Css.Global.descendants 124 | [ Css.Global.selector ".main-content__sidebar" 125 | [ Css.display Css.none ] 126 | ] 127 | ] 128 | 129 | 130 | mainContentNav : List Css.Style 131 | mainContentNav = 132 | [ Css.height <| Css.rem 5 133 | , Css.displayFlex 134 | , Css.backgroundColor Colors.white 135 | , Css.alignItems Css.center 136 | , Css.borderBottom3 (Css.px 1) Css.solid Colors.greyLighter 137 | , Css.flexShrink <| Css.int 0 138 | , Css.zIndex <| Css.int 999 139 | , Css.Global.descendants 140 | [ Css.Global.selector ".logo" 141 | [ Css.textDecoration Css.none 142 | , Css.color Colors.blueDarker 143 | , Css.fontWeight Css.bolder 144 | , Css.textTransform Css.lowercase 145 | , Css.fontSize <| Css.rem 1.1 146 | ] 147 | , Css.Global.selector ".container" 148 | [ Css.displayFlex 149 | , Css.justifyContent Css.spaceBetween 150 | ] 151 | , Css.Global.selector ".burger" 152 | [ Css.display Css.none 153 | , Css.color Colors.blueDarker 154 | , Breakpoints.small 155 | [ Css.display Css.inlineBlock 156 | , Css.marginLeft <| Css.rem 0.3 157 | , Css.cursor Css.pointer 158 | ] 159 | ] 160 | ] 161 | , Breakpoints.small 162 | [ Css.position Css.sticky 163 | , Css.top Css.zero 164 | ] 165 | ] 166 | 167 | 168 | mainContentSidebar : List Css.Style 169 | mainContentSidebar = 170 | [ Css.displayFlex 171 | , Css.width <| Css.px 300 172 | , Css.flexDirection Css.column 173 | , Css.paddingRight <| Css.rem 2 174 | , Css.Global.descendants 175 | [ Css.Global.selector ".inner" 176 | [ Css.justifyContent Css.spaceBetween 177 | , Css.flexDirection Css.column 178 | , Css.displayFlex 179 | ] 180 | , Css.Global.selector ".main-nav" 181 | [ Css.marginTop <| Css.rem 1 182 | , Css.fontSize <| Css.rem 0.9 183 | , Css.position Css.sticky 184 | , Css.top Css.zero 185 | , Css.property "height" "calc(100vh - 70px)" 186 | , Css.overflowY Css.auto 187 | , Css.padding4 (Css.rem 1) (Css.rem 3) (Css.rem 2) Css.zero 188 | , Css.Global.descendants 189 | [ Css.Global.selector ".main-nav__section" 190 | [ Css.marginBottom <| Css.rem 1 ] 191 | , Css.Global.selector ".main-nav__header" 192 | [ Css.Global.descendants 193 | [ Css.Global.selector "a" 194 | [ Css.textTransform Css.uppercase 195 | , Css.color Colors.blueDark 196 | , Css.fontSize <| Css.rem 0.8 197 | , Css.fontWeight Css.bolder 198 | ] 199 | ] 200 | ] 201 | , Css.Global.selector "a" 202 | [ Css.textDecoration Css.none 203 | , Css.color Colors.blackLightest 204 | , Css.display Css.block 205 | , Css.padding (Css.rem 0.3) 206 | , Css.Global.withClass "active" 207 | [ Css.color Colors.blueDarker 208 | , Css.backgroundColor Colors.blueLighter 209 | , Css.borderRadius <| Css.px 2 210 | ] 211 | , Css.hover 212 | [ Css.color Colors.blueDarker ] 213 | ] 214 | , Css.Global.selector ".close" 215 | [ Css.display Css.none 216 | , Css.position Css.fixed 217 | , Css.zIndex <| Css.int 99999 218 | , Css.top <| Css.rem 1.5 219 | , Css.right <| Css.rem 0.8 220 | , Css.color Colors.blueDarker 221 | ] 222 | ] 223 | , Breakpoints.small 224 | [ Css.position Css.relative 225 | , Css.top Css.zero 226 | , Css.height Css.auto 227 | , Css.overflowY Css.visible 228 | , Css.Global.descendants 229 | [ Css.Global.selector ".close" 230 | [ Css.important <| Css.display Css.block 231 | ] 232 | ] 233 | ] 234 | ] 235 | ] 236 | , Breakpoints.small 237 | [ Css.display Css.none 238 | , Css.Global.withClass "show" 239 | [ Css.displayFlex 240 | , Css.position Css.fixed 241 | , Css.top Css.zero 242 | , Css.left Css.zero 243 | , Css.bottom Css.zero 244 | , Css.width <| Css.pct 100 245 | , Css.backgroundColor Colors.white 246 | , Css.padding <| Css.rem 1 247 | , Css.zIndex <| Css.int 999 248 | , Css.overflowY Css.auto 249 | , Animations.fade 250 | ] 251 | , Css.Global.descendants 252 | [ Css.Global.selector ".main-nav" 253 | [ Css.important <| Css.marginTop Css.zero 254 | , Css.important <| Css.paddingRight Css.zero 255 | ] 256 | , Css.Global.selector "svg" 257 | [ Css.fontSize <| Css.rem 1.2 ] 258 | ] 259 | ] 260 | ] 261 | 262 | 263 | mainContentBody : List Css.Style 264 | mainContentBody = 265 | [ Css.displayFlex 266 | , Css.flexGrow <| Css.int 1 267 | , Css.Global.descendants 268 | [ Css.Global.selector ".container" 269 | [ Css.displayFlex ] 270 | , Css.Global.selector ".inner" 271 | [ Css.flexDirection Css.column 272 | , Css.paddingTop <| Css.rem 2 273 | , Css.flex <| Css.int 1 274 | ] 275 | , Css.Global.selector ".header" 276 | [ Css.marginBottom <| Css.rem 3 277 | , Css.color Colors.black 278 | , Css.displayFlex 279 | , Css.alignItems Css.center 280 | , Css.justifyContent Css.spaceBetween 281 | , Breakpoints.small 282 | [ Css.display Css.block ] 283 | ] 284 | , Css.Global.selector ".header svg" 285 | [ Css.marginLeft <| Css.rem 0.3 ] 286 | , Css.Global.selector ".content" 287 | [ Css.displayFlex 288 | , Css.justifyContent Css.center 289 | ] 290 | , Css.Global.selector ".content__example" 291 | [ Css.displayFlex 292 | , Css.justifyContent Css.center 293 | , Css.width <| Css.pct 100 294 | , Css.border3 (Css.px 1) Css.solid Colors.grey 295 | , Css.borderRadius <| Css.px 4 296 | , Css.boxShadow5 Css.zero (Css.px 25) (Css.px 50) (Css.px -12) Colors.grey 297 | , Css.overflow Css.hidden 298 | , Animations.scale 299 | ] 300 | , Css.Global.selector ".code" 301 | [ Css.marginTop <| Css.rem 3 302 | , Css.overflow Css.auto 303 | , Css.borderRadius <| Css.px 4 304 | , Css.fontFamilies [ "monospace" ] 305 | ] 306 | , Css.Global.selector "c-highlight" 307 | [ Css.width <| Css.pct 100 308 | , Css.overflow Css.auto 309 | ] 310 | , Css.Global.selector "pre" 311 | [ Css.margin Css.zero ] 312 | ] 313 | ] 314 | 315 | 316 | mainContentFooter : List Css.Style 317 | mainContentFooter = 318 | [ Css.fontSize Css.smaller 319 | , Css.height <| Css.rem 5 320 | , Css.flexShrink <| Css.int 0 321 | , Css.displayFlex 322 | , Css.alignItems Css.center 323 | , Css.Global.descendants 324 | [ Css.Global.selector ".container" 325 | [ Css.textAlign Css.center 326 | , Css.displayFlex 327 | , Css.alignItems Css.center 328 | , Css.justifyContent Css.center 329 | ] 330 | ] 331 | ] 332 | 333 | 334 | inner : List Css.Style 335 | inner = 336 | [ Css.flex <| Css.int 1 ] 337 | -------------------------------------------------------------------------------- /src/Styles/Animations.elm: -------------------------------------------------------------------------------- 1 | module Styles.Animations exposing 2 | ( fade 3 | , scale 4 | ) 5 | 6 | import Css 7 | import Css.Animations 8 | 9 | 10 | scale : Css.Style 11 | scale = 12 | Css.batch 13 | [ Css.animationName scaleIn 14 | , Css.animationDuration <| Css.ms 300 15 | ] 16 | 17 | 18 | fade : Css.Style 19 | fade = 20 | Css.batch 21 | [ Css.animationName fadeIn 22 | , Css.animationDuration <| Css.ms 300 23 | ] 24 | 25 | 26 | scaleIn : Css.Animations.Keyframes {} 27 | scaleIn = 28 | Css.Animations.keyframes 29 | [ ( 0 30 | , [ Css.Animations.transform [ Css.scale 0.5 ] 31 | , Css.Animations.opacity <| Css.num 0 32 | ] 33 | ) 34 | , ( 100 35 | , [ Css.Animations.transform [ Css.scale 1 ] 36 | , Css.Animations.opacity <| Css.num 1 37 | ] 38 | ) 39 | ] 40 | 41 | 42 | fadeIn : Css.Animations.Keyframes {} 43 | fadeIn = 44 | Css.Animations.keyframes 45 | [ ( 0 46 | , [ Css.Animations.opacity <| Css.num 0 ] 47 | ) 48 | , ( 100 49 | , [ Css.Animations.opacity <| Css.num 1 ] 50 | ) 51 | ] 52 | -------------------------------------------------------------------------------- /src/Styles/Breakpoints.elm: -------------------------------------------------------------------------------- 1 | module Styles.Breakpoints exposing (small) 2 | 3 | import Css 4 | import Css.Media 5 | 6 | 7 | {-| 8 | 9 | @media (min-width: 768px) 10 | 11 | -} 12 | small : List Css.Style -> Css.Style 13 | small = 14 | custom 768 15 | 16 | 17 | custom : Float -> List Css.Style -> Css.Style 18 | custom width = 19 | Css.Media.withMedia 20 | [ Css.Media.all [ Css.Media.maxWidth (Css.px width) ] ] 21 | -------------------------------------------------------------------------------- /src/Styles/Colors.elm: -------------------------------------------------------------------------------- 1 | module Styles.Colors exposing 2 | ( black 3 | , blackLight 4 | , blackLightest 5 | , blue 6 | , blueDark 7 | , blueDarker 8 | , blueLight 9 | , blueLighter 10 | , grey 11 | , greyLight 12 | , greyLighter 13 | , white 14 | ) 15 | 16 | import Css 17 | 18 | 19 | black : Css.Color 20 | black = 21 | Css.hex "2e3440" 22 | 23 | 24 | blackLight : Css.Color 25 | blackLight = 26 | Css.hex "3b4252" 27 | 28 | 29 | blackLightest : Css.Color 30 | blackLightest = 31 | Css.hex "4c566a" 32 | 33 | 34 | grey : Css.Color 35 | grey = 36 | Css.hex "d8dee9" 37 | 38 | 39 | greyLight : Css.Color 40 | greyLight = 41 | Css.hex "e5e9f0" 42 | 43 | 44 | greyLighter : Css.Color 45 | greyLighter = 46 | Css.hex "eceff4" 47 | 48 | 49 | blue : Css.Color 50 | blue = 51 | Css.hex "88c0d0" 52 | 53 | 54 | blueLight : Css.Color 55 | blueLight = 56 | Css.hex "8fbcbb" 57 | 58 | 59 | blueLighter : Css.Color 60 | blueLighter = 61 | Css.hex "e8f1f1" 62 | 63 | 64 | blueDark : Css.Color 65 | blueDark = 66 | Css.hex "81a1c1" 67 | 68 | 69 | blueDarker : Css.Color 70 | blueDarker = 71 | Css.hex "5e81ac" 72 | 73 | 74 | white : Css.Color 75 | white = 76 | Css.hex "ffffff" 77 | -------------------------------------------------------------------------------- /src/View.elm: -------------------------------------------------------------------------------- 1 | module View exposing 2 | ( View 3 | , map 4 | , none 5 | , toBrowserDocument 6 | ) 7 | 8 | import Assets 9 | import Browser 10 | import Components 11 | import Gen.Route as Route exposing (Route) 12 | import Html.Styled as Html exposing (Html) 13 | import Html.Styled.Attributes as AHtml 14 | import Html.Styled.Events as Html 15 | import Html.Styled.Keyed as HtmlKeyed 16 | import Styles 17 | import Url exposing (Url) 18 | 19 | 20 | type alias View msg = 21 | { title : String 22 | , body : List (Html msg) 23 | } 24 | 25 | 26 | placeholder : String -> View msg 27 | placeholder str = 28 | { title = str 29 | , body = [ Html.text str ] 30 | } 31 | 32 | 33 | none : View msg 34 | none = 35 | placeholder "" 36 | 37 | 38 | map : (a -> b) -> View a -> View b 39 | map fn view = 40 | { title = view.title 41 | , body = List.map (Html.map fn) view.body 42 | } 43 | 44 | 45 | toBrowserDocument : { isHomeRoute : Bool, showSidebar : Bool, onShowSidebarClick : msg, url : Url } -> View msg -> Browser.Document msg 46 | toBrowserDocument { isHomeRoute, showSidebar, onShowSidebarClick, url } view = 47 | { title = view.title ++ " | elm-css patterns" 48 | , body = 49 | [ Html.div 50 | [ AHtml.css Styles.mainContent 51 | , AHtml.id "main" 52 | , AHtml.classList 53 | [ ( "main-top", isHomeRoute ) 54 | , ( "show-sidebar", showSidebar ) 55 | ] 56 | ] 57 | [ navbar onShowSidebarClick 58 | , Html.div 59 | [ AHtml.class "main-content__body" ] 60 | [ Html.div 61 | [ AHtml.class "container" ] 62 | [ sidebar onShowSidebarClick showSidebar url 63 | , Html.div 64 | [ AHtml.class "inner" ] 65 | view.body 66 | ] 67 | ] 68 | , footer 69 | ] 70 | ] 71 | |> List.map Html.toUnstyled 72 | } 73 | 74 | 75 | footer : Html msg 76 | footer = 77 | Html.footer 78 | [ AHtml.class "main-content__footer" ] 79 | [ Html.div 80 | [ AHtml.class "container" ] 81 | [ Html.p 82 | [] 83 | [ Html.text "Crafted with ❤ and " 84 | , Html.a 85 | [ AHtml.href "https://elm-lang.org/" 86 | , AHtml.target "_blank" 87 | , AHtml.class "cool" 88 | ] 89 | [ Html.text "elm" ] 90 | , Html.text " by " 91 | , Html.a 92 | [ AHtml.href "https://github.com/bigardone" 93 | , AHtml.target "_blank" 94 | , AHtml.class "cool" 95 | ] 96 | [ Html.text "bigardone" ] 97 | , Html.text ". Powered by " 98 | , Html.a 99 | [ AHtml.href "https://github.com/ryannhg/elm-spa" 100 | , AHtml.target "_blank" 101 | , AHtml.class "cool" 102 | ] 103 | [ Html.text " elm-spa" ] 104 | , Html.text ". Inspired by " 105 | , Html.a 106 | [ AHtml.href "https://github.com/phuoc-ng/csslayout" 107 | , AHtml.target "_blank" 108 | , AHtml.class "cool" 109 | ] 110 | [ Html.text " csslayout" ] 111 | , Html.text "." 112 | ] 113 | ] 114 | ] 115 | 116 | 117 | navbar : msg -> Html msg 118 | navbar onShowSidebarClick = 119 | Html.nav 120 | [ AHtml.class "main-content__nav" ] 121 | [ Html.div 122 | [ AHtml.class "container" ] 123 | [ Html.div 124 | [ AHtml.class "" ] 125 | [ Html.a 126 | [ AHtml.class "logo" 127 | , AHtml.href (Route.toHref Route.Home_) 128 | ] 129 | [ Html.text "elm-css patterns" ] 130 | ] 131 | , Html.div 132 | [] 133 | [ Html.a 134 | [ AHtml.href "https://github.com/bigardone/elm-css-patterns" 135 | , AHtml.target "_blank" 136 | ] 137 | [ Assets.githubIcon ] 138 | , Html.span 139 | [ AHtml.class "burger" 140 | , Html.onClick onShowSidebarClick 141 | ] 142 | [ Assets.barsIcon ] 143 | ] 144 | ] 145 | ] 146 | 147 | 148 | sidebar : msg -> Bool -> Url -> Html msg 149 | sidebar onShowSidebarClick showSidebar url = 150 | Html.aside 151 | [ AHtml.classList 152 | [ ( "main-content__sidebar", True ) 153 | , ( "show", showSidebar ) 154 | ] 155 | ] 156 | [ Html.nav 157 | [ AHtml.class "main-nav" ] 158 | [ Html.span 159 | [ AHtml.class "close" 160 | , Html.onClick onShowSidebarClick 161 | ] 162 | [ Assets.closeIcon ] 163 | , mainNavSection "Layout" Components.layoutNavItems Route.Layout url 164 | , mainNavSection "Navigation" Components.navigationNavItems Route.Navigation url 165 | , mainNavSection "Input" Components.inputNavItems Route.Input url 166 | , mainNavSection "Feedback" Components.feedbackNavItems Route.Feedback url 167 | , mainNavSection "Misc" Components.miscNavItems Route.Misc url 168 | ] 169 | ] 170 | 171 | 172 | mainNavSection : String -> List ( Route, String ) -> Route -> Url -> Html msg 173 | mainNavSection title navItems route url = 174 | Html.div 175 | [ AHtml.class "main-nav__section" ] 176 | [ Html.header 177 | [ AHtml.class "main-nav__header" ] 178 | [ Html.a 179 | [ AHtml.href <| Route.toHref route ] 180 | [ Html.text title ] 181 | ] 182 | , nav navItems url 183 | ] 184 | 185 | 186 | nav : List ( Route, String ) -> Url -> Html msg 187 | nav items url = 188 | items 189 | |> List.map (navItem url) 190 | |> HtmlKeyed.ul [ AHtml.class "list" ] 191 | 192 | 193 | navItem : Url -> ( Route, String ) -> ( String, Html msg ) 194 | navItem url ( route, text ) = 195 | let 196 | active = 197 | Route.fromUrl url == route 198 | in 199 | ( text 200 | , Html.li 201 | [] 202 | [ Html.a 203 | [ AHtml.href <| Route.toHref route 204 | , AHtml.classList [ ( "active", active ) ] 205 | ] 206 | [ Html.text text ] 207 | ] 208 | ) 209 | --------------------------------------------------------------------------------