From ef5c6dae82f2a781859fb314098007b99c51421c Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:52:38 +0000 Subject: [PATCH 01/82] v2.1.3.dev improvements rssfoto newsfeeds for J4,J5 --- README.md | 3 +- css/template.css | 1165 ++++++++++++++++++++++++++++++++++++++- scss/_template_css.scss | 148 +++-- templateDetails.xml | 4 +- 4 files changed, 1233 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index faf9445..900cb19 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,5 @@ This project is licensed under the [GNU GPL], version 3 or later. 2018 – 2021 © [Bram Waasdorp](http://www.waasdorpsoekhan.nl). ## Changelog -* 2.1.2 removed hard returns from documentation field because j4.4 + doesn't accept that. \ No newline at end of file +* 2.1.3.dev improvements rssfoto newsfeeds for J4,J5 +* 2.1.2 removed hard returns from documentation field because j4.4 + doesn't accept that. diff --git a/css/template.css b/css/template.css index 090735f..ceaf4d6 100644 --- a/css/template.css +++ b/css/template.css @@ -1 +1,1164 @@ -.mfp-bg{top:0;left:0;width:100%;height:100%;z-index:1042;overflow:hidden;position:fixed;background:#0b0b0b;opacity:0.8}.mfp-wrap{top:0;left:0;width:100%;height:100%;z-index:1043;position:fixed;outline:none !important;-webkit-backface-visibility:hidden}.mfp-container{text-align:center;position:absolute;width:100%;height:100%;left:0;top:0;padding:0 8px;box-sizing:border-box}.mfp-container:before{content:'';display:inline-block;height:100%;vertical-align:middle}.mfp-align-top .mfp-container:before{display:none}.mfp-content{position:relative;display:inline-block;vertical-align:middle;margin:0 auto;text-align:left;z-index:1045}.mfp-inline-holder .mfp-content,.mfp-ajax-holder .mfp-content{width:100%;cursor:auto}.mfp-ajax-cur{cursor:progress}.mfp-zoom-out-cur,.mfp-zoom-out-cur .mfp-image-holder .mfp-close{cursor:-moz-zoom-out;cursor:-webkit-zoom-out;cursor:zoom-out}.mfp-zoom{cursor:pointer;cursor:-webkit-zoom-in;cursor:-moz-zoom-in;cursor:zoom-in}.mfp-auto-cursor .mfp-content{cursor:auto}.mfp-close,.mfp-arrow,.mfp-preloader,.mfp-counter{-webkit-user-select:none;-moz-user-select:none;user-select:none}.mfp-loading.mfp-figure{display:none}.mfp-hide{display:none !important}.mfp-preloader{color:#ccc;position:absolute;top:50%;width:auto;text-align:center;margin-top:-0.8em;left:8px;right:8px;z-index:1044}.mfp-preloader a{color:#ccc}.mfp-preloader a:hover{color:#fff}.mfp-s-ready .mfp-preloader{display:none}.mfp-s-error .mfp-content{display:none}button.mfp-close,button.mfp-arrow{overflow:visible;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;display:block;outline:none;padding:0;z-index:1046;box-shadow:none;touch-action:manipulation}button::-moz-focus-inner{padding:0;border:0}.mfp-close{width:44px;height:44px;line-height:44px;position:absolute;right:0;top:0;text-decoration:none;text-align:center;padding:0 0 18px 10px;font-style:normal;font-size:28px;font-family:Arial, Baskerville, monospace}.mfp-close:hover,.mfp-close:focus{opacity:1}.mfp-close:active{top:1px}.mfp-close-btn-in .mfp-close{color:#333}.mfp-image-holder .mfp-close,.mfp-iframe-holder .mfp-close{color:#fff;right:-6px;text-align:right;padding-right:6px;width:100%}.mfp-counter{position:absolute;top:0;right:0;color:#ccc;font-size:12px;line-height:18px;white-space:nowrap}.mfp-arrow{position:absolute;opacity:0.65;margin:0;top:50%;margin-top:-55px;padding:0;width:90px;height:110px;-webkit-tap-highlight-color:transparent}.mfp-arrow:active{margin-top:-54px}.mfp-arrow:hover,.mfp-arrow:focus{opacity:1}.mfp-arrow:before,.mfp-arrow:after{content:'';display:block;width:0;height:0;position:absolute;left:0;top:0;margin-top:35px;margin-left:35px;border:medium inset transparent}.mfp-arrow:after{border-top-width:13px;border-bottom-width:13px;top:8px}.mfp-arrow:before{border-top-width:21px;border-bottom-width:21px;opacity:0.7}.mfp-arrow-left{left:0}.mfp-arrow-left:after{border-right:17px solid #fff;margin-left:31px}.mfp-arrow-left:before{margin-left:25px;border-right:27px solid #3f3f3f}.mfp-arrow-right{right:0}.mfp-arrow-right:after{border-left:17px solid #fff;margin-left:39px}.mfp-arrow-right:before{border-left:27px solid #3f3f3f}.mfp-iframe-holder{padding-top:40px;padding-bottom:40px}.mfp-iframe-holder .mfp-content{line-height:0;width:100%;max-width:900px}.mfp-iframe-holder .mfp-close{top:-40px}.mfp-iframe-scaler{width:100%;height:0;overflow:hidden;padding-top:56.25%}.mfp-iframe-scaler iframe{position:absolute;display:block;top:0;left:0;width:100%;height:100%;box-shadow:0 0 8px rgba(0, 0, 0, 0.6);background:#000}img.mfp-img{width:auto;max-width:100%;height:auto;display:block;line-height:0;box-sizing:border-box;padding:40px 0 40px;margin:0 auto}.mfp-figure{line-height:0}.mfp-figure:after{content:'';position:absolute;left:0;top:40px;bottom:40px;display:block;right:0;width:auto;height:auto;z-index:-1;box-shadow:0 0 8px rgba(0, 0, 0, 0.6);background:#444}.mfp-figure small{color:#bdbdbd;display:block;font-size:12px;line-height:14px}.mfp-figure figure{margin:0}.mfp-bottom-bar{margin-top:-36px;position:absolute;top:100%;left:0;width:100%;cursor:auto}.mfp-title{text-align:left;line-height:18px;color:#f3f3f3;word-wrap:break-word;padding-right:36px}.mfp-image-holder .mfp-content{max-width:100%}.mfp-gallery .mfp-image-holder .mfp-figure{cursor:pointer}@media screen and (max-width:800px) and (orientation:landscape),screen and (max-height:300px){.mfp-img-mobile .mfp-image-holder{padding-left:0;padding-right:0}.mfp-img-mobile img.mfp-img{padding:0}.mfp-img-mobile .mfp-figure:after{top:0;bottom:0}.mfp-img-mobile .mfp-figure small{display:inline;margin-left:5px}.mfp-img-mobile .mfp-bottom-bar{background:rgba(0, 0, 0, 0.6);bottom:0;margin:0;top:auto;padding:3px 5px;position:fixed;box-sizing:border-box}.mfp-img-mobile .mfp-bottom-bar:empty{padding:0}.mfp-img-mobile .mfp-counter{right:5px;top:3px}.mfp-img-mobile .mfp-close{top:0;right:0;width:35px;height:35px;line-height:35px;background:rgba(0, 0, 0, 0.6);position:fixed;text-align:center;padding:0}}@media all and (max-width:900px){.mfp-arrow{-webkit-transform:scale(0.75);transform:scale(0.75)}.mfp-arrow-left{-webkit-transform-origin:0;transform-origin:0}.mfp-arrow-right{-webkit-transform-origin:100%;transform-origin:100%}.mfp-container{padding-left:6px;padding-right:6px}}.mfp-bg{background:#000;opacity:0.6}.mfp-iframe-scaler button.mfp-close,.mfp-image-holder button.mfp-close,.mfp-container button.mfp-close{background:url(../images/magnificpopup/closebox.png) no-repeat right;height:32px;width:32px;line-height:10px;top:9px;right:5px;padding-right:5px}.mfp-image-holder figure{margin:0 20px}div.mfp-figure:after{display:none}.mfp-iframe-scaler iframe,.mfp-image-holder img.mfp-img{margin:24px auto;padding:10px 10px;background:white;border-radius:3px;box-shadow:0 0 8px rgba(0, 0, 0, 0.6)}div.mfp-iframe-scaler button.mfp-close{right:-15px}.mfp-title{margin-left:20px}.mfp-bottom-bar{margin-top:-24px}body.modal{display:block;position:static;overflow:auto}#img_brandImage{width:auto}.navbar-default{background-color:#f8f8f8;border-color:#e7e7e7;background-image:-webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);background-image:-o-linear-gradient(top, #fff 0%, #f8f8f8 100%);background-image:linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFFFFFFF", endColorstr="#FFF8F8F8", GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075)}.navbar-default .navbar-brand{color:#777}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#5e5e5e;background-color:transparent}.navbar-default .navbar-text{color:#777}.navbar-default .navbar-nav > li > a{color:#777}.navbar-default .navbar-nav > li > a:hover,.navbar-default .navbar-nav > li > a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav > .active > a,.navbar-default .navbar-nav > .active > a:hover,.navbar-default .navbar-nav > .active > a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav > .disabled > a,.navbar-default .navbar-nav > .disabled > a:hover,.navbar-default .navbar-nav > .disabled > a:focus{color:#ccc;background-color:transparent}.navbar-default .navbar-toggle{border-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#777}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#ddd}.navbar-default .navbar-toggle .icon-bar{background-color:#888}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#e7e7e7}.navbar-default .navbar-nav > .open > a,.navbar-default .navbar-nav > .open > a:hover,.navbar-default .navbar-nav > .open > a:focus{background-color:#e7e7e7;color:#555}@media (max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu > li > a{color:#777}.navbar-default .navbar-nav .open .dropdown-menu > li > a:hover,.navbar-default .navbar-nav .open .dropdown-menu > li > a:focus{color:#333;background-color:transparent}.navbar-default .navbar-nav .open .dropdown-menu > .active > a,.navbar-default .navbar-nav .open .dropdown-menu > .active > a:hover,.navbar-default .navbar-nav .open .dropdown-menu > .active > a:focus{color:#555;background-color:#e7e7e7}.navbar-default .navbar-nav .open .dropdown-menu > .disabled > a,.navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:hover,.navbar-default .navbar-nav .open .dropdown-menu > .disabled > a:focus{color:#ccc;background-color:transparent}}.navbar-default .navbar-link{color:#777}.navbar-default .navbar-link:hover{color:#333}.navbar-default .btn-link{color:#777}.navbar-default .btn-link:hover,.navbar-default .btn-link:focus{color:#333}.navbar-default .btn-link[disabled]:hover,fieldset[disabled] .navbar-default .btn-link:hover,.navbar-default .btn-link[disabled]:focus,fieldset[disabled] .navbar-default .btn-link:focus{color:#ccc}.navbar-default .navbar-nav > .open > a,.navbar-default .navbar-nav > .active > a{background-image:-webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);background-image:-o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);background-image:linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr="#FFDADADA", endColorstr="#FFE2E2E2", GradientType=0);-webkit-box-shadow:inset 0 3px 9px rgba(0, 0, 0, .075);box-shadow:inset 0 3px 9px rgba(0, 0, 0, .075)}.navbar-brand,.navbar-nav > li > a{text-shadow:0 1px 0 rgba(255, 255, 255, .25)}.dropdown-menu{background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, .15)}.dropdown-menu > li > a{clear:both;color:#333;display:block;font-weight:normal;line-height:20px;padding:3px 20px;white-space:nowrap}.dropdown-menu > .active > a,.dropdown-menu > .active > a:hover,.dropdown-menu > .active > a:focus{background-color:#e5e5e5;background-image:none;background-repeat:repeat-x;color:#555;outline:0 none;text-decoration:none}.dropdown-menu > li > a:hover,.dropdown-menu > li > a:focus,.dropdown-submenu:hover > a,.dropdown-submenu:focus > a{background-color:#e5e5e5;background-image:none;background-repeat:repeat-x;color:#555;text-decoration:none}.nav-collapse .nav > li > a,.nav-collapse .dropdown-menu a{border-radius:3px;color:#777;font-weight:bold;padding:9px 15px}.nav-collapse .nav > li > a:hover,.nav-collapse .dropdown-menu a:hover,.nav-collapse .nav > li > a:focus,.nav-collapse .dropdown-menu a:focus{background-color:#e5e5e5}.dropdown-submenu{position:relative;}.dropdown-submenu > .dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px}.dropdown-submenu:hover > .dropdown-menu{display:block}.dropdown-submenu > a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#555;margin-top:5px;margin-right:-10px}.dropdown-submenu:hover > a:after{border-left-color:#555}.dropdown-submenu.pull-left{float:none}.dropdown-submenu.pull-left > .dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px}.nav > li > a:hover,.nav > li > a:focus{text-decoration:none;background-color:#eee}.nav > li.disabled > a{color:#777}.nav > li.disabled > a:hover,.nav > li.disabled > a:focus{color:#777;text-decoration:none;background-color:transparent;cursor:not-allowed}.nav .open > a,.nav .open > a:hover,.nav .open > a:focus{background-color:#eee;border-color:#337ab7}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs > li{float:left;margin-bottom:-1px}.nav-tabs > li > a{margin-right:2px;line-height:1.42857;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs > li > a:hover{border-color:#eee #eee #ddd}.nav-tabs > li.active > a,.nav-tabs > li.active > a:hover,.nav-tabs > li.active > a:focus{color:#555;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default}.nav-pills > li{float:left}.nav-pills > li > a{border-radius:4px}.nav-pills > li + li{margin-left:2px}.nav-pills > li.active > a,.nav-pills > li.active > a:hover,.nav-pills > li.active > a:focus{color:#fff;background-color:#337ab7}@media (min-width:768px){.sidebar-nav .navbar .navbar-collapse{padding:0;max-height:none}.sidebar-nav .navbar ul{float:none}.sidebar-nav .navbar ul:not{display:block}.sidebar-nav .navbar li{float:none;display:block}.sidebar-nav .navbar li a{padding-top:12px;padding-bottom:12px}}@media (min-width:768px){.nav-pills > li > a,.dropdown-menu{margin:0}.nav-pills > li.dropdown:hover ul.dropdown-menu,.nav-tabs > li.dropdown:hover ul.dropdown-menu{display:block}.nav-pills > li.dropdown ul.dropdown-menu .dropdown-submenu .dropdown-menu,.nav-tabs > li.dropdown ul.dropdown-menu .dropdown-submenu .dropdown-menu{display:none}.nav-pills > li.dropdown ul.dropdown-menu .dropdown-submenu:hover .dropdown-menu,.nav-tabs > li.dropdown ul.dropdown-menu .dropdown-submenu:hover .dropdown-menu{display:block}}@media (max-width:767px){.nav-tabs > li{float:none}.nav-tabs > .active > a,.nav-tabs > .active > a:hover{border:none}.dropdown,.dropdown-submenu{display:block;position:static;float:none}.dropdown-menu{position:static;float:none}.open .nav-child.dropdown-menu{display:block;background-color:transparent;border:none;border-radius:0;box-shadow:none}.nav-child.dropdown-menu{padding:0}.nav-child.small{font-size:13px}.dropdown-menu > li > a{padding:8px 12px 8px 20px}.nav > li.active > a,.nav > li.active > a:hover,.nav > li.active > a:focus{background-color:#999;color:#fff}.nav li.dropdown.active .caret,.nav li.dropdown.active a:hover .caret,.nav li.dropdown.active a:focus .caret{border-bottom-color:#fff;border-top-color:#fff}.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav > li.dropdown.open.active > a:hover,.nav > li.dropdown.open.active > a:focus{border:none}}#img_bg0Image{position:absolute;width:80px;left:10%;padding-top:10%;}#img_bg1Image{position:absolute;width:80%;left:50%;padding-top:auto;}#img_bg2Image{position:absolute;width:10%;left:80%;padding-top:10%;}#headerleft{position:relative;float:left;width:25%;height:0px;margin-top:1%;margin-left:0%;margin-bottom:0%;padding-top:0;padding-bottom:25%}#headerleft div.inner{position:absolute;top:0;left:0;width:100%;height:100%}#icons{position:absolute;top:0%;left:75%;width:24.5%}#wrapper,body > div.container{position:relative;overflow-x:hidden;border-radius:10px}#wrapper1{position:relative}.blog,.blog-featured,.contentpane,.contact,.item-page,.tag-category,div.newsfeed,div[class^="newsfeed"]{}.icon-cog,.icons .icon-cog{background-position:-432px 0}.img-fluid,.img-fluid-w33,.img-fluid-w50{max-width:100%;height:auto}.items-leading div .videoWrapper,.videoWrapper{position:relative;padding-bottom:56.25%;padding-top:25px;width:100%;height:0}.items-leading div .videoWrapper object,.videoWrapper object,.items-leading div .videoWrapper embed,.videoWrapper embed,.items-leading div .videoWrapper iframe,.videoWrapper iframe{position:absolute;top:0;left:0;width:100%;height:100%}.list-striped,.row-striped{border-top:none}.list-striped li,.list-striped dd,.row-striped .row,.row-striped .row-fluid{border-bottom:none;padding:0}.mod-languages{float:right}.navbar-collapse.in{overflow-y:visible}.navbar-toggle .icon-bar{background-color:#888}.newsfeed_rssfoto,.newsfeed_rssfoto01,.newsfeed_rsspicasa,div[class^="newsfeed"]{margin:0;padding:0;width:auto;}.newsfeed_rssfoto h2,.newsfeed_rssfoto01 h2,.newsfeed_rsspicasa h2,div[class^="newsfeed"] h2{margin:0;font-weight:bold;font-family:Helvetica, Arial, sans-serif;font-size:1.5em;padding-left:0px;margin-bottom:10px;text-align:left}.newsfeed_rssfoto h3,.newsfeed_rssfoto01 h3,.newsfeed_rsspicasa h3,div[class^="newsfeed"] h3{font-size:1.3em;line-height:1.3em;padding-left:0px;margin-bottom:0px;text-align:left}.newsfeed_rssfoto ol,.newsfeed_rssfoto01 ol,.newsfeed_rsspicasa ol,div[class^="newsfeed"] ol{padding:0}.newsfeed_rssfoto ol li,.newsfeed_rssfoto01 ol li,.newsfeed_rsspicasa ol li,div[class^="newsfeed"] ol li{list-style-type:none;margin-left:0;margin-right:10px;margin-bottom:10px}.newsfeed_rssfoto,.newsfeed_rssfoto01,.newsfeed_rsspicasa{}.newsfeed_rssfoto ol li,.newsfeed_rssfoto01 ol li,.newsfeed_rsspicasa ol li{float:left;height:320px;width:250px;overflow:hidden}.newsfeed_rssfoto ol li a img,.newsfeed_rsspicasa ol li a img{background-color:#6f571b;padding:2px;border:3px solid black;}.newsfeed_rssfoto ol li div.feed-item-description p:first-child,.newsfeed_rssfoto01 ol li div.feed-item-description p:first-child{font-size:4%;color:transparent}.newsfeed_rssfoto ol li div.feed-item-description p:first-child a,.newsfeed_rssfoto01 ol li div.feed-item-description p:first-child a{font-size:2500%;color:#337ab7}.newsfeed_rssfoto01 ol li{background-color:#ccc}.newsfeed_rssfoto01 ol li a img{padding:5px}.newsfeed_rsspicasa ol li{height:210px;background-color:#ccc}.tag-category fieldset{display:none}.tag-category ul{padding-left:0}.tag-category ul li{display:inline-block;position:static;vertical-align:top;max-width:100%;margin-right:1%;margin-bottom:1%}.tag-category ul.category.list-striped li{background-color:transparent;max-width:100%;width:256px}.tag-category ul li h3{display:none}body{font-family:Verdana, Arial, sans-serif;padding-top:10px;padding-bottom:40px;overflow:auto}div.pagination{margin-top:0px;width:100%}div.pagination p{margin-top:20px}div div.pagination ul{padding-left:0px}div div.pagination ul li{display:inline-block;position:static;vertical-align:top;max-width:100%;margin-right:0px;margin-bottom:0px}h1,h2,h3,h4,h5,h6{font-family:'Open Sans Condensed', sans-serif;font-weight:700}h1{font-size:30px;line-height:34px}h2{font-size:26px;line-height:30px}h3{font-size:22px;line-height:26px}h4{font-size:18px;line-height:20px}h5{font-size:14px;line-height:20px}h6{font-size:12px;line-height:20px}[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;margin-top:1px;line-height:14px;vertical-align:text-top;background-image:url("../img/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat}[class*="special"] .module-content ul{margin:0 0 10px 17px}[class*="special"] .module-content ul.unstyled{margin:0 0 10px 0}@media (max-width:767px){}@media (min-width:480px){.img-fluid-w33{max-width:33%}.img-fluid-w50{max-width:50%}.tag-category ul li{max-width:30%;width:auto}.tag-category ul.category.list-striped li{max-width:30%;width:auto}}@media (min-width:768px){.form-horizontal .control-group .control-label{text-align:left}}body{background-image:none;background-size:contain;background-repeat:no-repeat;background-position:10% 10%}#wrapper,body > div.container{background-color:#eee;background-image:none, none;background-size:80%;background-repeat:no-repeat, no-repeat;background-position:50%} \ No newline at end of file +/* variables.scss */ +/* mixins/reset-filter.scss */ +/* mixins/Gradients.scss */ +/* magnificpopup.variables.scss */ +/* template_variables.scss */ +/* uit asha-s */ +/* magnificpopup.scss */ +.mfp-bg { + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1042; + overflow: hidden; + position: fixed; + background: #0b0b0b; + opacity: 0.8; + filter: alpha(opacity=80); +} +.mfp-wrap { + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 1043; + position: fixed; + outline: none !important; + -webkit-backface-visibility: hidden; +} +.mfp-container { + text-align: center; + position: absolute; + width: 100%; + height: 100%; + left: 0; + top: 0; + padding: 0 8px; + box-sizing: border-box; +} +.mfp-container:before { + content: ''; + display: inline-block; + height: 100%; + vertical-align: middle; +} +.mfp-align-top .mfp-container:before { + display: none; +} +.mfp-content { + position: relative; + display: inline-block; + vertical-align: middle; + margin: 0 auto; + text-align: left; + z-index: 1045; +} +.mfp-inline-holder .mfp-content, .mfp-ajax-holder .mfp-content { + width: 100%; + cursor: auto; +} +.mfp-ajax-cur { + cursor: progress; +} +.mfp-zoom-out-cur, .mfp-zoom-out-cur .mfp-image-holder .mfp-close { + cursor: -moz-zoom-out; + cursor: -webkit-zoom-out; + cursor: zoom-out; +} +.mfp-zoom { + cursor: pointer; + cursor: -webkit-zoom-in; + cursor: -moz-zoom-in; + cursor: zoom-in; +} +.mfp-auto-cursor .mfp-content { + cursor: auto; +} +.mfp-close, .mfp-arrow, .mfp-preloader, .mfp-counter { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.mfp-loading.mfp-figure { + display: none; +} +.mfp-hide { + display: none !important; +} +.mfp-preloader { + color: #ccc; + position: absolute; + top: 50%; + width: auto; + text-align: center; + margin-top: -0.8em; + left: 8px; + right: 8px; + z-index: 1044; +} +.mfp-preloader a { + color: #ccc; +} +.mfp-preloader a:hover { + color: #fff; +} +.mfp-s-ready .mfp-preloader { + display: none; +} +.mfp-s-error .mfp-content { + display: none; +} +button.mfp-close, button.mfp-arrow { + overflow: visible; + cursor: pointer; + background: transparent; + border: 0; + -webkit-appearance: none; + display: block; + outline: none; + padding: 0; + z-index: 1046; + box-shadow: none; + touch-action: manipulation; +} +button::-moz-focus-inner { + padding: 0; + border: 0; +} +.mfp-close { + width: 44px; + height: 44px; + line-height: 44px; + position: absolute; + right: 0; + top: 0; + text-decoration: none; + text-align: center; + opacity: 1; + filter: alpha(opacity=100); + padding: 0 0 18px 10px; + font-style: normal; + font-size: 28px; + font-family: Arial, Baskerville, monospace; +} +.mfp-close:hover, .mfp-close:focus { + opacity: 1; + filter: alpha(opacity=100); +} +.mfp-close:active { + top: 1px; +} +.mfp-close-btn-in .mfp-close { + color: #333; +} +.mfp-image-holder .mfp-close, .mfp-iframe-holder .mfp-close { + color: #fff; + right: -6px; + text-align: right; + padding-right: 6px; + width: 100%; +} +.mfp-counter { + position: absolute; + top: 0; + right: 0; + color: #ccc; + font-size: 12px; + line-height: 18px; + white-space: nowrap; +} +.mfp-arrow { + position: absolute; + opacity: 0.65; + filter: alpha(opacity=65); + margin: 0; + top: 50%; + margin-top: -55px; + padding: 0; + width: 90px; + height: 110px; + -webkit-tap-highlight-color: transparent; +} +.mfp-arrow:active { + margin-top: -54px; +} +.mfp-arrow:hover, .mfp-arrow:focus { + opacity: 1; + filter: alpha(opacity=100); +} +.mfp-arrow:before, .mfp-arrow:after { + content: ''; + display: block; + width: 0; + height: 0; + position: absolute; + left: 0; + top: 0; + margin-top: 35px; + margin-left: 35px; + border: medium inset transparent; +} +.mfp-arrow:after { + border-top-width: 13px; + border-bottom-width: 13px; + top: 8px; +} +.mfp-arrow:before { + border-top-width: 21px; + border-bottom-width: 21px; + opacity: 0.7; + filter: alpha(opacity=70); +} +.mfp-arrow-left { + left: 0; +} +.mfp-arrow-left:after { + border-right: 17px solid #fff; + margin-left: 31px; +} +.mfp-arrow-left:before { + margin-left: 25px; + border-right: 27px solid #3f3f3f; +} +.mfp-arrow-right { + right: 0; +} +.mfp-arrow-right:after { + border-left: 17px solid #fff; + margin-left: 39px; +} +.mfp-arrow-right:before { + border-left: 27px solid #3f3f3f; +} +.mfp-iframe-holder { + padding-top: 40px; + padding-bottom: 40px; +} +.mfp-iframe-holder .mfp-content { + line-height: 0; + width: 100%; + max-width: 900px; +} +.mfp-iframe-holder .mfp-close { + top: -40px; +} +.mfp-iframe-scaler { + width: 100%; + height: 0; + overflow: hidden; + padding-top: 56.25%; +} +.mfp-iframe-scaler iframe { + position: absolute; + display: block; + top: 0; + left: 0; + width: 100%; + height: 100%; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); + background: #000; +} +/* Main image in popup */ +img.mfp-img { + width: auto; + max-width: 100%; + height: auto; + display: block; + line-height: 0; + box-sizing: border-box; + padding: 40px 0 40px; + margin: 0 auto; +} +/* The shadow behind the image */ +.mfp-figure { + line-height: 0; +} +.mfp-figure:after { + content: ''; + position: absolute; + left: 0; + top: 40px; + bottom: 40px; + display: block; + right: 0; + width: auto; + height: auto; + z-index: -1; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); + background: #444; +} +.mfp-figure small { + color: #bdbdbd; + display: block; + font-size: 12px; + line-height: 14px; +} +.mfp-figure figure { + margin: 0; +} +.mfp-bottom-bar { + margin-top: -36px; + position: absolute; + top: 100%; + left: 0; + width: 100%; + cursor: auto; +} +.mfp-title { + text-align: left; + line-height: 18px; + color: #f3f3f3; + word-wrap: break-word; + padding-right: 36px; +} +.mfp-image-holder .mfp-content { + max-width: 100%; +} +.mfp-gallery .mfp-image-holder .mfp-figure { + cursor: pointer; +} +@media screen and (max-width: 800px) and (orientation: landscape), screen and (max-height: 300px) { + /** + * Remove all paddings around the image on small screen + */ + .mfp-img-mobile .mfp-image-holder { + padding-left: 0; + padding-right: 0; + } + .mfp-img-mobile img.mfp-img { + padding: 0; + } + .mfp-img-mobile .mfp-figure:after { + top: 0; + bottom: 0; + } + .mfp-img-mobile .mfp-figure small { + display: inline; + margin-left: 5px; + } + .mfp-img-mobile .mfp-bottom-bar { + background: rgba(0, 0, 0, 0.6); + bottom: 0; + margin: 0; + top: auto; + padding: 3px 5px; + position: fixed; + box-sizing: border-box; + } + .mfp-img-mobile .mfp-bottom-bar:empty { + padding: 0; + } + .mfp-img-mobile .mfp-counter { + right: 5px; + top: 3px; + } + .mfp-img-mobile .mfp-close { + top: 0; + right: 0; + width: 35px; + height: 35px; + line-height: 35px; + background: rgba(0, 0, 0, 0.6); + position: fixed; + text-align: center; + padding: 0; + } +} +@media all and (max-width: 900px) { + .mfp-arrow { + -webkit-transform: scale(0.75); + transform: scale(0.75); + } + .mfp-arrow-left { + -webkit-transform-origin: 0; + transform-origin: 0; + } + .mfp-arrow-right { + -webkit-transform-origin: 100%; + transform-origin: 100%; + } + .mfp-container { + padding-left: 6px; + padding-right: 6px; + } +} +/* added bram waasdorp 2060403 */ +.mfp-bg { + background: #000; + opacity: 0.6; +} +.mfp-iframe-scaler button.mfp-close, .mfp-image-holder button.mfp-close, .mfp-container button.mfp-close { + background: url(../images/magnificpopup/closebox.png) no-repeat right; + height: 32px; + width: 32px; + line-height: 10px; + top: 9px; + /* must be the same as margin top of image - 15 */ + right: 5px; + /* must be the same as margin right of figure - 15 */ + padding-right: 5px; + color: transparent; +} +.mfp-image-holder figure { + margin: 0 20px; +} +div.mfp-figure:after { + display: none; +} +.mfp-iframe-scaler iframe, .mfp-image-holder img.mfp-img { + margin: 24px auto; + padding: 10px 10px; + background: white; + border-radius: 3px; + box-shadow: 0 0 8px rgba(0, 0, 0, 0.6); + max-height: calc(100vh - 48px); + /* work-around voor niet (goed) werken verticalFit in gallery */ +} +div.mfp-iframe-scaler button.mfp-close { + right: -15px; +} +.mfp-title { + margin-left: 20px; +} +.mfp-bottom-bar { + /* must be the same as margin bottom of image (36px title max 2 lines then slider can come in) */ + margin-top: -24px; +} +/* modal weer zichtbaar maken in iframe popup + voorbeeld + + */ +body.modal { + display: block; + position: static; + overflow: auto; +} +/* template_dropdown.scss */ +/* ------------------------------------ + CSS uit template_css.less gehaald om dropdown-menu in joomla goed te laten werken in bootstrap 3 + oa extra CSS voor dropdown-submenu, dat in B2 bestand bestond, maar in B3 vervallen is + 01-5-2016 + 23-5-2016 + 9-6-2016 + 10-2-2019 bs 4 ipv alleen navbar-defualt (bs3) zelfdekleueren voo + 11-2-2019 brandwith relatief tov lg + 28-12-2021 .dropdown-menu > li > a replaced by .dropdown-menu > .nav-item > .nav-link to give it higher priority in BS4 and BS5 + and padding and line-height px value changed to rem value + -----------------------------------------*/ +#img_brandImage { + width: auto * 300 / 960; +} +/* $navbar-theme == navbar-dark */ +/* bs4 navbar-dark */ +.navbar-dark .navbar-brand { + color: #777; +} +.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus { + color: #5e5e5e; +} +.navbar-dark .navbar-nav .nav-link { + color: #777; +} +.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { + color: #333; +} +.navbar-dark .navbar-nav .nav-link.disabled { + color: #ccc; +} +.navbar-dark .navbar-nav .show > .nav-link, .navbar-dark .navbar-nav .active > .nav-link, .navbar-dark .navbar-nav .nav-link.show, .navbar-dark .navbar-nav .nav-link.active { + color: #555; +} +.navbar-dark .navbar-toggler { + color: #777; + border-color: #ddd; +} +.navbar-dark .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} +.navbar-dark .navbar-text { + color: #777; +} +.navbar-dark .navbar-text a { + color: #555; +} +.navbar-dark .navbar-text a:hover, .navbar-dark .navbar-text a:focus { + color: #555; +} +.navbar-brand, .navbar-nav > li > a { + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25); +} +/* ====================== + GENERAL STYLES + ===================== */ +.dropdown-menu { + background-color: #fff; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.15); +} +.dropdown-menu > .nav-item > .nav-link { + clear: both; + color: #333; + display: block; + font-weight: normal; + line-height: 1.1rem; + padding: 0.15rem 1rem; + white-space: nowrap; +} +.dropdown-menu > .active > a, .dropdown-menu > .active > a:hover, .dropdown-menu > .active > a:focus { + background-color: #e5e5e5; + background-image: none; + background-repeat: repeat-x; + color: #555; + outline: 0 none; + text-decoration: none; +} +.dropdown-menu > li > a:hover, .dropdown-menu > li > a:focus, .dropdown-submenu:hover > a, .dropdown-submenu:focus > a { + background-color: #e5e5e5; + background-image: none; + background-repeat: repeat-x; + color: #555; + text-decoration: none; +} +.nav-collapse .nav > li > a, .nav-collapse .dropdown-menu a { + border-radius: 3px; + color: #777; + font-weight: bold; + padding: 9px 15px; +} +.nav-collapse .nav > li > a:hover, .nav-collapse .dropdown-menu a:hover, .nav-collapse .nav > li > a:focus, .nav-collapse .dropdown-menu a:focus { + background-color: #e5e5e5; +} +/* einde gekopieerd uit fire bug to override bootstrap.min.css */ +/* dropdown-submenu werkt standaard niet meer in bootstrap 3 */ +.dropdown-submenu { + position: relative; + /* dropdown-submenu einde */ +} +.dropdown-submenu > .dropdown-menu { + top: 0; + left: 100%; + margin-top: -6px; + margin-left: -1px; + -webkit-border-radius: 0 6px 6px 6px; + -moz-border-radius: 0 6px 6px 6px; + border-radius: 0 6px 6px 6px; +} +.dropdown-submenu:hover > .dropdown-menu { + display: block; +} +.dropdown-submenu > a:after { + display: block; + content: " "; + float: right; + width: 0; + height: 0; + border-color: transparent; + border-style: solid; + border-width: 5px 0 5px 5px; + border-left-color: #555; + margin-top: 5px; + margin-right: -10px; +} +.dropdown-submenu:hover > a:after { + border-left-color: #555; +} +.dropdown-submenu.pull-left { + float: none; +} +.dropdown-submenu.pull-left > .dropdown-menu { + left: -100%; + margin-left: 10px; + -webkit-border-radius: 6px 0 6px 6px; + -moz-border-radius: 6px 0 6px 6px; + border-radius: 6px 0 6px 6px; +} +.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { + color: #333; +} +.nav-tabs .nav-link:focus, .nav-tabs .nav-link:hover { + border-color: #e9ecef #e9ecef #dee2e6; +} +.nav-tabs .nav-link { + border: 1px solid transparent; + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} +.nav > li > a:hover, .nav > li > a:focus { + text-decoration: none; + background-color: #eee; +} +.nav > li.disabled > a { + color: #777; +} +.nav > li.disabled > a:hover, .nav > li.disabled > a:focus { + color: #777; + text-decoration: none; + background-color: transparent; + cursor: not-allowed; +} +.nav .open > a, .nav .open > a:hover, .nav .open > a:focus { + background-color: #eee; + border-color: #337ab7; +} +.nav-tabs { + border-bottom: 1px solid #ddd; +} +.nav-tabs > li { + float: left; + margin-bottom: -1px; +} +.nav-tabs > li > a { + margin-right: 2px; + line-height: 1.428571429; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; +} +.nav-tabs > li > a:hover { + border-color: #eee #eee #ddd; +} +.nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus { + color: #555; + background-color: #fff; + border: 1px solid #ddd; + border-bottom-color: transparent; + cursor: default; +} +.nav-pills > li { + float: left; +} +.nav-pills > li > a { + border-radius: 4px; +} +.nav-pills > li + li { + margin-left: 2px; +} +.nav-pills > li.active > a, .nav-pills > li.active > a:hover, .nav-pills > li.active > a:focus { + color: #fff; + background-color: #337ab7; +} +/* =================================================================================== + BOOTSTRAP MEDIA QUERIES OVERRIDES + NOTE: The order of the media queries is important when styles overwrite each other + ================================================================================== + */ +/* make sidebar nav vertical */ +/* from http://www.jonathanbriehl.com/2014/01/17/vertical-menu-for-bootstrap-3/ + At a resolution of 768px or greater you see vertical menu in one of my two main columns. + When scaled down to less than 768px, the menu collapses and works just like the normal theme menu. + I only made one small addition to the standard HTML – I added a container div around the menu with a class called “sidebar-navâ€�. + (In joomla kan je deze wellicht als menu-class, of module-class meegeven) + */ +@media (min-width: 768px) { + .sidebar-nav .navbar .navbar-collapse { + padding: 0; + max-height: none; + } + .sidebar-nav .navbar ul { + float: none; + } + .sidebar-nav .navbar ul:not { + display: block; + } + .sidebar-nav .navbar li { + float: none; + display: block; + } + .sidebar-nav .navbar li a { + padding-top: 12px; + padding-bottom: 12px; + } +} +/* einde make sidebar nav vertical */ +@media (min-width: 768px) { + /* Activates hovering the main items to show the sub items */ + .nav-pills > li > a, .dropdown-menu { + margin: 0; + } + .nav-pills > li.dropdown:hover ul.dropdown-menu, .nav-tabs > li.dropdown:hover ul.dropdown-menu { + display: block; + } + .nav-pills > li.dropdown ul.dropdown-menu .dropdown-submenu .dropdown-menu, .nav-tabs > li.dropdown ul.dropdown-menu .dropdown-submenu .dropdown-menu { + display: none; + } + .nav-pills > li.dropdown ul.dropdown-menu .dropdown-submenu:hover .dropdown-menu, .nav-tabs > li.dropdown ul.dropdown-menu .dropdown-submenu:hover .dropdown-menu { + display: block; + } +} +@media (max-width: 767px) { + /* minimale breedte voor horizontaal tabs menu */ + /* Submenu's onder elkaar plaatsen (tbv mobiele apparaten)*/ + /* Groote van de subitems gelijk maken */ + /* Achtergrond kleur van de actieve hoofdmenu items, caret en border correctie */ + .nav-tabs > li { + float: none; + } + .nav-tabs > .active > a, .nav-tabs > .active > a:hover { + border: none; + } + .dropdown, .dropdown-submenu { + display: block; + position: static; + float: none; + } + .dropdown-menu { + position: static; + float: none; + } + .open .nav-child.dropdown-menu { + display: block; + background-color: transparent; + border: none; + border-radius: 0; + box-shadow: none; + } + .nav-child.dropdown-menu { + padding: 0; + } + .nav-child.small { + font-size: 13px; + } + .dropdown-menu > li > a { + padding: 8px 12px 8px 20px; + } + .nav > li.active > a, .nav > li.active > a:hover, .nav > li.active > a:focus { + background-color: #999; + color: #fff; + } + .nav li.dropdown.active .caret, .nav li.dropdown.active a:hover .caret, .nav li.dropdown.active a:focus .caret { + border-bottom-color: #fff; + border-top-color: #fff; + } + .nav-tabs .open .dropdown-toggle, .nav-pills .open .dropdown-toggle, .nav > li.dropdown.open.active > a:hover, .nav > li.dropdown.open.active > a:focus { + border: none; + } +} +@media (min-width: 576px) { + #img_brandImage { + width: auto * 540 / 960; + } +} +/* einde up(sm) */ +@media (min-width: 768px) { + #img_brandImage { + width: auto * 720 / 960; + } +} +/* einde up(md) */ +@media (min-width: 992px) { + #img_brandImage { + width: auto; + } +} +/* einde up(lg) */ +/* template_css.scss */ +/* =========================== + alle schermbreedtes + Write your general styles eerst voor alle schermbreedtes, + daarna uitzonderingen voor steeds bredere schermen (mobile first) + ========================== */ +/* background images via absoluut geplaatste html */ +/* content background */ +#img_bg1Image { + position: absolute; + width: 80%; + height: auto; + left: auto; + padding-top: auto; + /* margin-top:$bg1Top; ivm fout in safari */ +} +/* z-index: $bg1Z-index; */ +#headerleft { + position: relative; + float: left; + width: 25%; + margin-top: 1%; + margin-left: 0%; + margin-bottom: 0%; + padding-top: 0; + padding-bottom: 0; +} +#headerleft div.inner { + position: relative; + width: 100%; +} +.visually-hidden { + display: none; +} +#navbar-right-mod { + display: inline-block; + width: 340px; + max-width: 100%; +} +#wrapper, body > div.container { + position: relative; + overflow-x: hidden; + border-radius: 10px; +} +#wrapper1 { + /* voor achtergrondafbeeldingen van #wrapper geen extra margin ed toevoegen, anders klopt lay-out niet meer */ + position: relative; +} +.bg-transparent { + background-color: transparent !important; +} +.blog { + /* .blog_inline algemene definities (gestuurd door blog tabblad paginaweergave paginaclass: niets blog is standaard) + heeft definities op alle breedtes, naarmate het scherm breder wordt krijgen meer + spans hun eigenlijke breedte (99% / 12 * ) -1% en margin-right 1%. + (spannr wordt aangestuurd door blog tabblad blogweergave 12 / # kolommen tevens komt er dan een cols-nr in de div eronder ) + en komen meer breedtes voor items-leading beschikbaar (gestuurd door paginaweergave paginaclass: blog lead-cols-2 ) + .blog ook voor kop ul.list-striped komt overeen met div.items-row (maar cols-1 etc kan hier niet gevuld worden + volgende nivo li.cat-list-row0 en li.cat-list-row1 komen overeen met div.span1 span2 enz + volgende nivo ontbreekt bij taglist komt overeen met div.item + volgende nivo span.tag-body (en h3) komt overeen met p + */ +} +.blog .items-leading, .blog .items-row, .blog .list-striped { + word-spacing: -0.25em; + width: 100%; +} +.blog .items-leading > div, .blog .items-row > div, .blog .items-row > div > div, .blog .list-striped > li { + display: inline-block; + word-spacing: normal; + vertical-align: top; + float: none; + max-width: 100%; +} +.blog .item, .blog .span6, .blog .span4, .blog .span3, .blog .span2, .blog .span1, .blog .cat-list-row0, .blog .cat-list-row1 { + width: 100%; + margin-right: 0px; +} +.header-inner { + display: -ms-flexbox; + display: flex; + -ms-flex-direction: column; + flex-direction: column; +} +.header-inner .navbar { + width: 100%; +} +.header-inner .navbar > .container, .header-inner .navbar > .container-fluid { + align-items: flex-start; +} +.icon-cog, .icons .icon-cog { + background-position: -432px 0; +} +.iconssm { + /* icons social media boven logo absolute vanaf 'navbar-expand-..' */ + position: relative; + display: block; + display: -ms-flexbox; + display: flex; + -ms-flex-direction: row; + flex-direction: row; + width: 100%; + -ms-flex-order: -1; + order: -1; +} +.img-fluid, .img-fluid-w33, .img-fluid-w50 { + /* vooruitlopend op bs4 in 3 is dit img-responsive */ + max-width: 100%; + height: auto; +} +.items-leading div .videoWrapper, .videoWrapper { + position: relative; + padding-bottom: 56.25%; + padding-top: 25px; + max-width: 100%; + width: 1170px; + height: 0; +} +.items-leading div .videoWrapper object, .videoWrapper object, .items-leading div .videoWrapper embed, .videoWrapper embed, .items-leading div .videoWrapper iframe, .videoWrapper iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.list-striped, .row-striped { + border-top: none; +} +.list-striped li, .list-striped dd, .row-striped .row, .row-striped .row-fluid { + border-bottom: none; + padding: 0; +} +.mod-languages { + float: right; +} +/* tijdelijk toegvoegd voor bs 3 en bs4 */ +.navbar-collapse.in { + overflow-y: visible; + display: block; +} +.navbar-toggle .icon-bar { + background-color: #888; +} +/* transparent navbar */ +.navbar.navbar-default.transparent, .navbar.navbar-inverse.transparent { + border-width: 0px; + -webkit-box-shadow: 0px 0px; + box-shadow: 0px 0px; + background-color: rgba(0, 0, 0, 0); + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, rgba(0, 0, 0, 0)), color-stop(100%, rgba(0, 0, 0, 0))); + background-image: -webkit-linear-gradient(270deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 100%); + background-image: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0) 100%); +} +/* einde tijdelijk toegvoegd voor bs 3 */ +/* adaptations for newsfeeds */ +/* rss fotos of flickr suffix _rssfoto */ +/* rss fotos of flickr met suffix _rssfoto */ +/* rss flickr images (ul li p a img) */ +[class*="rssfoto"] .newsfeed { + margin: 0; + padding: 0; + width: auto; +} +[class*="rssfoto"] .newsfeed h2 { + margin: 0; + font-weight: bold; + font-family: Helvetica, Arial, sans-serif; + font-size: 1.5em; + padding-left: 0px; + margin-bottom: 10px; + text-align: left; +} +[class*="rssfoto"] .newsfeed h3 { + font-size: 1.3em; + line-height: 1.3em; + padding-left: 0px; + margin-bottom: 0px; + text-align: left; +} +[class*="rssfoto"] .newsfeed ol, [class*="rssfoto"] .newsfeed ul { + padding: 0; +} +[class*="rssfoto"] .newsfeed li { + list-style-type: none; + margin-left: 0; + margin-right: 10px; + margin-bottom: 10px; + display: inline-block; + height: 320px; + /* vaste hoogte (en breedte) voor mooier ordenen */ + width: 250px; + overflow: hidden; +} +[class*="rssfoto"] .newsfeed li a img { + background-color: rgba(255, 255, 255, 0.75); + padding: 4px; + border: 1px solid lightgray; + border-radius: 5px; + box-shadow: 0 0 8px 4px lightgray; + margin: 5px; +} +[class*="rssfoto"] .newsfeed li div.feed-item-description p:first-child { + /* make unwanted image header text from newsfeed invisible */ + font-size: 4%; + color: transparent; +} +[class*="rssfoto"] .newsfeed li div.feed-item-description p:first-child a { + font-size: 2500%; + color: #337ab7; +} +/* end rssfoto newsfeed */ +/* exceptions for rssfoto01 */ +[class*="rssfoto01"] div.newsfeed li { + background-color: lightgray; +} +[class*="rssfoto01"] div.newsfeed li a img { + padding: 5px; +} +/* end exceptions for rssfoto01 */ +.tag-category fieldset { + /* tot joomla het zoekveld goed verbergt */ + display: none; +} +.tag-category ul { + /* tag-list inline maken in plaats van opsomming */ + padding-left: 0; +} +.tag-category ul li { + display: inline-block; + position: static; + vertical-align: top; + max-width: 100%; + margin-right: 1%; + margin-bottom: 1%; +} +.tag-category ul.category.list-striped li { + /* element rij alleen in tag-lijst, vaste breedte */ + background-color: transparent; + max-width: 100%; + width: 256px; +} +.tag-category ul li h3 { + display: none; +} +body { + font-family: Verdana, Arial, sans-serif; + padding-top: 10px; + padding-bottom: 40px; + overflow: auto; +} +/* aanpassingen rij in tag-lijst en tag overzicht, tag-list ongedaan maken voor pagination */ +div.pagination { + /* normale bootstrap class is ul.pagination */ + margin-top: 0px; + width: 100%; +} +div.pagination p { + margin-top: 20px; +} +div div.pagination ul { + /* tag-list inline maken in plaats van opsomming */ + padding-left: 0px; +} +div div.pagination ul li { + /* element rij in tag-lijst en tag overzicht, tag-list inline maken in plaats van opsomming */ + display: inline-block; + position: static; + vertical-align: top; + max-width: 100%; + margin-right: 0px; + margin-bottom: 0px; +} +/* einde aanpassing alleen voor pagination */ +div.mod-languages a { + padding: 0; +} +div.mod-languages ul li { + margin-left: 5px; + margin-right: 5px; +} +div.mod-languages ul li.lang-active { + background-color: transparent; +} +h1, h2, h3, h4, h5, h6 { + font-family: 'Open Sans Condensed', sans-serif; + font-weight: 700; +} +h1 { + font-size: 30px; + line-height: 34px; +} +h2 { + font-size: 26px; + line-height: 30px; +} +h3 { + font-size: 22px; + line-height: 26px; +} +h4 { + font-size: 18px; + line-height: 20px; +} +h5 { + font-size: 14px; + line-height: 20px; +} +h6 { + font-size: 12px; + line-height: 20px; +} +/* overige aanpassingen pagination tbv bootstrap 3 */ +/* einde overige aanpassingen pagination tbv bootstrap 3 */ +[class^="icon-"], [class*=" icon-"] { + display: inline-block; + width: 14px; + height: 14px; + margin-top: 1px; + line-height: 14px; + vertical-align: text-top; + background-image: url("../img/glyphicons-halflings.png"); + background-position: 14px 14px; + background-repeat: no-repeat; +} +/* einde tijdelijk overgenomen uit bootstrap css v2 */ +/* Special general */ +[class*="special"] .module-content ul { + margin: 0 0 10px 17px; +} +[class*="special"] .module-content ul.unstyled { + margin: 0 0 10px 0; +} +/* =========================== + einde alle schermbreedtes + ========================== */ +/* einde (max-width: $screen-xs-max) */ +@media (min-width: 576px) { + .blog .span6, .blog .span4, .blog .span3, .blog .span2, .blog .span1, .blog.cols-2 .cat-list-row0, .blog.cols-3 .cat-list-row0, .blog.cols-4 .cat-list-row0, .blog.cols-5 .cat-list-row0, .blog.cols-6 .cat-list-row0, .blog.cols-2 .cat-list-row1, .blog.cols-3 .cat-list-row1, .blog.cols-4 .cat-list-row1, .blog.cols-5 .cat-list-row1, .blog.cols-6 .cat-list-row1 { + width: 49.25%; + margin-left: auto; + } + .blog.lead-cols-2 .items-leading > div { + width: 49.25%; + margin-left: auto; + } + .img-fluid-w33 { + max-width: 33%; + } + .img-fluid-w50 { + max-width: 50%; + } + .tag-category ul li { + max-width: 30%; + width: auto; + } + .tag-category ul.category.list-striped li { + max-width: 30%; + width: auto; + } +} +/* einde up(sm) */ +@media (min-width: 768px) { + #navbar-right-mod { + float: right; + margin-right: -15px; + } + .blog .span4, .blog.cols-3 .cat-list-row0, .blog.cols-3 .cat-list-row1 { + width: 32.6666666667%; + } + .blog .span3, .blog .span2, .blog .span1, .blog.cols-4 .cat-list-row0, .blog.cols-5 .cat-list-row0, .blog.cols-6 .cat-list-row0, .blog.cols-4 .cat-list-row1, .blog.cols-5 .cat-list-row1, .blog.cols-6 .cat-list-row1 { + width: 24.375%; + } + .blog.lead-cols-3 .items-leading > div { + width: 32.6666666667%; + margin-left: auto; + } + .form-horizontal .control-group .control-label { + text-align: left; + } + .hiicons .navbar.navbar-expand-md #img_brandImage { + margin-top: -40px; + } +} +/* einde up(md) */ +@media (min-width: 992px) { + .blog .cols-5 .span2, .blog.cols-5 .cat-list-row0, .blog.cols-5 .cat-list-row1 { + width: 19.4%; + } + .blog .span2, .blog.cols-6 .cat-list-row0, .blog.cols-6 .cat-list-row1 { + width: 16.0833333333%; + } + .blog .cols-8 .span1 { + width: 11.9375%; + } + .blog .span1 { + width: 7.7916666667%; + } + .hiicons .navbar.navbar-expand-lg #img_brandImage { + margin-top: -40px; + } +} +/* einde up(lg) */ +@media (min-width: 1200px) { + .hiicons .navbar.navbar-expand-xl #img_brandImage { + margin-top: -40px; + } +} +/* einde up(xl) */ +/*# sourceMappingURL=data:application/json,%7B%22version%22%3A3%2C%22sources%22%3A%5B%22home%5C%2Fdeb120151%5C%2Fdomains%5C%2Fwaasdorp.soekhan.nl%5C%2Fpublic_html%5C%2Ftemplates%5C%2Fwsa_bootstrap%5C%2Frules%5C%2F..%5C%2Fscss%5C%2Fstyle13.scss%22%2C%22home%5C%2Fdeb120151%5C%2Fdomains%5C%2Fwaasdorp.soekhan.nl%5C%2Fpublic_html%5C%2Ftemplates%5C%2Fwsa_bootstrap%5C%2Frules%5C%2F..%5C%2Fscss%5C%2F_magnificpopup.scss%22%2C%22home%5C%2Fdeb120151%5C%2Fdomains%5C%2Fwaasdorp.soekhan.nl%5C%2Fpublic_html%5C%2Ftemplates%5C%2Fwsa_bootstrap%5C%2Frules%5C%2F..%5C%2Fscss%5C%2F_template_dropdown.scss%22%2C%22home%5C%2Fdeb120151%5C%2Fdomains%5C%2Fwaasdorp.soekhan.nl%5C%2Fpublic_html%5C%2Ftemplates%5C%2Fwsa_bootstrap%5C%2Frules%5C%2F..%5C%2Fscss%5C%2Fnode_modules%5C%2Fbootstrap%5C%2Fscss%5C%2Fmixins%5C%2F_breakpoints.scss%22%2C%22home%5C%2Fdeb120151%5C%2Fdomains%5C%2Fwaasdorp.soekhan.nl%5C%2Fpublic_html%5C%2Ftemplates%5C%2Fwsa_bootstrap%5C%2Frules%5C%2F..%5C%2Fscss%5C%2F_template_css.scss%22%5D%2C%22names%22%3A%5B%5D%2C%22mappings%22%3A%22AAAD%2CoBAAA%3BAAAA%2C8BAAA%3BAAAA%2C2BAAA%3BAAAA%2CkCAAA%3BAAAA%2C6BAAA%3BAAAA%2CgBAAA%3BAAAA%2CwBAAA%3BACIC%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3B4BAAA%3BAAAA%3BAAYA%3BAAAA%3B%3B%3B%3B%3B%3B%3BsCAAA%3BAAAA%3BAAUA%3BAAAA%3B%3B%3B%3B%3B%3B%3ByBAAA%3BAAAA%3BAAUA%3BAAAA%3B%3B%3ByBAAA%3BAAAA%3BAAMA%3BAAAA%2CgBAAA%3BAAAA%3BAAGA%3BAAAA%3B%3B%3B%3B%3BgBAAA%3BAAAA%3BAAQA%3BAAAA%3BeAAA%3BAAAA%3BAAKA%3BAAAA%2CmBAAA%3BAAAA%3BAAGA%3BAAAA%3B%3BmBAAA%3BAAAA%3BAAKA%3BAAAA%3B%3B%3BkBAAA%3BAAAA%3BAAMA%3BAAAA%2CeAAA%3BAAAA%3BAAGA%3BAAAA%3B%3BoBAAA%3BAAAA%3BAAQA%3BAAAA%2CgBAAA%3BAAAA%3BAAGA%3BAAAA%2C2BAAA%3BAAAA%3BAAGA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3BgBAAA%3BAAAA%3BAAUE%3BAAAA%2CcAAA%3BAAAA%3BAAEE%3BAAAA%2CcAAA%3BAAAA%3BAAGJ%3BAAAA%2CgBAAA%3BAAAA%3BAAGA%3BAAAA%2CgBAAA%3BAAAA%3BAAGA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B6BAAA%3BAAAA%3BAAiBA%3BAAAA%3BYAAA%3BAAAA%3BAAIA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B6CAAA%3BAAAA%3BAAmBE%3BAAAA%3B6BAAA%3BAAAA%3BAAIA%3BAAAA%2CWAAA%3BAAAA%3BAAGF%3BAAAA%2CcAAA%3BAAAA%3BAAGA%3BAAAA%3B%3B%3B%3BcAAA%3BAAAA%3BAAQA%3BAAAA%3B%3B%3B%3B%3B%3BsBAAA%3BAAAA%3BAASA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3B2CAAA%3BAAAA%3BAAWE%3BAAAA%2CoBAAA%3BAAAA%3BAAEA%3BAAAA%3B6BAAA%3BAAAA%3BAAIA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3BmCAAA%3BAAAA%3BAAYA%3BAAAA%3B%3BWAAA%3BAAAA%3BAAIA%3BAAAA%3B%3B%3B4BAAA%3BAAAA%3BAAMF%3BAAAA%2CUAAA%3BAAAA%3BAAEE%3BAAAA%3BoBAAA%3BAAAA%3BAAGA%3BAAAA%3BmCAAA%3BAAAA%3BAAIF%3BAAAA%2CWAAA%3BAAAA%3BAAEE%3BAAAA%3BoBAAA%3BAAAA%3BAAGA%3BAAAA%2CkCAAA%3BAAAA%3BAAGF%3BAAAA%3BuBAAA%3BAAAA%3BAAGE%3BAAAA%3B%3BmBAAA%3BAAAA%3BAAIA%3BAAAA%2CaAAA%3BAAAA%3BAAGF%3BAAAA%3B%3B%3BsBAAA%3BAAAA%3BAAKE%3BAAAA%3B%3B%3B%3B%3B%3B%3BmBAAA%3BAAAA%3BADxPH%2CyBAAA%3BACmQC%3BAAAA%3B%3B%3B%3B%3B%3B%3BiBAAA%3BAAAA%3BADnQD%2CiCAAA%3BAC8QC%3BAAAA%2CiBAAA%3BAAAA%3BAAEA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B%3BmBAAA%3BAAAA%3BAAaE%3BAAAA%3B%3B%3BoBAAA%3BAAAA%3BAAKA%3BAAAA%2CYAAA%3BAAAA%3BAAGF%3BAAAA%3B%3B%3B%3B%3BeAAA%3BAAAA%3BAAQA%3BAAAA%3B%3B%3B%3BsBAAA%3BAAAA%3BAAOA%3BAAAA%2CkBAAA%3BAAAA%3BAAGA%3BAAAA%2CkBAAA%3BAAAA%3BAAGA%3BAAAA%3B%3BKAAA%3BAAIE%3BAAAA%3BqBAAA%3BAAAA%3BAAGA%3BAAAA%2CeAAA%3BAAAA%3BAAEA%3BAAAA%3BcAAA%3BAAAA%3BAAGA%3BAAAA%3BqBAAA%3BAAAA%3BAAGA%3BAAAA%3B%3B%3B%3B%3B%3B2BAAA%3BAAAA%3BAAQE%3BAAAA%2CeAAA%3BAAAA%3BAAEF%3BAAAA%3BaAAA%3BAAAA%3BAAGA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3BeAAA%3BAAAA%3BAAAA%3BAAWF%3BAACE%3BAAAA%3B2BAAA%3BAAAA%3BAAGA%3BAAAA%3BwBAAA%3BAAAA%3BAAGA%3BAAAA%3B2BAAA%3BAAAA%3BAAGA%3BAAAA%3BuBAAA%3BAAAA%3BAAAA%3BAD3WH%2CiCAAA%3BAC%2BWC%3BAAAA%3BeAAA%3BAAAA%3BAAIA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3BqBAAA%3BAAAA%3BAAcA%3BAAAA%2CiBAAA%3BAAAA%3BAAIA%3BAAAA%2CgBAAA%3BAAAA%3BAAGA%3BAAAA%3B%3B%3B%3B%3B%3BkEAAA%3BAAAA%3BAAWA%3BAAAA%2CeAAA%3BAAAA%3BAAKA%3BAAAA%2CoBAAA%3BAAAA%3BAAGA%3BAAAA%3BoBAAA%3BAAAA%3BAD3ZD%3B%3B%3B%3B%3BGAAA%3BACsaC%3BAAAA%3B%3BiBAAA%3BAAAA%3BADtaD%2C4BAAA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3B%3B4CAAA%3BAEaC%3BAAAA%2C0BAAA%3BAAAA%3BAFbD%2CkCAAA%3BAAAA%2CqBAAA%3BAEkLG%3BAAAA%2CcAAA%3BAAAA%3BAAGC%3BAAAA%2CiBAAA%3BAAAA%3BAAOC%3BAAAA%2CcAAA%3BAAAA%3BAAGE%3BAAAA%2CcAAA%3BAAAA%3BAAKA%3BAAAA%2CcAAA%3BAAAA%3BAAKF%3BAAAA%2CcAAA%3BAAAA%3BAAQF%3BAAAA%3BqBAAA%3BAAAA%3BAAKA%3BAAAA%2CiQAAA%3BAAAA%3BAAIA%3BAAAA%2CcAAA%3BAAAA%3BAAEE%3BAAAA%2CcAAA%3BAAAA%3BAAGE%3BAAAA%2CcAAA%3BAAAA%3BAAeN%3BAAAA%2CiDAAA%3BAAAA%3BAF9OD%3B%3ByBAAA%3BAEwPC%3BAAAA%3B%3BwCAAA%3BAAAA%3BAAKE%3BAAAA%3B%3B%3B%3B%3B%3BsBAAA%3BAAAA%3BAAUA%3BAAAA%3B%3B%3B%3B%3BwBAAA%3BAAAA%3BAAYF%3BAAAA%3B%3B%3B%3BwBAAA%3BAAAA%3BAAaA%3BAAAA%3B%3B%3BoBAAA%3BAAAA%3BAAOG%3BAAAA%2C4BAAA%3BAAAA%3BAFvSJ%2CiEAAA%3BAAAA%2C%2BDAAA%3BAEgTC%3BAAAA%3B8BAAA%3BAAAA%3BAAGG%3BAAAA%3B%3B%3B%3B%3B%3B%2BBAAA%3BAAAA%3BAAUA%3BAAAA%2CiBAAA%3BAAAA%3BAAIA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3B%3BsBAAA%3BAAAA%3BAAcA%3BAAAA%2C0BAAA%3BAAAA%3BAAIA%3BAAAA%2CcAAA%3BAAAA%3BAAEG%3BAAAA%3B%3B%3B%3B%2BBAAA%3BAAAA%3BAAgBN%3BAAAA%2CcAAA%3BAAAA%3BAAMA%3BAAAA%2CwCAAA%3BAAAA%3BAAKA%3BAAAA%3B%3BmCAAA%3BAAAA%3BAAYM%3BAAAA%3ByBAAA%3BAAAA%3BAAOF%3BAAAA%2CcAAA%3BAAAA%3BAAEE%3BAAAA%3B%3B%3BsBAAA%3BAAAA%3BAAYF%3BAAAA%3BwBAAA%3BAAAA%3BAAYJ%3BAAAA%2CgCAAA%3BAAAA%3BAAEE%3BAAAA%3BsBAAA%3BAAAA%3BAAME%3BAAAA%3B%3B%3B6BAAA%3BAAAA%3BAAKE%3BAAAA%2C%2BBAAA%3BAAAA%3BAAOA%3BAAAA%3B%3B%3B%3BkBAAA%3BAAAA%3BAAkBJ%3BAAAA%2CcAAA%3BAAAA%3BAAIE%3BAAAA%2CqBAAA%3BAAAA%3BAAGA%3BAAAA%2CmBAAA%3BAAAA%3BAAME%3BAAAA%3B4BAAA%3BAAAA%3BAFhdP%3B%3B%3B%3BGAAA%3BAAAA%2C%2BBAAA%3BAAAA%3B%3B%3B%3B%3BGAAA%3BAEueC%3BAACE%3BAAAA%3BqBAAA%3BAAAA%3BAAIA%3BAAAA%2CgBAAA%3BAAAA%3BAAGA%3BAAAA%2CmBAAA%3BAAAA%3BAAGA%3BAAAA%3BmBAAA%3BAAAA%3BAAIA%3BAAAA%3ByBAAA%3BAAAA%3BAAAA%3BAFtfH%2CqCAAA%3BAE6fC%3BAAAA%2C%2BDAAA%3BAACO%3BAAAA%2CcAAA%3BAAAA%3BAAKA%3BAAAA%2CmBAAA%3BAAAA%3BAAKA%3BAAAA%2CkBAAA%3BAAAA%3BAAKA%3BAAAA%2CmBAAA%3BAAAA%3BAAAA%3BAAMP%3BAAAA%3B%3B%3BmFAAA%3BAACA%3BAAAA%2CgBAAA%3BAAAA%3BAAGA%3BAAAA%2CiBAAA%3BAAAA%3BAAKA%3BAAAA%3B%3BgBAAA%3BAAAA%3BAAMA%3BAAAA%3BgBAAA%3BAAAA%3BAAIA%3BAAAA%3B%3B%3B%3BqBAAA%3BAAAA%3BAAQA%3BAAAA%2CeAAA%3BAAAA%3BAAGA%3BAAAA%2CoBAAA%3BAAAA%3BAAGA%3BAAAA%2C%2BBAAA%3BAAAA%3BAAIA%3BAAAA%3BgBAAA%3BAAAA%3BAAMA%3BAAAA%3B2BAAA%3BAAAA%3BAAMA%3BAAAA%2CiBAAA%3BAAAA%3BAAAA%3BACxgBI%3BADohBJ%3BAAAA%2C4BAAA%3BAAAA%3BAAAA%3BAFhlBD%2CkBAAA%3BAG4DK%3BAD2hBJ%3BAAAA%2C4BAAA%3BAAAA%3BAAAA%3BAFvlBD%2CkBAAA%3BAG4DK%3BADkiBJ%3BAAAA%2CgBAAA%3BAAAA%3BAAAA%3BAF9lBD%2CkBAAA%3BAAAA%2CuBAAA%3BAAAA%3B%3B%3B%3B8BAAA%3BAAAA%2CoDAAA%3BAAAA%2CwBAAA%3BAIkCC%3BAAAA%3B%3B%3B%3B%3B%2BCAAA%3BAAAA%3BAJlCD%2C4BAAA%3BAI6DC%3BAAAA%3B%3B%3B%3B%3B%3B%3BoBAAA%3BAAAA%3BAASM%3BAAAA%3BcAAA%3BAAAA%3BAAKN%3BAAAA%2CgBAAA%3BAAAA%3BAA8BA%3BAAAA%3B%3BkBAAA%3BAAAA%3BAAOA%3BAAAA%3B%3BsBAAA%3BAAAA%3BAAMA%3BAAAA%3BqBAAA%3BAAAA%3BAAMA%3BAAAA%2C2CAAA%3BAAAA%3BAAGA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3BKAAA%3BAAAA%3BAAWC%3BAAAA%3BcAAA%3BAAAA%3BAAOA%3BAAAA%3B%3B%3B%3BkBAAA%3BAAAA%3BAAWA%3BAAAA%3BoBAAA%3BAAAA%3BAAOD%3BAAAA%3B%3B%3ByBAAA%3BAAAA%3BAAMC%3BAAAA%2CcAAA%3BAAAA%3BAAEA%3BAAAA%2C0BAAA%3BAAAA%3BAAKD%3BAAAA%2CgCAAA%3BAAAA%3BAAKA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%3BYAAA%3BAAAA%3BAAgBA%3BAAAA%3B%3BeAAA%3BAAAA%3BAAQA%3BAAAA%3B%3B%3B%3B%3BYAAA%3BAAAA%3BAAQE%3BAAAA%3B%3B%3B%3BeAAA%3BAAAA%3BAASF%3BAAAA%2CmBAAA%3BAAAA%3BAAGA%3BAAAA%3BaAAA%3BAAAA%3BAAKA%3BAAAA%2CeAAA%3BAAAA%3BAJtOD%2C2CAAA%3BAI0OC%3BAAAA%3BiBAAA%3BAAAA%3BAAIA%3BAAAA%2CyBAAA%3BAAAA%3BAJ9OD%2CwBAAA%3BAIkPC%3BAAAA%3B%3B%3B%3B%3B%3BwFAAA%3BAAAA%3BAJlPD%2CyCAAA%3BAAAA%2C%2BBAAA%3BAAAA%2CyCAAA%3BAAAA%2C8CAAA%3BAAAA%2CuCAAA%3BAImQC%3BAAAA%3B%3BcAAA%3BAAAA%3BAAKC%3BAAAA%3B%3B%3B%3B%3B%3BmBAAA%3BAAAA%3BAAWA%3BAAAA%3B%3B%3B%3BmBAAA%3BAAAA%3BAASA%3BAAAA%2CaAAA%3BAAAA%3BAAIA%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3BmBAAA%3BAAAA%3BAAWC%3BAAAA%3B%3B%3B%3B%3BcAAA%3BAAAA%3BAAUC%3BAAAA%3B%3BqBAAA%3BAAAA%3BAAII%3BAAAA%3BiBAAA%3BAAAA%3BAJzTR%2C2BAAA%3BAAAA%2C8BAAA%3BAIoUC%3BAAAA%2C8BAAA%3BAAAA%3BAAGC%3BAAAA%2CeAAA%3BAAAA%3BAJvUF%2CkCAAA%3BAI6UC%3BAAAA%3BgBAAA%3BAAAA%3BAAKA%3BAAAA%3BkBAAA%3BAAAA%3BAAIC%3BAAAA%3B%3B%3B%3B%3BoBAAA%3BAAAA%3BAASC%3BAAAA%3B%3B%3BeAAA%3BAAAA%3BAAQD%3BAAAA%2CgBAAA%3BAAAA%3BAAMD%3BAAAA%3B%3B%3BiBAAA%3BAAAA%3BAJ7WD%2C6FAAA%3BAIqXC%3BAAAA%3B%3BcAAA%3BAAAA%3BAAIA%3BAAAA%2CmBAAA%3BAAAA%3BAAGA%3BAAAA%3BoBAAA%3BAAAA%3BAAMA%3BAAAA%3B%3B%3B%3B%3B%3BqBAAA%3BAAAA%3BAJlYD%2C6CAAA%3BAI6YE%3BAAAA%2CaAAA%3BAAAA%3BAAIC%3BAAAA%3BoBAAA%3BAAAA%3BAAIA%3BAAAA%2CgCAAA%3BAAAA%3BAASF%3BAAAA%3BmBAAA%3BAAAA%3BAAKA%3BAAAA%3BoBAAA%3BAAAA%3BAAKA%3BAAAA%3BoBAAA%3BAAAA%3BAAKA%3BAAAA%3BoBAAA%3BAAAA%3BAAKA%3BAAAA%3BoBAAA%3BAAAA%3BAAKA%3BAAAA%3BoBAAA%3BAAAA%3BAAKA%3BAAAA%3BoBAAA%3BAAAA%3BAJ5bD%2CqDAAA%3BAAAA%2C2DAAA%3BAI0cC%3BAAAA%3B%3B%3B%3B%3B%3B%3B%3B%2BBAAA%3BAAAA%3BAJ1cD%2CsDAAA%3BAAAA%2CqBAAA%3BAIwdC%3BAAAA%2CwBAAA%3BAAAA%3BAAIA%3BAAAA%2CqBAAA%3BAAAA%3BAJ5dD%3B%3B8BAAA%3BAAAA%2CuCAAA%3BAG4DK%3BACibH%3BAAAA%3BsBAAA%3BAAAA%3BAAWA%3BAAAA%3BsBAAA%3BAAAA%3BAASD%3BAAAA%2CmBAAA%3BAAAA%3BAAIC%3BAAAA%2CmBAAA%3BAAAA%3BAAMA%3BAAAA%3BgBAAA%3BAAAA%3BAAKC%3BAAAA%3BgBAAA%3BAAAA%3BAAAA%3BAJhhBH%2CkBAAA%3BAG4DK%3BAC8dJ%3BAAAA%3BwBAAA%3BAAAA%3BAAMC%3BAAAA%2C0BAAA%3BAAAA%3BAAKA%3BAAAA%2CmBAAA%3BAAAA%3BAAQA%3BAAAA%3BsBAAA%3BAAAA%3BAAYC%3BAAAA%2CqBAAA%3BAAAA%3BAAkBF%3BAAAA%2CsBAAA%3BAAAA%3BAAAA%3BAJ3kBD%2CkBAAA%3BAG4DK%3BAC2hBH%3BAAAA%2CiBAAA%3BAAAA%3BAAMA%3BAAAA%2C0BAAA%3BAAAA%3BAAKA%3BAAAA%2CoBAAA%3BAAAA%3BAAGC%3BAAAA%2CyBAAA%3BAAAA%3BAAiBF%3BAAAA%2CsBAAA%3BAAAA%3BAAAA%3BAJtnBD%2CkBAAA%3BAG4DK%3BAC8kBJ%3BAAAA%2CsBAAA%3BAAAA%3BAAAA%3BAJ1oBD%2CkBAAA%22%7D */ \ No newline at end of file diff --git a/scss/_template_css.scss b/scss/_template_css.scss index bc19e73..fd6aaaf 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -23,6 +23,10 @@ // 20211229 header-inner navbar width 100% toegevoegd om toggler rechts te kunnen plaatsen, buiten header inner gaat dit al goed. // 20211230 padding .span12 extra voor BS3 in BS4/5 wordt col12 gebruikt en staan deze paddings al voor alle col-deimensies. // padding header-inner .navbar alleen nog 0 voor BS3 +// 20240930 Redesigned block for RSS (Flickr) fotos newsfeed component, because J4, J5 module class is not a suffix after the component class, +// but an extra class in the page header, ul may be used in stead of ol and Pias is stopped. So .newsfeed_rssfoto is approximately +// replaced by by ._rssfoto .newsfeed. At the same time make more use of scss possibillities use css attribute match selectors and +// remove unnecessary selectors. /* =========================== alle schermbreedtes @@ -253,105 +257,83 @@ order: -1; } /* einde tijdelijk toegvoegd voor bs 3 */ -/* aanpassingen voor newsfeeds uit oudere templates van mij */ -/* rss fotos van flickr en picasa met suffix _rssfoto */ -/* rss fotos van flickr en picasa met suffix _rssfoto */ +/* adaptations for newsfeeds */ +/* rss fotos of flickr suffix _rssfoto */ +/* rss fotos of flickr met suffix _rssfoto */ /* rss flickr images (ul li p a img) */ -/* rss picasa images (ul li a img) */ -.newsfeed_rssfoto, -.newsfeed_rssfoto01, -.newsfeed_rsspicasa, -div[class^="newsfeed"] -{ -margin: 0; -padding: 0; -width: auto; - - h2 - { +[class*="rssfoto"] .newsfeed { margin: 0; - font-weight: bold; - font-family: Helvetica,Arial,sans-serif; - font-size: 1.5em; - padding-left: 0px; - margin-bottom: 10px; - text-align: left; - } + padding: 0; + width: auto; - h3 - { - font-size: 1.3em; - line-height: 1.3em; - padding-left: 0px; - margin-bottom: 0px; - text-align: left; - } + h2 + { + margin: 0; + font-weight: bold; + font-family: Helvetica,Arial,sans-serif; + font-size: 1.5em; + padding-left: 0px; + margin-bottom: 10px; + text-align: left; + } - ol - { - padding:0; + h3 + { + font-size: 1.3em; + line-height: 1.3em; + padding-left: 0px; + margin-bottom: 0px; + text-align: left; + } - li + ol, ul + { + padding:0; + } + li { list-style-type: none; margin-left: 0; margin-right: 10px; margin-bottom: 10px; - } - } - -/* einde div[class^="newsfeed"] */} -.newsfeed_rssfoto, -.newsfeed_rssfoto01, -.newsfeed_rsspicasa -{ - ol - { - - li - { display: inline-block; height: 320px; /* vaste hoogte (en breedte) voor mooier ordenen */ width: 250px; overflow: hidden; + + a img + { + background-color: rgba(255,255,255,0.75); + padding:4px; + border: 1px solid lightgray; + border-radius: 5px; + box-shadow: 0 0 8px 4px lightgray; + margin: 5px; + } + + div.feed-item-description p:first-child + { /* make unwanted image header text from newsfeed invisible */ + font-size: 4%; + color: transparent; + a + { + font-size: 2500%; + color: $link-color; + } + } + } - } -/* einde newsfeed_rssfoto */ } + +} /* end rssfoto newsfeed */ +/* exceptions for rssfoto01 */ +[class*="rssfoto01"] div.newsfeed li{ + background-color: lightgray; -.newsfeed_rssfoto ol li a img, -.newsfeed_rsspicasa ol li a img -{ -background-color: #6F571B; -padding:2px; -border: 3px solid black; /*ridge */ -} -/* ongewenste tekst van newsfeed onzichtbaar maken j3 zodat override niet nodig is */ -.newsfeed_rssfoto ol li div.feed-item-description p:first-child, -.newsfeed_rssfoto01 ol li div.feed-item-description p:first-child -{ -font-size: 4%; -//opacity: 0.1; -color: transparent; - a - { - font-size: 2500%; - //opacity: 1.0; - color: $link-color; - } -} -.newsfeed_rssfoto01 ol li -{ -background-color: #ccc; -} -.newsfeed_rssfoto01 ol li a img -{ -padding:5px; -} -.newsfeed_rsspicasa ol li -{ -height: 210px; /* picasa foto's zijn kleiner en vierkant */ -background-color: #ccc; -} + a img + { + padding:5px; + } +} /* end exceptions for rssfoto01 */ .tag-category fieldset { /* tot joomla het zoekveld goed verbergt */ diff --git a/templateDetails.xml b/templateDetails.xml index b699ee9..c4bd415 100644 --- a/templateDetails.xml +++ b/templateDetails.xml @@ -8,8 +8,8 @@ wsa_bootstrap - 2.1.2 - 12-07-2023 + 2.1.3.dev + 30-09-2024 AHC Waasdorp info@waasdorpsoekhan.nl http://www.waasdorpsoekhan.nl From c08d67922086a5d320bb820de55e4ddac322e3aa Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Tue, 1 Oct 2024 09:15:31 +0000 Subject: [PATCH 02/82] 2.1.3.dev --- css/template.css | 12 ++++++------ index.php | 7 ++++--- scss/_template_css.scss | 6 +++--- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/css/template.css b/css/template.css index ceaf4d6..a6e0855 100644 --- a/css/template.css +++ b/css/template.css @@ -947,12 +947,12 @@ body.modal { overflow: hidden; } [class*="rssfoto"] .newsfeed li a img { - background-color: rgba(255, 255, 255, 0.75); - padding: 4px; - border: 1px solid lightgray; - border-radius: 5px; - box-shadow: 0 0 8px 4px lightgray; - margin: 5px; + background-color: rgba(255,255,255,0.75); + padding:4px; + border: 1px solid rgba(0,0,0,0.3); + border-radius: 5px; + box-shadow: 0 0 8px 4px rgba(0,0,0,0.2); + margin: 5px; } [class*="rssfoto"] .newsfeed li div.feed-item-description p:first-child { /* make unwanted image header text from newsfeed invisible */ diff --git a/index.php b/index.php index ba0c4a9..fa4043b 100644 --- a/index.php +++ b/index.php @@ -40,7 +40,8 @@ Joomla ge 4 stylesheets and javascript via webassets Joomla 3 addStylesheet, addScript 28-12-2021 default BS5 style and javascript in joomla.asset.json and overrides in code for lower BS versions and styleid specific template style - and removed conditional inclusion BS stylesheet an javascript + and removed conditional inclusion BS stylesheet an javascript + 01-10-2024 2.1.3 make content wider to display 3 columns in rssfot newsfeed */ // copied from cassiopeia use Joomla\CMS\Factory; @@ -221,8 +222,8 @@ } else { - $spanc = "span8 col-md-8"; - $spans = "span4 col-md-4"; + $spanc = "span9 col-md-9"; + $spans = "span3 col-md-3"; } $hi_mods = ($this->countModules('position-0')? ' hipos0': '') . ($this->countModules('icons')? ' hiicons': '') diff --git a/scss/_template_css.scss b/scss/_template_css.scss index fd6aaaf..dad71d9 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -23,7 +23,7 @@ // 20211229 header-inner navbar width 100% toegevoegd om toggler rechts te kunnen plaatsen, buiten header inner gaat dit al goed. // 20211230 padding .span12 extra voor BS3 in BS4/5 wordt col12 gebruikt en staan deze paddings al voor alle col-deimensies. // padding header-inner .navbar alleen nog 0 voor BS3 -// 20240930 Redesigned block for RSS (Flickr) fotos newsfeed component, because J4, J5 module class is not a suffix after the component class, +// 20240930 2.1.3 Redesigned block for RSS (Flickr) fotos newsfeed component, because J4, J5 module class is not a suffix after the component class, // but an extra class in the page header, ul may be used in stead of ol and Pias is stopped. So .newsfeed_rssfoto is approximately // replaced by by ._rssfoto .newsfeed. At the same time make more use of scss possibillities use css attribute match selectors and // remove unnecessary selectors. @@ -305,9 +305,9 @@ order: -1; { background-color: rgba(255,255,255,0.75); padding:4px; - border: 1px solid lightgray; + border: 1px solid rgba(0,0,0,0.3); border-radius: 5px; - box-shadow: 0 0 8px 4px lightgray; + box-shadow: 0 0 8px 4px rgba(0,0,0,0.2); margin: 5px; } From a881257a4fc870df2582d87f0e805fbdc42dd0c6 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Wed, 2 Oct 2024 12:10:07 +0000 Subject: [PATCH 03/82] 2.2.0 removed BS3, update BS4, BS5 to 4.6.2 and 5.3.3. --- README.md | 2 +- index.php | 63 +++++++----------- joomla.asset.json | 158 ++++++++++++++++++++++------------------------ 3 files changed, 99 insertions(+), 124 deletions(-) diff --git a/README.md b/README.md index 900cb19..9680ebc 100644 --- a/README.md +++ b/README.md @@ -9,5 +9,5 @@ This project is licensed under the [GNU GPL], version 3 or later. 2018 – 2021 © [Bram Waasdorp](http://www.waasdorpsoekhan.nl). ## Changelog -* 2.1.3.dev improvements rssfoto newsfeeds for J4,J5 +* 2.2.0.dev improvements rssfoto newsfeeds for J4,J5, remove suport BS3, use latest versions BS4 and BS5, remove some redundant code. * 2.1.2 removed hard returns from documentation field because j4.4 + doesn't accept that. diff --git a/index.php b/index.php index fa4043b..f8c7a0d 100644 --- a/index.php +++ b/index.php @@ -41,7 +41,9 @@ Joomla 3 addStylesheet, addScript 28-12-2021 default BS5 style and javascript in joomla.asset.json and overrides in code for lower BS versions and styleid specific template style and removed conditional inclusion BS stylesheet an javascript - 01-10-2024 2.1.3 make content wider to display 3 columns in rssfot newsfeed + 01-10-2024 2.1.3 make content wider to display 3 columns in rssfoto newsfeed + 02-10-2024 2.2.0 Remove support for BS (Bootstrap) 3, remove redundant span* classes inherited from grid Bootstrap 2 and used in Joomla 3, + which are replaced by col* classes since BS3 and Joomla 4. Updated to latest versions of BS4 (4.6.2) and BS5 (5.3.3) javascript and css and assosited libraries. */ // copied from cassiopeia use Joomla\CMS\Factory; @@ -127,22 +129,15 @@ // register overrides for older BS versions switch ($twbs_version) { // case "5" : { -// $wa->registerStyle('bootstrap.css', 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css', ['version'=>'5.1.3'], ['integrity' => 'sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3', 'crossorigin' => 'anonymous'],[]) -// ->registerScript('bootstrap.js', 'https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js', ['version'=>'5.1.3'], ['integrity' => 'sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p', 'crossorigin' => 'anonymous', 'defer' => TRUE],[]) +// $wa->registerStyle('bootstrap.css', 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css', ['version'=>'5.3.3'], ['integrity' => 'sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH', 'crossorigin' => 'anonymous'],[]) +// ->registerScript('bootstrap.js', 'https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js', ['version'=>'5.3.3'], ['integrity' => 'sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz', 'crossorigin' => 'anonymous', 'defer' => TRUE],[]) // ; // } // break; case "4" : { - $wa->registerStyle('bootstrap.css', 'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css', ['version'=>'4.3.1'], ['integrity' => 'sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T', 'crossorigin' => 'anonymous'],[]) - ->registerScript('popper.js', 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js', ['version'=>'1.14.7'], ['integrity' => 'sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1', 'crossorigin' => 'anonymous', 'defer' => TRUE],[]) - ->registerScript('bootstrap.js', 'https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js', ['version'=>'4.3.1'], ['integrity' => 'sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM', 'crossorigin' => 'anonymous', 'defer' => TRUE],['popper.js']) - ; - } - break; - case "3" : { - $wa->registerStyle('bootstrap.css', 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css', ['version'=>'3.3.7'], ['integrity' => 'sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u', 'crossorigin' => 'anonymous'],[]) - ->registerAndUseStyle('bootstrap.theme.css', 'https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css', ['version'=>'3.3.7'], ['integrity' => 'sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp', 'crossorigin' => 'anonymous'],['bootstrap.css']) - ->registerScript('bootstrap.js', 'jui/bootstrap.min.js', ['version'=>'3.3.7'], ['defer' => TRUE],['jquery']) + $wa->registerStyle('bootstrap.css', 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css', ['version'=>'4.6.2'], ['integrity' => 'sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N', 'crossorigin' => 'anonymous'],[]) + ->registerScript('jquery.js', 'https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js', ['version'=>'3.5.1'], ['integrity' => 'sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj', 'crossorigin' => 'anonymous', 'defer' => TRUE],[]) + ->registerScript('bootstrap.js', 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js', ['version'=>'4.6.2'], ['integrity' => 'sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct', 'crossorigin' => 'anonymous', 'defer' => TRUE],['popper.js']) ; } } @@ -156,20 +151,13 @@ // bootstrap stylesheets van cdn switch ($twbs_version) { case "5" : { - $attribs = array('id'=>'bootstrap.min.css', 'integrity' => 'sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3', 'crossorigin' => 'anonymous'); - $this->addStyleSheet('https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css', array('version'=>'5.1.3'), $attribs); + $this->addStyleSheet('https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css', array('version'=>'5.3.3'), + array('id'=>'bootstrap.min.css', 'integrity' => 'sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH', 'crossorigin' => 'anonymous')); } break; case "4" : { - $attribs = array('id'=>'bootstrap.min.css', 'integrity' => 'sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T', 'crossorigin' => 'anonymous'); - $this->addStyleSheet('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css', array('version'=>'4.3.1'), $attribs); - } -break; -case "3" : { -$attribs = array('id'=>'bootstrap.min.css', 'integrity' => 'sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u', 'crossorigin' => 'anonymous'); -$this->addStyleSheet('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css', array('version'=>'3.3.7'), $attribs); -$attribs = array('id'=>'bootstrap-theme.min.css', 'integrity' => 'sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp', 'crossorigin' => 'anonymous'); -$this->addStyleSheet('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css' , array('version'=>'3.3.7'), $attribs); + $this->addStyleSheet('href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css', array('version'=>'4.6.2'), + array('id'=>'bootstrap.min.css', 'integrity' => 'sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N', 'crossorigin' => 'anonymous')); } } // template stijl @@ -182,20 +170,15 @@ switch ($twbs_version) { case "5" : { - $this->addScript('https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js', array('version'=>'5.1.3'), - array('id'=>'bootstrap.min.js', 'integrity' => 'sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p', 'crossorigin' => 'anonymous')); + $this->addScript('https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js', array('version'=>'5.3.3'), + array('id'=>'bootstrap.min.js', 'integrity' => 'sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz', 'crossorigin' => 'anonymous')); } break; case "4" : { - $this->addScript('https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js', array('version'=>'1.14.7'), - array('id'=>'popper.js', 'integrity' => 'sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1', 'crossorigin' => 'anonymous')); - $this->addScript('https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js', array('version'=>'4.3.1'), - array('id'=>'bootstrap.min.js', 'integrity' => 'sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM', 'crossorigin' => 'anonymous')); - } -break; -case "3" :{ - $this->addScript('templates/' . $this->template . '/js/jui/bootstrap.min.js', array('version'=>'3.3.7'), - array('id'=>'bootstrap.min.js', 'defer'=>'defer')); + $this->addScript('https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js', array('version'=>'3.5.1'), + array('id'=>'jquery.js', 'integrity' => 'sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj', 'crossorigin' => 'anonymous')); + $this->addScript('https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js', array('version'=>'4.6.2'), + array('id'=>'bootstrap.min.js', 'integrity' => 'sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct', 'crossorigin' => 'anonymous')); } } @@ -212,18 +195,18 @@ // Adjusting content width if ($this->countModules('position-7') && $this->countModules('position-8')) { - $spanc = "span6 col-md-6" ; - $spans = "span3 col-md-3"; + $spanc = "col-md-6" ; + $spans = "col-md-3"; } elseif (!$this->countModules('position-7') && !$this->countModules('position-8')) { - $spanc = "span12 col-12"; + $spanc = "col-12"; } else { - $spanc = "span9 col-md-9"; - $spans = "span3 col-md-3"; + $spanc = "col-md-9"; + $spans = "col-md-3"; } $hi_mods = ($this->countModules('position-0')? ' hipos0': '') . ($this->countModules('icons')? ' hiicons': '') diff --git a/joomla.asset.json b/joomla.asset.json index d8abdc8..bedf217 100644 --- a/joomla.asset.json +++ b/joomla.asset.json @@ -1,84 +1,76 @@ { - "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json", - "name": "wsa_bootstrap", - "version": "2.1.0", - "description": "This file contains details of the default assets used by wsa_bootstrap template, a Joomla 3 and 4 site template.", - "license": "GPL-2.0-or-later", - "assets": [ - { - "name": "template.wsa_bootstrap", - "description": "The css file to be used when there is no specific styleid known, will be overridden by template.min..css.", - "type": "style", - "uri": "template.css", - "version": "2.1.0", - "dependencies": [ - "bootstrap.theme.css" - ] - }, - { - "name": "bootstrap.css", - "description": "The default css file to be used with bootstrap 5.1.3, (only) after it is used can be overridden in index.php by older versions", - "type": "style", - "uri": "https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css", - "version": "5.1.3", - "attributes" : { - "integrity": "sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3", - "crossorigin": "anonymous" - } - }, - { - "name": "bootstrap.theme.css", - "description": "The theme css file only used with bootstrap 3.3.7. therefore default empty url", - "type": "style", - "uri": "", - "dependencies": [ - "bootstrap.css" - ] - }, - { - "name": "bootstrap.js", - "description": "The default file containing the javascript used with bootstrap 5.1.3, can be overridden by older versions", - "type": "script", - "uri": "https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js", - "version": "5.1.3", - "attributes" : { - "defer": true, - "integrity": "sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p", - "crossorigin": "anonymous" - } - - }, - { - "name": "template.wsa_bootstrap", - "description": "The file containing the javascript for this template. bootstrap has to be registered before usinf this script.", - "type": "script", - "uri": "template.js", - "version": "2.1.0", - "attributes" : { - "defer": true - }, - "dependencies": [ - "core", - "bootstrap.js" - ] - }, - { - "name": "magnificpopup", - "type": "script", - "uri": "magnificpopup/MagnificPopupV1-1-0.js", - "version": "1.1.0", - "dependencies": [ - "jquery" - ] - }, - { - "name": "template.wsa_bootstrap", - "description": "Default with bootstrap 5 override with older bootstrap versions in code after this is used", - "type": "preset", - "dependencies": [ - "template.wsa_bootstrap#style", - "template.wsa_bootstrap#script" - ] - } - ] -} + "$schema" : "https://developer.joomla.org/schemas/json-schema/web_assets.json", + "name" : "wsa_bootstrap", + "version" : "2.2.0", + "description" : "This file contains details of the default assets used by wsa_bootstrap template, a Joomla 3 and 4 site template.", + "license" : "GPL-2.0-or-later", + "assets" : [{ + "name" : "template.wsa_bootstrap", + "description" : "The css file to be used when there is no specific styleid known, will be overridden by template.min..css.", + "type" : "style", + "uri" : "template.css", + "version" : "2.1.0", + "dependencies" : [ + "bootstrap.theme.css" + ] + }, { + "name" : "bootstrap.css", + "description" : "The default css file to be used with bootstrap 5.3.3, (only) after it is used can be overridden in index.php by older versions", + "type" : "style", + "uri" : "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css", + "version" : "5.3.3", + "attributes" : { + "integrity" : "sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH", + "crossorigin" : "anonymous" + } + }, { + "name" : "bootstrap.theme.css", + "description" : "The theme css file only used with bootstrap 3.3.7. therefore default empty url", + "type" : "style", + "uri" : "", + "dependencies" : [ + "bootstrap.css" + ] + }, { + "name" : "bootstrap.js", + "description" : "The default file containing the javascript used with bootstrap 5.1.3, can be overridden by older versions", + "type" : "script", + "uri" : "https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js", + "version" : "5.1.3", + "attributes" : { + "defer" : true, + "integrity" : "sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p", + "crossorigin" : "anonymous" + } + }, { + "name" : "template.wsa_bootstrap", + "description" : "The file containing the javascript for this template. bootstrap has to be registered before usinf this script.", + "type" : "script", + "uri" : "template.js", + "version" : "2.1.0", + "attributes" : { + "defer" : true + }, + "dependencies" : [ + "core", + "bootstrap.js" + ] + }, { + "name" : "magnificpopup", + "type" : "script", + "uri" : "magnificpopup/MagnificPopupV1-1-0.js", + "version" : "1.1.0", + "dependencies" : [ + "jquery" + ] + }, { + "name" : "template.wsa_bootstrap", + "description" : "Default with bootstrap 5 override with older bootstrap versions in code after this is used", + "type" : "preset", + "dependencies" : [ + "template.wsa_bootstrap#style", + "template.wsa_bootstrap#script" + ] + } + ] +} \ No newline at end of file From 3963cd10cb40464a4fb3070310a44869dcc092ec Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Wed, 2 Oct 2024 12:17:59 +0000 Subject: [PATCH 04/82] 2.2.0 dependency --- index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.php b/index.php index f8c7a0d..fe12fab 100644 --- a/index.php +++ b/index.php @@ -137,7 +137,7 @@ case "4" : { $wa->registerStyle('bootstrap.css', 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css', ['version'=>'4.6.2'], ['integrity' => 'sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N', 'crossorigin' => 'anonymous'],[]) ->registerScript('jquery.js', 'https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js', ['version'=>'3.5.1'], ['integrity' => 'sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj', 'crossorigin' => 'anonymous', 'defer' => TRUE],[]) - ->registerScript('bootstrap.js', 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js', ['version'=>'4.6.2'], ['integrity' => 'sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct', 'crossorigin' => 'anonymous', 'defer' => TRUE],['popper.js']) + ->registerScript('bootstrap.js', 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js', ['version'=>'4.6.2'], ['integrity' => 'sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct', 'crossorigin' => 'anonymous', 'defer' => TRUE],['jquery.js']) ; } } From ffa591948f5455876f63bc6c17286fec0e5dea00 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Wed, 2 Oct 2024 12:32:00 +0000 Subject: [PATCH 05/82] 2.2.0 --- language/en-GB/en-GB.tpl_wsa_bootstrap.ini | 10 +++++----- language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini | 10 +++++----- templateDetails.xml | 5 ++--- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/language/en-GB/en-GB.tpl_wsa_bootstrap.ini b/language/en-GB/en-GB.tpl_wsa_bootstrap.ini index fc95594..347e995 100644 --- a/language/en-GB/en-GB.tpl_wsa_bootstrap.ini +++ b/language/en-GB/en-GB.tpl_wsa_bootstrap.ini @@ -2,14 +2,14 @@ ; Copyright (C) 2015 - 2024 A.H.C. Waasdorp. All rights reserved. ; license GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php ; Note : All ini files need to be saved as UTF-8 -; 9-12-2023 v2.1.2 +; 2-10-2024 v2.2.2 COM_TEMPLATES_BACKGROUND_FIELDSET_LABEL="Background" COM_TEMPLATES_DEVELOPER_FIELDSET_LABEL="Developer" COM_TEMPLATES_NAVBAR_FIELDSET_LABEL="Navbar" COM_TEMPLATES_DOCUMENTATION_FIELDSET_LABEL="Documentation" COMPRESS_CSS_LABEL="Compress Css" COMPRESS_CSS_DESCRIPTION="Compress Css" -TPL_WSA_BOOTSTRAP_DESCRIPTION="Basic Template with bootstrap 5 (4 or 3) Joomla 4 and 3" +TPL_WSA_BOOTSTRAP_DESCRIPTION="Basic Template with bootstrap 5 or 4 Joomla 4 and 3" EXPLANATION0="First layer backgound (browserbackground)" EXPLANATION1="Second layer backgound (containerbackground)" EXPLANATION2="Third layer backgound (eg. logo)" @@ -74,8 +74,8 @@ WSA_NAVTEXT_HINT="eg Navbar text with an inline elemen WSA_NAVBARRIGHT_LABEL="Width NavbarRight:" WSA_NAVBARRIGHT_DESCRIPTION="Width NavbarRight module in pixels " -TPL_WSABOOTSTRAP_TWBS_VERSION="Use TWBS version 5, 3 or 4" -TPL_WSABOOTSTRAP_TWBS_VERSION_DESC="Use twitter bootstrap version 5, 3 or 4" +TPL_WSABOOTSTRAP_TWBS_VERSION="Use TWBS version 5 or 4" +TPL_WSABOOTSTRAP_TWBS_VERSION_DESC="Use twitter bootstrap version 5 or 4" TPL_WSABOOTSTRAP_INCLUDE_MP="Include magnific popup" TPL_WSABOOTSTRAP_INCLUDE_MP_DESC="Include magnific popup javascript and css, only needed if not included in template" @@ -87,7 +87,7 @@ BGLEFT_LABEL="Margin left background image:" BGPERCENTAGE="Percentage of background" BGPIXELS="Pixels" BGCOLOR_LABEL="Background color:" -WSA-DOCUMENTATION="Changes become effective after save template style with Developer / Compile LESS files: YES.

CSS classes for inline blog and tagged items lay-out
(leading articles in 1,2, or 3 colums other articles 1 ... 6, 8 (only blog) and 12 columns):
general: blog tab Page Display Page class: blog (is default).
general: tagged items tab Page Display Page class: blog.
leading articles (only blog) > 1 col: blog tab Page Display Page class: (add) lead-cols-2 or lead-cols-3.
other articles : blog tab Blog Layout # Columns: 1 ... 6, or 8 or 12.
other articles : tagged items tab Page Display Page class: cols-2 ... 6.
" +WSA-DOCUMENTATION="Changes become effective after save template style with Developer / Compile SCSS files: YES.

CSS classes for inline blog and tagged items lay-out
(leading articles in 1,2, or 3 colums other articles 1 ... 6, 8 (only blog) and 12 columns):
general: blog tab Page Display Page class: blog (is default).
general: tagged items tab Page Display Page class: blog.
leading articles (only blog) > 1 col: blog tab Page Display Page class: (add) lead-cols-2 or lead-cols-3.
other articles : blog tab Blog Layout # Columns: 1 ... 6, or 8 or 12.
other articles : tagged items tab Page Display Page class: cols-2 ... 6.
" WSA_CUSTOMCSS_LABEL="Custom css:" WSA_CUSTOMCSS_DESCRIPTION="Add custom css via custom css file from dir images/scss" WSA_CSS_FILENAME_LABEL="CSS filename:" diff --git a/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini b/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini index d4fa436..ab68dbe 100644 --- a/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini +++ b/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini @@ -2,14 +2,14 @@ ; Copyright (C) 2015 -2024 A.H.C. Waasdorp. All rights reserved. ; license GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php ; Note : All ini files need to be saved as UTF-8 -; 9-12-2023 v2.1.2 +; 2-10-2024 v2.2.0 COM_TEMPLATES_BACKGROUND_FIELDSET_LABEL="Achtergrond" COM_TEMPLATES_DEVELOPER_FIELDSET_LABEL="Ontwikkelaar" COM_TEMPLATES_NAVBAR_FIELDSET_LABEL="Navbar" COM_TEMPLATES_DOCUMENTATION_FIELDSET_LABEL="Documentatie" COMPRESS_CSS_LABEL="Comprimeer Css" COMPRESS_CSS_DESCRIPTION="Comprimeer Css" -TPL_WSA_BOOTSTRAP_DESCRIPTION="Basis Template met bootstrap 5, 3 of 4 Joomla 3 of 4" +TPL_WSA_BOOTSTRAP_DESCRIPTION="Basis Template met bootstrap 5 of 4 Joomla 3 of 4" EXPLANATION0="Onderste laag achtergrond (browserachtergrond)." EXPLANATION1="Tweede laag achtergrond (container achtergrond)" EXPLANATION2="Derde laag achtergrond (bv. logo)" @@ -76,8 +76,8 @@ WSA_NAVTEXT_HINT="bv: Navbar text with an inline eleme WSA_NAVBARRIGHT_LABEL="Breedte NavbarRight:" WSA_NAVBARRIGHT_DESCRIPTION="Breedte NavbarRight module in pixels " -TPL_WSABOOTSTRAP_TWBS_VERSION="Gebruik TWBS versie 5, 3 of 4" -TPL_WSABOOTSTRAP_TWBS_VERSION_DESC="Gebruik twitter bootstrap versie 5, 3 of 4" +TPL_WSABOOTSTRAP_TWBS_VERSION="Gebruik TWBS versie 5 of 4" +TPL_WSABOOTSTRAP_TWBS_VERSION_DESC="Gebruik twitter bootstrap versie 5 of 4" TPL_WSABOOTSTRAP_INCLUDE_MP="Magnific popup invoegen" TPL_WSABOOTSTRAP_INCLUDE_MP_DESC="Magnific popup javascript en css invoegen." @@ -89,7 +89,7 @@ BGLEFT_LABEL="Marge links van getoonde afbeelding:" BGPERCENTAGE="Percentage van achtergrond" BGPIXELS="Pixels" BGCOLOR_LABEL="afbeelding kleur:" -WSA-DOCUMENTATION="Wijzigingen worden pas effectief na opslaan template style met Ontwikkelaar / Compileer LESS files: JA.

CSS classe voor inline blog en getagde items lay-out
(hoofd artikelen in 1,2, or 3 kolommen andere artickelen 1 ... 6, 8 (allen blog), 12 kolommen):
algemeen: blog tab Paginaweergave paginaclass: (blog standaard).
algemeen: getagde items tab Paginaweergave paginaclass: blog.
hoofdartikelen > 1 kolom: (alleen) blog tab Paginaweergave paginaclass: (extra) lead-cols-2 or lead-cols-3.
andere artikelen: blog tab Blogweergave # Kolommen: 1...6 of 8 of 12.
andere artikelen: getagde items tab Paginaweergave paginaclass: cols-2...6.
" +WSA-DOCUMENTATION="Wijzigingen worden pas effectief na opslaan template style met Ontwikkelaar / Compileer SCSS files: JA.

CSS classe voor inline blog en getagde items lay-out
(hoofd artikelen in 1,2, or 3 kolommen andere artickelen 1 ... 6, 8 (allen blog), 12 kolommen):
algemeen: blog tab Paginaweergave paginaclass: (blog standaard).
algemeen: getagde items tab Paginaweergave paginaclass: blog.
hoofdartikelen > 1 kolom: (alleen) blog tab Paginaweergave paginaclass: (extra) lead-cols-2 or lead-cols-3.
andere artikelen: blog tab Blogweergave # Kolommen: 1...6 of 8 of 12.
andere artikelen: getagde items tab Paginaweergave paginaclass: cols-2...6.
" WSA_CUSTOMCSS_LABEL="Custom css:" WSA_CUSTOMCSS_DESCRIPTION="Voeg custom css toe via custom less bestand in dir images/scss" WSA_CSS_FILENAME_LABEL="CSS bestandnaam:" diff --git a/templateDetails.xml b/templateDetails.xml index c4bd415..e8887e4 100644 --- a/templateDetails.xml +++ b/templateDetails.xml @@ -362,9 +362,8 @@ description="WSA_CSS_FILENAME_DESCRIPTION" /> - - - + + Date: Wed, 2 Oct 2024 13:26:50 +0000 Subject: [PATCH 06/82] 2.2.0 --- joomla.asset.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/joomla.asset.json b/joomla.asset.json index bedf217..350da8a 100644 --- a/joomla.asset.json +++ b/joomla.asset.json @@ -33,13 +33,13 @@ ] }, { "name" : "bootstrap.js", - "description" : "The default file containing the javascript used with bootstrap 5.1.3, can be overridden by older versions", + "description" : "The default file containing the javascript used with bootstrap 5.3.3, can be overridden by older versions", "type" : "script", - "uri" : "https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js", - "version" : "5.1.3", + "uri" : "https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js", + "version" : "5.3.3", "attributes" : { "defer" : true, - "integrity" : "sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p", + "integrity" : "sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz", "crossorigin" : "anonymous" } }, { From 4f34cfb293c244d6214e18dfcf8aa4dd5d1f2967 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:07:24 +0000 Subject: [PATCH 07/82] 2.2.0 scssphp added --- README.md | 5 +- rules/compiler.php | 43 +- rules/scssphp/LICENSE.md | 20 + rules/scssphp/README.md | 71 + rules/scssphp/bin/pscss | 244 + rules/scssphp/composer.json | 117 + rules/scssphp/scss.inc.php | 21 + rules/scssphp/src/Base/Range.php | 57 + rules/scssphp/src/Block.php | 73 + rules/scssphp/src/Block/AtRootBlock.php | 37 + rules/scssphp/src/Block/CallableBlock.php | 46 + rules/scssphp/src/Block/ContentBlock.php | 38 + rules/scssphp/src/Block/DirectiveBlock.php | 38 + rules/scssphp/src/Block/EachBlock.php | 38 + rules/scssphp/src/Block/ElseBlock.php | 27 + rules/scssphp/src/Block/ElseifBlock.php | 33 + rules/scssphp/src/Block/ForBlock.php | 48 + rules/scssphp/src/Block/IfBlock.php | 38 + rules/scssphp/src/Block/MediaBlock.php | 38 + .../scssphp/src/Block/NestedPropertyBlock.php | 37 + rules/scssphp/src/Block/WhileBlock.php | 32 + rules/scssphp/src/Cache.php | 272 + rules/scssphp/src/Colors.php | 247 + rules/scssphp/src/CompilationResult.php | 69 + rules/scssphp/src/Compiler.php | 10514 ++++++++++++++++ rules/scssphp/src/Compiler/CachedResult.php | 77 + rules/scssphp/src/Compiler/Environment.php | 68 + .../src/Exception/CompilerException.php | 24 + .../scssphp/src/Exception/ParserException.php | 58 + .../scssphp/src/Exception/RangeException.php | 24 + rules/scssphp/src/Exception/SassException.php | 7 + .../src/Exception/SassScriptException.php | 32 + .../scssphp/src/Exception/ServerException.php | 26 + rules/scssphp/src/Formatter.php | 377 + rules/scssphp/src/Formatter/Compact.php | 52 + rules/scssphp/src/Formatter/Compressed.php | 83 + rules/scssphp/src/Formatter/Crunched.php | 87 + rules/scssphp/src/Formatter/Debug.php | 127 + rules/scssphp/src/Formatter/Expanded.php | 72 + rules/scssphp/src/Formatter/Nested.php | 238 + rules/scssphp/src/Formatter/OutputBlock.php | 68 + rules/scssphp/src/Logger/LoggerInterface.php | 48 + rules/scssphp/src/Logger/QuietLogger.php | 29 + rules/scssphp/src/Logger/StreamLogger.php | 62 + rules/scssphp/src/Node.php | 43 + rules/scssphp/src/Node/Number.php | 844 ++ rules/scssphp/src/OutputStyle.php | 62 + rules/scssphp/src/Parser.php | 4244 +++++++ rules/scssphp/src/SourceMap/Base64.php | 187 + rules/scssphp/src/SourceMap/Base64VLQ.php | 151 + .../src/SourceMap/SourceMapGenerator.php | 390 + rules/scssphp/src/Type.php | 211 + rules/scssphp/src/Util.php | 184 + rules/scssphp/src/Util/Path.php | 77 + rules/scssphp/src/ValueConverter.php | 95 + rules/scssphp/src/Version.php | 23 + rules/scssphp/src/Warn.php | 84 + templateDetails.xml | 2 +- 58 files changed, 20330 insertions(+), 29 deletions(-) create mode 100644 rules/scssphp/LICENSE.md create mode 100644 rules/scssphp/README.md create mode 100644 rules/scssphp/bin/pscss create mode 100644 rules/scssphp/composer.json create mode 100644 rules/scssphp/scss.inc.php create mode 100644 rules/scssphp/src/Base/Range.php create mode 100644 rules/scssphp/src/Block.php create mode 100644 rules/scssphp/src/Block/AtRootBlock.php create mode 100644 rules/scssphp/src/Block/CallableBlock.php create mode 100644 rules/scssphp/src/Block/ContentBlock.php create mode 100644 rules/scssphp/src/Block/DirectiveBlock.php create mode 100644 rules/scssphp/src/Block/EachBlock.php create mode 100644 rules/scssphp/src/Block/ElseBlock.php create mode 100644 rules/scssphp/src/Block/ElseifBlock.php create mode 100644 rules/scssphp/src/Block/ForBlock.php create mode 100644 rules/scssphp/src/Block/IfBlock.php create mode 100644 rules/scssphp/src/Block/MediaBlock.php create mode 100644 rules/scssphp/src/Block/NestedPropertyBlock.php create mode 100644 rules/scssphp/src/Block/WhileBlock.php create mode 100644 rules/scssphp/src/Cache.php create mode 100644 rules/scssphp/src/Colors.php create mode 100644 rules/scssphp/src/CompilationResult.php create mode 100644 rules/scssphp/src/Compiler.php create mode 100644 rules/scssphp/src/Compiler/CachedResult.php create mode 100644 rules/scssphp/src/Compiler/Environment.php create mode 100644 rules/scssphp/src/Exception/CompilerException.php create mode 100644 rules/scssphp/src/Exception/ParserException.php create mode 100644 rules/scssphp/src/Exception/RangeException.php create mode 100644 rules/scssphp/src/Exception/SassException.php create mode 100644 rules/scssphp/src/Exception/SassScriptException.php create mode 100644 rules/scssphp/src/Exception/ServerException.php create mode 100644 rules/scssphp/src/Formatter.php create mode 100644 rules/scssphp/src/Formatter/Compact.php create mode 100644 rules/scssphp/src/Formatter/Compressed.php create mode 100644 rules/scssphp/src/Formatter/Crunched.php create mode 100644 rules/scssphp/src/Formatter/Debug.php create mode 100644 rules/scssphp/src/Formatter/Expanded.php create mode 100644 rules/scssphp/src/Formatter/Nested.php create mode 100644 rules/scssphp/src/Formatter/OutputBlock.php create mode 100644 rules/scssphp/src/Logger/LoggerInterface.php create mode 100644 rules/scssphp/src/Logger/QuietLogger.php create mode 100644 rules/scssphp/src/Logger/StreamLogger.php create mode 100644 rules/scssphp/src/Node.php create mode 100644 rules/scssphp/src/Node/Number.php create mode 100644 rules/scssphp/src/OutputStyle.php create mode 100644 rules/scssphp/src/Parser.php create mode 100644 rules/scssphp/src/SourceMap/Base64.php create mode 100644 rules/scssphp/src/SourceMap/Base64VLQ.php create mode 100644 rules/scssphp/src/SourceMap/SourceMapGenerator.php create mode 100644 rules/scssphp/src/Type.php create mode 100644 rules/scssphp/src/Util.php create mode 100644 rules/scssphp/src/Util/Path.php create mode 100644 rules/scssphp/src/ValueConverter.php create mode 100644 rules/scssphp/src/Version.php create mode 100644 rules/scssphp/src/Warn.php diff --git a/README.md b/README.md index 9680ebc..fd31de8 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,14 @@ - up to version 1.3.5 compatible with Joomla 3 - from version 1.4 compatible with Joomla 3.8 + - from version 2.1.0 Bootstrap 3,4,5 and more specific Joomla 4 code. like use of webassets in Joomla 4. +- from version 2.2 Bootstrap 4 and 5 Joomla 4+ (although J 3.8+ may still work) ## Copyright and License This project is licensed under the [GNU GPL], version 3 or later. -2018 – 2021 © [Bram Waasdorp](http://www.waasdorpsoekhan.nl). +2018 – 2024 © [Bram Waasdorp](http://www.waasdorpsoekhan.nl). ## Changelog * 2.2.0.dev improvements rssfoto newsfeeds for J4,J5, remove suport BS3, use latest versions BS4 and BS5, remove some redundant code. + original scss files of BS4 and BS5 in folders scss bs4 and bs5. + New scss compiler scssphp/scssphp 1.13.0 as continuation of leafo/scssphp * 2.1.2 removed hard returns from documentation field because j4.4 + doesn't accept that. diff --git a/rules/compiler.php b/rules/compiler.php index 7c42983..b02f33f 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -10,39 +10,26 @@ de save v 23-2-2016 v 20-3-2016 bootstrap 3 -V 6-4-2016 magnific popup -V 24-4-2016 dropdown menu in apart .less bestand -V 16-5-2016 kleuren dropdownmenu variabel gemaakt. -V 18-5-2016 compiler uit template.php gebruikt, deze werkt beter met mixins en functies -V 19-5-2016 kleine aanpassing instellingen compiler -V 22-5-2016 brandImage toegevoegd -V 27-5-2016 kleuren navbar toggle button -V 29-5-2016 breakpointmobile verwijderd. -V juni 2016 overgang naar SASS (scss) -v 12-6-2016 fout in bg1Pos (weer) opgelost -v 15-7-2016 grid.scss toegevoegd -v 28-12-2016 alle backgroundimages via html niet meer css, wel twee groottes -v 2-1-2017 breakpoint voor sizes -v 5-1-2017 ook breakpoint small -v 27-4-2017 andere naam css mogelijk ook templatestyleid overal doorgevoerd. v 7-1-2018 J3.8 j4 namespace v 19-1-2019 custom scss v 20-1-2019 wsaNavbarRightWidth v 25-1-2019 bootstrap 4 .scss files toegevoegd ter voorbereiding op uitbreiding breakpoints -v 30-1-2019 uitbreiding breakpoints voorwasardelijk in style<...>.scss schrijven ipv in apart .scss file. +v 30-1-2019 uitbreiding breakpoints voorwaardelijk in style<...>.scss schrijven ipv in apart .scss file. V 2-2-2019 nieuwe versie van Leafo\ScssPhp\Compiler 0.7.6 V 6-2-2019 navbar kleuren default bs4 ipv 3 v 7-2 2019 nog maar 1 set achtergondafbeeldingen en 2 kleuren. -v 10-2-2019 naam veranderd en enkele aanpassingen voor v4 naam van het bestand moet compiler.php blijven, omdat deze gemoemd wordt in validat cluasule van compiler veld +v 10-2-2019 naam veranderd en enkele aanpassingen voor v4 naam van het bestand moet compiler.php blijven, omdat deze gemoemd wordt in validat clausule van compiler veld v 11-2-2019 params as an object v 20-3-2019 border en active link colors nav-bar v 26-12-2021 added Joomla version info to use J4 specific code. 2023-12-07 resolved Unknown constant path_parts (is var $path_parts). +2024-10-03 v2.2.0 New scss compiler scssphp/scssphp 1.13.0 as continuation of leafo/scssphp. remove Bootstrap 3, use latest versions 5.3.3 and 4.6.2 + of BS 5 and 4. */ defined('_JEXEC') or die('caught by _JEXEC'); -use Leafo\ScssPhp\Compiler; -use Leafo\ScssPhp\Server; +use ScssPhp\ScssPhp\Compiler; +//use Leafo\ScssPhp\Server; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormRule; @@ -96,23 +83,25 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input { /* creeren en compileren */ // scss compiler van leafo http://leafo.github.io/scssphp/ -require_once "leafo/scss.inc.php"; -require_once "leafo/src/Server.php"; +// require_once "leafo/scss.inc.php"; +// require_once "leafo/src/Server.php"; +// scss compiler van scssphp https://scssphp.github.io/scssphp/ + require_once "scssphp/scss.inc.php"; $scss = new Compiler(); if ( htmlspecialchars($params->compress) == "1") { -$scss->setFormatter('Leafo\ScssPhp\Formatter\Crunched'); + $scss->setOutputStyle ('\ScssPhp\ScssPhp\OutputStyle::COMPRESSED'); } else { // voor debug netter formatteren en commentaren behouden. - $scss->setFormatter('Leafo\ScssPhp\Formatter\Expanded'); + $scss->setOutputStyle ('\ScssPhp\ScssPhp\OutputStyle::EXPANDED'); // $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); } -$server = new Server($currentpath. '/../scss', null, $scss); +//$server = new Server($currentpath. '/../scss', null, $scss); //$server->serve(); @@ -518,14 +507,14 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input /* einde opslaam style parameters in style.scss bestanden */ /* scss files compileren naar .css */ -$server->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/' . $wsaCssFilename); +$scss->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/' . $wsaCssFilename); if ($home == 1 ) {/* niet kunnen vinden van templatestyleid bij root (lijkt inmiddels opgelost te zijn)*/ - $server->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/template.min.' . '.css'); + $scss->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/template.min.' . '.css'); /* ivm &tmpl=component */ - $server->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/template' . '.css'); + $scss->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/template' . '.css'); } /* einde les files compileren naar .css */ diff --git a/rules/scssphp/LICENSE.md b/rules/scssphp/LICENSE.md new file mode 100644 index 0000000..afcfdfb --- /dev/null +++ b/rules/scssphp/LICENSE.md @@ -0,0 +1,20 @@ +Copyright (c) 2015 Leaf Corcoran, http://scssphp.github.io/scssphp + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/rules/scssphp/README.md b/rules/scssphp/README.md new file mode 100644 index 0000000..65bb93e --- /dev/null +++ b/rules/scssphp/README.md @@ -0,0 +1,71 @@ +# scssphp +### + +![Build](https://github.com/scssphp/scssphp/workflows/CI/badge.svg) +[![License](https://poser.pugx.org/scssphp/scssphp/license)](https://packagist.org/packages/scssphp/scssphp) + +`scssphp` is a compiler for SCSS written in PHP. + +Checkout the homepage, , for directions on how to use. + +## Running Tests + +`scssphp` uses [PHPUnit](https://github.com/sebastianbergmann/phpunit) for testing. + +Run the following command from the root directory to run every test: + + vendor/bin/phpunit tests + +There are several tests in the `tests/` directory: + +* `ApiTest.php` contains various unit tests that test the PHP interface. +* `ExceptionTest.php` contains unit tests that test for exceptions thrown by the parser and compiler. +* `FailingTest.php` contains tests reported in Github issues that demonstrate compatibility bugs. +* `InputTest.php` compiles every `.scss` file in the `tests/inputs` directory + then compares to the respective `.css` file in the `tests/outputs` directory. +* `SassSpecTest.php` extracts tests from the `sass/sass-spec` repository. + +When changing any of the tests in `tests/inputs`, the tests will most likely +fail because the output has changed. Once you verify that the output is correct +you can run the following command to rebuild all the tests: + + BUILD=1 vendor/bin/phpunit tests + +This will compile all the tests, and save results into `tests/outputs`. It also +updates the list of excluded specs from sass-spec. + +To enable the full `sass-spec` compatibility tests: + + TEST_SASS_SPEC=1 vendor/bin/phpunit tests + +## Coding Standard + +`scssphp` source conforms to [PSR12](https://www.php-fig.org/psr/psr-12/). + +Run the following command from the root directory to check the code for "sniffs". + + vendor/bin/phpcs --standard=PSR12 --extensions=php bin src tests *.php + +## Static Analysis + +`scssphp` uses [phpstan](https://phpstan.org/) for static analysis. + +Run the following command from the root directory to analyse the codebase: + + make phpstan + +As most of the codebase is composed of legacy code which cannot be type-checked +fully, the setup contains a baseline file with all errors we want to ignore. In +particular, we ignore all errors related to not specifying the types inside arrays +when these arrays correspond to the representation of Sass values and Sass AST nodes +in the parser and compiler. +When contributing, the proper process to deal with static analysis is the following: + +1. Make your change in the codebase +2. Run `make phpstan` +3. Fix errors reported by phpstan when possible +4. Repeat step 2 and 3 until nothing gets fixed anymore at step 3 +5. Run `make phpstan-baseline` to regenerate the phpstan baseline + +Additions to the baseline will be reviewed to avoid ignoring errors that should have +been fixed. diff --git a/rules/scssphp/bin/pscss b/rules/scssphp/bin/pscss new file mode 100644 index 0000000..0f009d6 --- /dev/null +++ b/rules/scssphp/bin/pscss @@ -0,0 +1,244 @@ +#!/usr/bin/env php +parse($data)), true)); + + fwrite(STDERR, 'Warning: the --dump-tree option is deprecated. Use proper debugging tools instead.'); + + exit(); +} + +$scss = new Compiler(); + +if ($loadPaths) { + $scss->setImportPaths($loadPaths); +} + +if ($style) { + if ($style === OutputStyle::COMPRESSED || $style === OutputStyle::EXPANDED) { + $scss->setOutputStyle($style); + } else { + fwrite(STDERR, "WARNING: the $style style is deprecated.\n"); + $scss->setFormatter('ScssPhp\\ScssPhp\\Formatter\\' . ucfirst($style)); + } +} + +$outputFile = isset($arguments[1]) ? $arguments[1] : null; +$sourceMapFile = null; + +if ($sourceMap) { + $sourceMapOptions = array( + 'outputSourceFiles' => $embedSources, + ); + if ($embedSourceMap || $outputFile === null) { + $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); + } else { + $sourceMapFile = $outputFile . '.map'; + $sourceMapOptions['sourceMapWriteTo'] = $sourceMapFile; + $sourceMapOptions['sourceMapURL'] = basename($sourceMapFile); + $sourceMapOptions['sourceMapBasepath'] = getcwd(); + $sourceMapOptions['sourceMapFilename'] = basename($outputFile); + + $scss->setSourceMap(Compiler::SOURCE_MAP_FILE); + } + + $scss->setSourceMapOptions($sourceMapOptions); +} + +if ($encoding) { + $scss->setEncoding($encoding); +} + +try { + $result = $scss->compileString($data, $inputFile); +} catch (SassException $e) { + fwrite(STDERR, 'Error: '.$e->getMessage()."\n"); + exit(1); +} + +if ($outputFile) { + file_put_contents($outputFile, $result->getCss()); + + if ($sourceMapFile !== null && $result->getSourceMap() !== null) { + file_put_contents($sourceMapFile, $result->getSourceMap()); + } +} else { + echo $result->getCss(); +} diff --git a/rules/scssphp/composer.json b/rules/scssphp/composer.json new file mode 100644 index 0000000..d17ffb9 --- /dev/null +++ b/rules/scssphp/composer.json @@ -0,0 +1,117 @@ +{ + "name": "scssphp/scssphp", + "type": "library", + "description": "scssphp is a compiler for SCSS written in PHP.", + "keywords": ["css", "stylesheet", "scss", "sass", "less"], + "homepage": "http://scssphp.github.io/scssphp/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthon Pang", + "email": "apang@softwaredevelopment.ca", + "homepage": "https://github.com/robocoder" + }, + { + "name": "Cédric Morin", + "email": "cedric@yterium.com", + "homepage": "https://github.com/Cerdic" + } + ], + "autoload": { + "psr-4": { "ScssPhp\\ScssPhp\\": "src/" } + }, + "autoload-dev": { + "psr-4": { "ScssPhp\\ScssPhp\\Tests\\": "tests/" } + }, + "require": { + "php": ">=5.6.0", + "ext-json": "*", + "ext-ctype": "*" + }, + "suggest": { + "ext-mbstring": "For best performance, mbstring should be installed as it is faster than ext-iconv", + "ext-iconv": "Can be used as fallback when ext-mbstring is not available" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4", + "sass/sass-spec": "*", + "squizlabs/php_codesniffer": "~3.5", + "symfony/phpunit-bridge": "^5.1", + "thoughtbot/bourbon": "^7.0", + "twbs/bootstrap": "~5.0", + "twbs/bootstrap4": "4.6.1", + "zurb/foundation": "~6.7.0" + }, + "repositories": [ + { + "type": "package", + "package": { + "name": "sass/sass-spec", + "version": "2022.08.19", + "source": { + "type": "git", + "url": "https://github.com/sass/sass-spec.git", + "reference": "2bdc199723a3445d5badac3ac774105698f08861" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sass/sass-spec/zipball/2bdc199723a3445d5badac3ac774105698f08861", + "reference": "2bdc199723a3445d5badac3ac774105698f08861", + "shasum": "" + } + } + }, + { + "type": "package", + "package": { + "name": "thoughtbot/bourbon", + "version": "v7.0.0", + "source": { + "type": "git", + "url": "https://github.com/thoughtbot/bourbon.git", + "reference": "fbe338ee6807e7f7aa996d82c8a16f248bb149b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thoughtbot/bourbon/zipball/fbe338ee6807e7f7aa996d82c8a16f248bb149b3", + "reference": "fbe338ee6807e7f7aa996d82c8a16f248bb149b3", + "shasum": "" + } + } + }, + { + "type": "package", + "package": { + "name": "twbs/bootstrap4", + "version": "v4.6.1", + "source": { + "type": "git", + "url": "https://github.com/twbs/bootstrap.git", + "reference": "043a03c95a2ad6738f85b65e53b9dbdfb03b8d10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twbs/bootstrap/zipball/043a03c95a2ad6738f85b65e53b9dbdfb03b8d10", + "reference": "043a03c95a2ad6738f85b65e53b9dbdfb03b8d10", + "shasum": "" + } + } + } + ], + "bin": ["bin/pscss"], + "config": { + "sort-packages": true, + "allow-plugins": { + "bamarni/composer-bin-plugin": true + } + }, + "extra": { + "bamarni-bin": { + "forward-command": false, + "bin-links": false + } + } +} diff --git a/rules/scssphp/scss.inc.php b/rules/scssphp/scss.inc.php new file mode 100644 index 0000000..4598378 --- /dev/null +++ b/rules/scssphp/scss.inc.php @@ -0,0 +1,21 @@ + + * + * @internal + */ +class Range +{ + /** + * @var float|int + */ + public $first; + + /** + * @var float|int + */ + public $last; + + /** + * Initialize range + * + * @param int|float $first + * @param int|float $last + */ + public function __construct($first, $last) + { + $this->first = $first; + $this->last = $last; + } + + /** + * Test for inclusion in range + * + * @param int|float $value + * + * @return bool + */ + public function includes($value) + { + return $value >= $this->first && $value <= $this->last; + } +} diff --git a/rules/scssphp/src/Block.php b/rules/scssphp/src/Block.php new file mode 100644 index 0000000..96668dc --- /dev/null +++ b/rules/scssphp/src/Block.php @@ -0,0 +1,73 @@ + + * + * @internal + */ +class Block +{ + /** + * @var string|null + */ + public $type; + + /** + * @var Block|null + */ + public $parent; + + /** + * @var string + */ + public $sourceName; + + /** + * @var int + */ + public $sourceIndex; + + /** + * @var int + */ + public $sourceLine; + + /** + * @var int + */ + public $sourceColumn; + + /** + * @var array|null + */ + public $selectors; + + /** + * @var array + */ + public $comments; + + /** + * @var array + */ + public $children; + + /** + * @var Block|null + */ + public $selfParent; +} diff --git a/rules/scssphp/src/Block/AtRootBlock.php b/rules/scssphp/src/Block/AtRootBlock.php new file mode 100644 index 0000000..41842c2 --- /dev/null +++ b/rules/scssphp/src/Block/AtRootBlock.php @@ -0,0 +1,37 @@ +type = Type::T_AT_ROOT; + } +} diff --git a/rules/scssphp/src/Block/CallableBlock.php b/rules/scssphp/src/Block/CallableBlock.php new file mode 100644 index 0000000..9b32d8c --- /dev/null +++ b/rules/scssphp/src/Block/CallableBlock.php @@ -0,0 +1,46 @@ +|null + */ + public $args; + + /** + * @var Environment|null + */ + public $parentEnv; + + /** + * @param string $type + */ + public function __construct($type) + { + $this->type = $type; + } +} diff --git a/rules/scssphp/src/Block/ContentBlock.php b/rules/scssphp/src/Block/ContentBlock.php new file mode 100644 index 0000000..8708498 --- /dev/null +++ b/rules/scssphp/src/Block/ContentBlock.php @@ -0,0 +1,38 @@ +type = Type::T_INCLUDE; + } +} diff --git a/rules/scssphp/src/Block/DirectiveBlock.php b/rules/scssphp/src/Block/DirectiveBlock.php new file mode 100644 index 0000000..22b346e --- /dev/null +++ b/rules/scssphp/src/Block/DirectiveBlock.php @@ -0,0 +1,38 @@ +type = Type::T_DIRECTIVE; + } +} diff --git a/rules/scssphp/src/Block/EachBlock.php b/rules/scssphp/src/Block/EachBlock.php new file mode 100644 index 0000000..1217994 --- /dev/null +++ b/rules/scssphp/src/Block/EachBlock.php @@ -0,0 +1,38 @@ +type = Type::T_EACH; + } +} diff --git a/rules/scssphp/src/Block/ElseBlock.php b/rules/scssphp/src/Block/ElseBlock.php new file mode 100644 index 0000000..6abb4d7 --- /dev/null +++ b/rules/scssphp/src/Block/ElseBlock.php @@ -0,0 +1,27 @@ +type = Type::T_ELSE; + } +} diff --git a/rules/scssphp/src/Block/ElseifBlock.php b/rules/scssphp/src/Block/ElseifBlock.php new file mode 100644 index 0000000..f732c2d --- /dev/null +++ b/rules/scssphp/src/Block/ElseifBlock.php @@ -0,0 +1,33 @@ +type = Type::T_ELSEIF; + } +} diff --git a/rules/scssphp/src/Block/ForBlock.php b/rules/scssphp/src/Block/ForBlock.php new file mode 100644 index 0000000..9629441 --- /dev/null +++ b/rules/scssphp/src/Block/ForBlock.php @@ -0,0 +1,48 @@ +type = Type::T_FOR; + } +} diff --git a/rules/scssphp/src/Block/IfBlock.php b/rules/scssphp/src/Block/IfBlock.php new file mode 100644 index 0000000..659c7c2 --- /dev/null +++ b/rules/scssphp/src/Block/IfBlock.php @@ -0,0 +1,38 @@ + + */ + public $cases = []; + + public function __construct() + { + $this->type = Type::T_IF; + } +} diff --git a/rules/scssphp/src/Block/MediaBlock.php b/rules/scssphp/src/Block/MediaBlock.php new file mode 100644 index 0000000..ab975c7 --- /dev/null +++ b/rules/scssphp/src/Block/MediaBlock.php @@ -0,0 +1,38 @@ +type = Type::T_MEDIA; + } +} diff --git a/rules/scssphp/src/Block/NestedPropertyBlock.php b/rules/scssphp/src/Block/NestedPropertyBlock.php new file mode 100644 index 0000000..1ea4a6c --- /dev/null +++ b/rules/scssphp/src/Block/NestedPropertyBlock.php @@ -0,0 +1,37 @@ +type = Type::T_NESTED_PROPERTY; + } +} diff --git a/rules/scssphp/src/Block/WhileBlock.php b/rules/scssphp/src/Block/WhileBlock.php new file mode 100644 index 0000000..ac18d4e --- /dev/null +++ b/rules/scssphp/src/Block/WhileBlock.php @@ -0,0 +1,32 @@ +type = Type::T_WHILE; + } +} diff --git a/rules/scssphp/src/Cache.php b/rules/scssphp/src/Cache.php new file mode 100644 index 0000000..9731c60 --- /dev/null +++ b/rules/scssphp/src/Cache.php @@ -0,0 +1,272 @@ + + * + * @internal + */ +class Cache +{ + const CACHE_VERSION = 1; + + /** + * directory used for storing data + * + * @var string|false + */ + public static $cacheDir = false; + + /** + * prefix for the storing data + * + * @var string + */ + public static $prefix = 'scssphp_'; + + /** + * force a refresh : 'once' for refreshing the first hit on a cache only, true to never use the cache in this hit + * + * @var bool|string + */ + public static $forceRefresh = false; + + /** + * specifies the number of seconds after which data cached will be seen as 'garbage' and potentially cleaned up + * + * @var int + */ + public static $gcLifetime = 604800; + + /** + * array of already refreshed cache if $forceRefresh==='once' + * + * @var array + */ + protected static $refreshed = []; + + /** + * Constructor + * + * @param array $options + * + * @phpstan-param array{cacheDir?: string, prefix?: string, forceRefresh?: string} $options + */ + public function __construct($options) + { + // check $cacheDir + if (isset($options['cacheDir'])) { + self::$cacheDir = $options['cacheDir']; + } + + if (empty(self::$cacheDir)) { + throw new Exception('cacheDir not set'); + } + + if (isset($options['prefix'])) { + self::$prefix = $options['prefix']; + } + + if (empty(self::$prefix)) { + throw new Exception('prefix not set'); + } + + if (isset($options['forceRefresh'])) { + self::$forceRefresh = $options['forceRefresh']; + } + + self::checkCacheDir(); + } + + /** + * Get the cached result of $operation on $what, + * which is known as dependant from the content of $options + * + * @param string $operation parse, compile... + * @param mixed $what content key (e.g., filename to be treated) + * @param array $options any option that affect the operation result on the content + * @param int|null $lastModified last modified timestamp + * + * @return mixed + * + * @throws \Exception + */ + public function getCache($operation, $what, $options = [], $lastModified = null) + { + $fileCache = self::$cacheDir . self::cacheName($operation, $what, $options); + + if ( + ((self::$forceRefresh === false) || (self::$forceRefresh === 'once' && + isset(self::$refreshed[$fileCache]))) && file_exists($fileCache) + ) { + $cacheTime = filemtime($fileCache); + + if ( + (\is_null($lastModified) || $cacheTime > $lastModified) && + $cacheTime + self::$gcLifetime > time() + ) { + $c = file_get_contents($fileCache); + $c = unserialize($c); + + if (\is_array($c) && isset($c['value'])) { + return $c['value']; + } + } + } + + return null; + } + + /** + * Put in cache the result of $operation on $what, + * which is known as dependant from the content of $options + * + * @param string $operation + * @param mixed $what + * @param mixed $value + * @param array $options + * + * @return void + */ + public function setCache($operation, $what, $value, $options = []) + { + $fileCache = self::$cacheDir . self::cacheName($operation, $what, $options); + + $c = ['value' => $value]; + $c = serialize($c); + + file_put_contents($fileCache, $c); + + if (self::$forceRefresh === 'once') { + self::$refreshed[$fileCache] = true; + } + } + + /** + * Get the cache name for the caching of $operation on $what, + * which is known as dependant from the content of $options + * + * @param string $operation + * @param mixed $what + * @param array $options + * + * @return string + */ + private static function cacheName($operation, $what, $options = []) + { + $t = [ + 'version' => self::CACHE_VERSION, + 'scssphpVersion' => Version::VERSION, + 'operation' => $operation, + 'what' => $what, + 'options' => $options + ]; + + $t = self::$prefix + . sha1(json_encode($t)) + . ".$operation" + . ".scsscache"; + + return $t; + } + + /** + * Check that the cache dir exists and is writeable + * + * @return void + * + * @throws \Exception + */ + public static function checkCacheDir() + { + self::$cacheDir = str_replace('\\', '/', self::$cacheDir); + self::$cacheDir = rtrim(self::$cacheDir, '/') . '/'; + + if (! is_dir(self::$cacheDir)) { + throw new Exception('Cache directory doesn\'t exist: ' . self::$cacheDir); + } + + if (! is_writable(self::$cacheDir)) { + throw new Exception('Cache directory isn\'t writable: ' . self::$cacheDir); + } + } + + /** + * Delete unused cached files + * + * @return void + */ + public static function cleanCache() + { + static $clean = false; + + if ($clean || empty(self::$cacheDir)) { + return; + } + + $clean = true; + + // only remove files with extensions created by SCSSPHP Cache + // css files removed based on the list files + $removeTypes = ['scsscache' => 1]; + + $files = scandir(self::$cacheDir); + + if (! $files) { + return; + } + + $checkTime = time() - self::$gcLifetime; + + foreach ($files as $file) { + // don't delete if the file wasn't created with SCSSPHP Cache + if (strpos($file, self::$prefix) !== 0) { + continue; + } + + $parts = explode('.', $file); + $type = array_pop($parts); + + if (! isset($removeTypes[$type])) { + continue; + } + + $fullPath = self::$cacheDir . $file; + $mtime = filemtime($fullPath); + + // don't delete if it's a relatively new file + if ($mtime > $checkTime) { + continue; + } + + unlink($fullPath); + } + } +} diff --git a/rules/scssphp/src/Colors.php b/rules/scssphp/src/Colors.php new file mode 100644 index 0000000..2df3999 --- /dev/null +++ b/rules/scssphp/src/Colors.php @@ -0,0 +1,247 @@ + + * + * @internal + */ +class Colors +{ + /** + * CSS Colors + * + * @see http://www.w3.org/TR/css3-color + * + * @var array + */ + protected static $cssColors = [ + 'aliceblue' => '240,248,255', + 'antiquewhite' => '250,235,215', + 'aqua' => '0,255,255', + 'cyan' => '0,255,255', + 'aquamarine' => '127,255,212', + 'azure' => '240,255,255', + 'beige' => '245,245,220', + 'bisque' => '255,228,196', + 'black' => '0,0,0', + 'blanchedalmond' => '255,235,205', + 'blue' => '0,0,255', + 'blueviolet' => '138,43,226', + 'brown' => '165,42,42', + 'burlywood' => '222,184,135', + 'cadetblue' => '95,158,160', + 'chartreuse' => '127,255,0', + 'chocolate' => '210,105,30', + 'coral' => '255,127,80', + 'cornflowerblue' => '100,149,237', + 'cornsilk' => '255,248,220', + 'crimson' => '220,20,60', + 'darkblue' => '0,0,139', + 'darkcyan' => '0,139,139', + 'darkgoldenrod' => '184,134,11', + 'darkgray' => '169,169,169', + 'darkgrey' => '169,169,169', + 'darkgreen' => '0,100,0', + 'darkkhaki' => '189,183,107', + 'darkmagenta' => '139,0,139', + 'darkolivegreen' => '85,107,47', + 'darkorange' => '255,140,0', + 'darkorchid' => '153,50,204', + 'darkred' => '139,0,0', + 'darksalmon' => '233,150,122', + 'darkseagreen' => '143,188,143', + 'darkslateblue' => '72,61,139', + 'darkslategray' => '47,79,79', + 'darkslategrey' => '47,79,79', + 'darkturquoise' => '0,206,209', + 'darkviolet' => '148,0,211', + 'deeppink' => '255,20,147', + 'deepskyblue' => '0,191,255', + 'dimgray' => '105,105,105', + 'dimgrey' => '105,105,105', + 'dodgerblue' => '30,144,255', + 'firebrick' => '178,34,34', + 'floralwhite' => '255,250,240', + 'forestgreen' => '34,139,34', + 'fuchsia' => '255,0,255', + 'magenta' => '255,0,255', + 'gainsboro' => '220,220,220', + 'ghostwhite' => '248,248,255', + 'gold' => '255,215,0', + 'goldenrod' => '218,165,32', + 'gray' => '128,128,128', + 'grey' => '128,128,128', + 'green' => '0,128,0', + 'greenyellow' => '173,255,47', + 'honeydew' => '240,255,240', + 'hotpink' => '255,105,180', + 'indianred' => '205,92,92', + 'indigo' => '75,0,130', + 'ivory' => '255,255,240', + 'khaki' => '240,230,140', + 'lavender' => '230,230,250', + 'lavenderblush' => '255,240,245', + 'lawngreen' => '124,252,0', + 'lemonchiffon' => '255,250,205', + 'lightblue' => '173,216,230', + 'lightcoral' => '240,128,128', + 'lightcyan' => '224,255,255', + 'lightgoldenrodyellow' => '250,250,210', + 'lightgray' => '211,211,211', + 'lightgrey' => '211,211,211', + 'lightgreen' => '144,238,144', + 'lightpink' => '255,182,193', + 'lightsalmon' => '255,160,122', + 'lightseagreen' => '32,178,170', + 'lightskyblue' => '135,206,250', + 'lightslategray' => '119,136,153', + 'lightslategrey' => '119,136,153', + 'lightsteelblue' => '176,196,222', + 'lightyellow' => '255,255,224', + 'lime' => '0,255,0', + 'limegreen' => '50,205,50', + 'linen' => '250,240,230', + 'maroon' => '128,0,0', + 'mediumaquamarine' => '102,205,170', + 'mediumblue' => '0,0,205', + 'mediumorchid' => '186,85,211', + 'mediumpurple' => '147,112,219', + 'mediumseagreen' => '60,179,113', + 'mediumslateblue' => '123,104,238', + 'mediumspringgreen' => '0,250,154', + 'mediumturquoise' => '72,209,204', + 'mediumvioletred' => '199,21,133', + 'midnightblue' => '25,25,112', + 'mintcream' => '245,255,250', + 'mistyrose' => '255,228,225', + 'moccasin' => '255,228,181', + 'navajowhite' => '255,222,173', + 'navy' => '0,0,128', + 'oldlace' => '253,245,230', + 'olive' => '128,128,0', + 'olivedrab' => '107,142,35', + 'orange' => '255,165,0', + 'orangered' => '255,69,0', + 'orchid' => '218,112,214', + 'palegoldenrod' => '238,232,170', + 'palegreen' => '152,251,152', + 'paleturquoise' => '175,238,238', + 'palevioletred' => '219,112,147', + 'papayawhip' => '255,239,213', + 'peachpuff' => '255,218,185', + 'peru' => '205,133,63', + 'pink' => '255,192,203', + 'plum' => '221,160,221', + 'powderblue' => '176,224,230', + 'purple' => '128,0,128', + 'red' => '255,0,0', + 'rosybrown' => '188,143,143', + 'royalblue' => '65,105,225', + 'saddlebrown' => '139,69,19', + 'salmon' => '250,128,114', + 'sandybrown' => '244,164,96', + 'seagreen' => '46,139,87', + 'seashell' => '255,245,238', + 'sienna' => '160,82,45', + 'silver' => '192,192,192', + 'skyblue' => '135,206,235', + 'slateblue' => '106,90,205', + 'slategray' => '112,128,144', + 'slategrey' => '112,128,144', + 'snow' => '255,250,250', + 'springgreen' => '0,255,127', + 'steelblue' => '70,130,180', + 'tan' => '210,180,140', + 'teal' => '0,128,128', + 'thistle' => '216,191,216', + 'tomato' => '255,99,71', + 'turquoise' => '64,224,208', + 'violet' => '238,130,238', + 'wheat' => '245,222,179', + 'white' => '255,255,255', + 'whitesmoke' => '245,245,245', + 'yellow' => '255,255,0', + 'yellowgreen' => '154,205,50', + 'rebeccapurple' => '102,51,153', + 'transparent' => '0,0,0,0', + ]; + + /** + * Convert named color in a [r,g,b[,a]] array + * + * @param string $colorName + * + * @return int[]|null + */ + public static function colorNameToRGBa($colorName) + { + if (\is_string($colorName) && isset(static::$cssColors[$colorName])) { + $rgba = explode(',', static::$cssColors[$colorName]); + + // only case with opacity is transparent, with opacity=0, so we can intval on opacity also + $rgba = array_map('intval', $rgba); + + return $rgba; + } + + return null; + } + + /** + * Reverse conversion : from RGBA to a color name if possible + * + * @param int $r + * @param int $g + * @param int $b + * @param int|float $a + * + * @return string|null + */ + public static function RGBaToColorName($r, $g, $b, $a = 1) + { + static $reverseColorTable = null; + + if (! is_numeric($r) || ! is_numeric($g) || ! is_numeric($b) || ! is_numeric($a)) { + return null; + } + + if ($a < 1) { + return null; + } + + if (\is_null($reverseColorTable)) { + $reverseColorTable = []; + + foreach (static::$cssColors as $name => $rgb_str) { + $rgb_str = explode(',', $rgb_str); + + if ( + \count($rgb_str) == 3 && + ! isset($reverseColorTable[\intval($rgb_str[0])][\intval($rgb_str[1])][\intval($rgb_str[2])]) + ) { + $reverseColorTable[\intval($rgb_str[0])][\intval($rgb_str[1])][\intval($rgb_str[2])] = $name; + } + } + } + + if (isset($reverseColorTable[\intval($r)][\intval($g)][\intval($b)])) { + return $reverseColorTable[\intval($r)][\intval($g)][\intval($b)]; + } + + return null; + } +} diff --git a/rules/scssphp/src/CompilationResult.php b/rules/scssphp/src/CompilationResult.php new file mode 100644 index 0000000..36adb0d --- /dev/null +++ b/rules/scssphp/src/CompilationResult.php @@ -0,0 +1,69 @@ +css = $css; + $this->sourceMap = $sourceMap; + $this->includedFiles = $includedFiles; + } + + /** + * @return string + */ + public function getCss() + { + return $this->css; + } + + /** + * @return string[] + */ + public function getIncludedFiles() + { + return $this->includedFiles; + } + + /** + * The sourceMap content, if it was generated + * + * @return null|string + */ + public function getSourceMap() + { + return $this->sourceMap; + } +} diff --git a/rules/scssphp/src/Compiler.php b/rules/scssphp/src/Compiler.php new file mode 100644 index 0000000..d654ee6 --- /dev/null +++ b/rules/scssphp/src/Compiler.php @@ -0,0 +1,10514 @@ + + * + * @final Extending the Compiler is deprecated + */ +class Compiler +{ + /** + * @deprecated + */ + const LINE_COMMENTS = 1; + /** + * @deprecated + */ + const DEBUG_INFO = 2; + + /** + * @deprecated + */ + const WITH_RULE = 1; + /** + * @deprecated + */ + const WITH_MEDIA = 2; + /** + * @deprecated + */ + const WITH_SUPPORTS = 4; + /** + * @deprecated + */ + const WITH_ALL = 7; + + const SOURCE_MAP_NONE = 0; + const SOURCE_MAP_INLINE = 1; + const SOURCE_MAP_FILE = 2; + + /** + * @var array + */ + protected static $operatorNames = [ + '+' => 'add', + '-' => 'sub', + '*' => 'mul', + '/' => 'div', + '%' => 'mod', + + '==' => 'eq', + '!=' => 'neq', + '<' => 'lt', + '>' => 'gt', + + '<=' => 'lte', + '>=' => 'gte', + ]; + + /** + * @var array + */ + protected static $namespaces = [ + 'special' => '%', + 'mixin' => '@', + 'function' => '^', + ]; + + public static $true = [Type::T_KEYWORD, 'true']; + public static $false = [Type::T_KEYWORD, 'false']; + /** @deprecated */ + public static $NaN = [Type::T_KEYWORD, 'NaN']; + /** @deprecated */ + public static $Infinity = [Type::T_KEYWORD, 'Infinity']; + public static $null = [Type::T_NULL]; + /** + * @internal + */ + public static $nullString = [Type::T_STRING, '', []]; + /** + * @internal + */ + public static $defaultValue = [Type::T_KEYWORD, '']; + /** + * @internal + */ + public static $selfSelector = [Type::T_SELF]; + public static $emptyList = [Type::T_LIST, '', []]; + public static $emptyMap = [Type::T_MAP, [], []]; + public static $emptyString = [Type::T_STRING, '"', []]; + /** + * @internal + */ + public static $with = [Type::T_KEYWORD, 'with']; + /** + * @internal + */ + public static $without = [Type::T_KEYWORD, 'without']; + private static $emptyArgumentList = [Type::T_LIST, '', [], []]; + + /** + * @var array + */ + protected $importPaths = []; + /** + * @var array + */ + protected $importCache = []; + + /** + * @var string[] + */ + protected $importedFiles = []; + + /** + * @var array + * @phpstan-var array + */ + protected $userFunctions = []; + /** + * @var array + */ + protected $registeredVars = []; + /** + * @var array + */ + protected $registeredFeatures = [ + 'extend-selector-pseudoclass' => false, + 'at-error' => true, + 'units-level-3' => true, + 'global-variable-shadowing' => false, + ]; + + /** + * @var string|null + */ + protected $encoding = null; + /** + * @var null + * @deprecated + */ + protected $lineNumberStyle = null; + + /** + * @var int|SourceMapGenerator + * @phpstan-var self::SOURCE_MAP_*|SourceMapGenerator + */ + protected $sourceMap = self::SOURCE_MAP_NONE; + + /** + * @var array + * @phpstan-var array{sourceRoot?: string, sourceMapFilename?: string|null, sourceMapURL?: string|null, sourceMapWriteTo?: string|null, outputSourceFiles?: bool, sourceMapRootpath?: string, sourceMapBasepath?: string} + */ + protected $sourceMapOptions = []; + + /** + * @var bool + */ + private $charset = true; + + /** + * @var Formatter + */ + protected $formatter; + + /** + * @var string + * @phpstan-var class-string + */ + private $configuredFormatter = Expanded::class; + + /** + * @var Environment + */ + protected $rootEnv; + /** + * @var OutputBlock|null + */ + protected $rootBlock; + + /** + * @var \ScssPhp\ScssPhp\Compiler\Environment + */ + protected $env; + /** + * @var OutputBlock|null + */ + protected $scope; + /** + * @var Environment|null + */ + protected $storeEnv; + /** + * @var bool|null + * + * @deprecated + */ + protected $charsetSeen; + /** + * @var array + */ + protected $sourceNames; + + /** + * @var Cache|null + */ + protected $cache; + + /** + * @var bool + */ + protected $cacheCheckImportResolutions = false; + + /** + * @var int + */ + protected $indentLevel; + /** + * @var array[] + */ + protected $extends; + /** + * @var array + */ + protected $extendsMap; + + /** + * @var array + */ + protected $parsedFiles = []; + + /** + * @var Parser|null + */ + protected $parser; + /** + * @var int|null + */ + protected $sourceIndex; + /** + * @var int|null + */ + protected $sourceLine; + /** + * @var int|null + */ + protected $sourceColumn; + /** + * @var bool|null + */ + protected $shouldEvaluate; + /** + * @var null + * @deprecated + */ + protected $ignoreErrors; + /** + * @var bool + */ + protected $ignoreCallStackMessage = false; + + /** + * @var array[] + */ + protected $callStack = []; + + /** + * @var array + * @phpstan-var list + */ + private $resolvedImports = []; + + /** + * The directory of the currently processed file + * + * @var string|null + */ + private $currentDirectory; + + /** + * The directory of the input file + * + * @var string + */ + private $rootDirectory; + + /** + * @var bool + */ + private $legacyCwdImportPath = true; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var array + */ + private $warnedChildFunctions = []; + + /** + * Constructor + * + * @param array|null $cacheOptions + * @phpstan-param array{cacheDir?: string, prefix?: string, forceRefresh?: string, checkImportResolutions?: bool}|null $cacheOptions + */ + public function __construct($cacheOptions = null) + { + $this->sourceNames = []; + + if ($cacheOptions) { + $this->cache = new Cache($cacheOptions); + if (!empty($cacheOptions['checkImportResolutions'])) { + $this->cacheCheckImportResolutions = true; + } + } + + $this->logger = new StreamLogger(fopen('php://stderr', 'w'), true); + } + + /** + * Get compiler options + * + * @return array + * + * @internal + */ + public function getCompileOptions() + { + $options = [ + 'importPaths' => $this->importPaths, + 'registeredVars' => $this->registeredVars, + 'registeredFeatures' => $this->registeredFeatures, + 'encoding' => $this->encoding, + 'sourceMap' => serialize($this->sourceMap), + 'sourceMapOptions' => $this->sourceMapOptions, + 'formatter' => $this->configuredFormatter, + 'legacyImportPath' => $this->legacyCwdImportPath, + ]; + + return $options; + } + + /** + * Sets an alternative logger. + * + * Changing the logger in the middle of the compilation is not + * supported and will result in an undefined behavior. + * + * @param LoggerInterface $logger + * + * @return void + */ + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * Set an alternative error output stream, for testing purpose only + * + * @param resource $handle + * + * @return void + * + * @deprecated Use {@see setLogger} instead + */ + public function setErrorOuput($handle) + { + @trigger_error('The method "setErrorOuput" is deprecated. Use "setLogger" instead.', E_USER_DEPRECATED); + + $this->logger = new StreamLogger($handle); + } + + /** + * Compile scss + * + * @param string $code + * @param string|null $path + * + * @return string + * + * @throws SassException when the source fails to compile + * + * @deprecated Use {@see compileString} instead. + */ + public function compile($code, $path = null) + { + @trigger_error(sprintf('The "%s" method is deprecated. Use "compileString" instead.', __METHOD__), E_USER_DEPRECATED); + + $result = $this->compileString($code, $path); + + $sourceMap = $result->getSourceMap(); + + if ($sourceMap !== null) { + if ($this->sourceMap instanceof SourceMapGenerator) { + $this->sourceMap->saveMap($sourceMap); + } elseif ($this->sourceMap === self::SOURCE_MAP_FILE) { + $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); + $sourceMapGenerator->saveMap($sourceMap); + } + } + + return $result->getCss(); + } + + /** + * Compiles the provided scss file into CSS. + * + * @param string $path + * + * @return CompilationResult + * + * @throws SassException when the source fails to compile + */ + public function compileFile($path) + { + $source = file_get_contents($path); + + if ($source === false) { + throw new \RuntimeException('Could not read the file content'); + } + + return $this->compileString($source, $path); + } + + /** + * Compiles the provided scss source code into CSS. + * + * If provided, the path is considered to be the path from which the source code comes + * from, which will be used to resolve relative imports. + * + * @param string $source + * @param string|null $path The path for the source, used to resolve relative imports + * + * @return CompilationResult + * + * @throws SassException when the source fails to compile + */ + public function compileString($source, $path = null) + { + if ($this->cache) { + $cacheKey = ($path ? $path : '(stdin)') . ':' . md5($source); + $compileOptions = $this->getCompileOptions(); + $cachedResult = $this->cache->getCache('compile', $cacheKey, $compileOptions); + + if ($cachedResult instanceof CachedResult && $this->isFreshCachedResult($cachedResult)) { + return $cachedResult->getResult(); + } + } + + $this->indentLevel = -1; + $this->extends = []; + $this->extendsMap = []; + $this->sourceIndex = null; + $this->sourceLine = null; + $this->sourceColumn = null; + $this->env = null; + $this->scope = null; + $this->storeEnv = null; + $this->shouldEvaluate = null; + $this->ignoreCallStackMessage = false; + $this->parsedFiles = []; + $this->importedFiles = []; + $this->resolvedImports = []; + + if (!\is_null($path) && is_file($path)) { + $path = realpath($path) ?: $path; + $this->currentDirectory = dirname($path); + $this->rootDirectory = $this->currentDirectory; + } else { + $this->currentDirectory = null; + $this->rootDirectory = getcwd(); + } + + try { + $this->parser = $this->parserFactory($path); + $tree = $this->parser->parse($source); + $this->parser = null; + + $this->formatter = new $this->configuredFormatter(); + $this->rootBlock = null; + $this->rootEnv = $this->pushEnv($tree); + + $warnCallback = function ($message, $deprecation) { + $this->logger->warn($message, $deprecation); + }; + $previousWarnCallback = Warn::setCallback($warnCallback); + + try { + $this->injectVariables($this->registeredVars); + $this->compileRoot($tree); + $this->popEnv(); + } finally { + Warn::setCallback($previousWarnCallback); + } + + $sourceMapGenerator = null; + + if ($this->sourceMap) { + if (\is_object($this->sourceMap) && $this->sourceMap instanceof SourceMapGenerator) { + $sourceMapGenerator = $this->sourceMap; + $this->sourceMap = self::SOURCE_MAP_FILE; + } elseif ($this->sourceMap !== self::SOURCE_MAP_NONE) { + $sourceMapGenerator = new SourceMapGenerator($this->sourceMapOptions); + } + } + assert($this->scope !== null); + + $out = $this->formatter->format($this->scope, $sourceMapGenerator); + + $prefix = ''; + + if ($this->charset && strlen($out) !== Util::mbStrlen($out)) { + $prefix = '@charset "UTF-8";' . "\n"; + $out = $prefix . $out; + } + + $sourceMap = null; + + if (! empty($out) && $this->sourceMap !== self::SOURCE_MAP_NONE && $this->sourceMap) { + assert($sourceMapGenerator !== null); + $sourceMap = $sourceMapGenerator->generateJson($prefix); + $sourceMapUrl = null; + + switch ($this->sourceMap) { + case self::SOURCE_MAP_INLINE: + $sourceMapUrl = sprintf('data:application/json,%s', Util::encodeURIComponent($sourceMap)); + break; + + case self::SOURCE_MAP_FILE: + if (isset($this->sourceMapOptions['sourceMapURL'])) { + $sourceMapUrl = $this->sourceMapOptions['sourceMapURL']; + } + break; + } + + if ($sourceMapUrl !== null) { + $out .= sprintf('/*# sourceMappingURL=%s */', $sourceMapUrl); + } + } + } catch (SassScriptException $e) { + throw new CompilerException($this->addLocationToMessage($e->getMessage()), 0, $e); + } + + $includedFiles = []; + + foreach ($this->resolvedImports as $resolvedImport) { + $includedFiles[$resolvedImport['filePath']] = $resolvedImport['filePath']; + } + + $result = new CompilationResult($out, $sourceMap, array_values($includedFiles)); + + if ($this->cache && isset($cacheKey) && isset($compileOptions)) { + $this->cache->setCache('compile', $cacheKey, new CachedResult($result, $this->parsedFiles, $this->resolvedImports), $compileOptions); + } + + // Reset state to free memory + // TODO in 2.0, reset parsedFiles as well when the getter is removed. + $this->resolvedImports = []; + $this->importedFiles = []; + + return $result; + } + + /** + * @param CachedResult $result + * + * @return bool + */ + private function isFreshCachedResult(CachedResult $result) + { + // check if any dependency file changed since the result was compiled + foreach ($result->getParsedFiles() as $file => $mtime) { + if (! is_file($file) || filemtime($file) !== $mtime) { + return false; + } + } + + if ($this->cacheCheckImportResolutions) { + $resolvedImports = []; + + foreach ($result->getResolvedImports() as $import) { + $currentDir = $import['currentDir']; + $path = $import['path']; + // store the check across all the results in memory to avoid multiple findImport() on the same path + // with same context. + // this is happening in a same hit with multiple compilations (especially with big frameworks) + if (empty($resolvedImports[$currentDir][$path])) { + $resolvedImports[$currentDir][$path] = $this->findImport($path, $currentDir); + } + + if ($resolvedImports[$currentDir][$path] !== $import['filePath']) { + return false; + } + } + } + + return true; + } + + /** + * Instantiate parser + * + * @param string|null $path + * + * @return \ScssPhp\ScssPhp\Parser + */ + protected function parserFactory($path) + { + // https://sass-lang.com/documentation/at-rules/import + // CSS files imported by Sass don’t allow any special Sass features. + // In order to make sure authors don’t accidentally write Sass in their CSS, + // all Sass features that aren’t also valid CSS will produce errors. + // Otherwise, the CSS will be rendered as-is. It can even be extended! + $cssOnly = false; + + if ($path !== null && substr($path, -4) === '.css') { + $cssOnly = true; + } + + $parser = new Parser($path, \count($this->sourceNames), $this->encoding, $this->cache, $cssOnly, $this->logger); + + $this->sourceNames[] = $path; + $this->addParsedFile($path); + + return $parser; + } + + /** + * Is self extend? + * + * @param array $target + * @param array $origin + * + * @return bool + */ + protected function isSelfExtend($target, $origin) + { + foreach ($origin as $sel) { + if (\in_array($target, $sel)) { + return true; + } + } + + return false; + } + + /** + * Push extends + * + * @param string[] $target + * @param array $origin + * @param array|null $block + * + * @return void + */ + protected function pushExtends($target, $origin, $block) + { + $i = \count($this->extends); + $this->extends[] = [$target, $origin, $block]; + + foreach ($target as $part) { + if (isset($this->extendsMap[$part])) { + $this->extendsMap[$part][] = $i; + } else { + $this->extendsMap[$part] = [$i]; + } + } + } + + /** + * Make output block + * + * @param string|null $type + * @param string[]|null $selectors + * + * @return \ScssPhp\ScssPhp\Formatter\OutputBlock + */ + protected function makeOutputBlock($type, $selectors = null) + { + $out = new OutputBlock(); + $out->type = $type; + $out->lines = []; + $out->children = []; + $out->parent = $this->scope; + $out->selectors = $selectors; + $out->depth = $this->env->depth; + + if ($this->env->block instanceof Block) { + $out->sourceName = $this->env->block->sourceName; + $out->sourceLine = $this->env->block->sourceLine; + $out->sourceColumn = $this->env->block->sourceColumn; + } else { + $out->sourceName = isset($this->sourceNames[$this->sourceIndex]) ? $this->sourceNames[$this->sourceIndex] : '(stdin)'; + $out->sourceLine = $this->sourceLine; + $out->sourceColumn = $this->sourceColumn; + } + + return $out; + } + + /** + * Compile root + * + * @param \ScssPhp\ScssPhp\Block $rootBlock + * + * @return void + */ + protected function compileRoot(Block $rootBlock) + { + $this->rootBlock = $this->scope = $this->makeOutputBlock(Type::T_ROOT); + + $this->compileChildrenNoReturn($rootBlock->children, $this->scope); + assert($this->scope !== null); + $this->flattenSelectors($this->scope); + $this->missingSelectors(); + } + + /** + * Report missing selectors + * + * @return void + */ + protected function missingSelectors() + { + foreach ($this->extends as $extend) { + if (isset($extend[3])) { + continue; + } + + list($target, $origin, $block) = $extend; + + // ignore if !optional + if ($block[2]) { + continue; + } + + $target = implode(' ', $target); + $origin = $this->collapseSelectors($origin); + + $this->sourceLine = $block[Parser::SOURCE_LINE]; + throw $this->error("\"$origin\" failed to @extend \"$target\". The selector \"$target\" was not found."); + } + } + + /** + * Flatten selectors + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * @param string $parentKey + * + * @return void + */ + protected function flattenSelectors(OutputBlock $block, $parentKey = null) + { + if ($block->selectors) { + $selectors = []; + + foreach ($block->selectors as $s) { + $selectors[] = $s; + + if (! \is_array($s)) { + continue; + } + + // check extends + if (! empty($this->extendsMap)) { + $this->matchExtends($s, $selectors); + + // remove duplicates + array_walk($selectors, function (&$value) { + $value = serialize($value); + }); + + $selectors = array_unique($selectors); + + array_walk($selectors, function (&$value) { + $value = unserialize($value); + }); + } + } + + $block->selectors = []; + $placeholderSelector = false; + + foreach ($selectors as $selector) { + if ($this->hasSelectorPlaceholder($selector)) { + $placeholderSelector = true; + continue; + } + + $block->selectors[] = $this->compileSelector($selector); + } + + if ($placeholderSelector && 0 === \count($block->selectors) && null !== $parentKey) { + assert($block->parent !== null); + unset($block->parent->children[$parentKey]); + + return; + } + } + + foreach ($block->children as $key => $child) { + $this->flattenSelectors($child, $key); + } + } + + /** + * Glue parts of :not( or :nth-child( ... that are in general split in selectors parts + * + * @param array $parts + * + * @return array + */ + protected function glueFunctionSelectors($parts) + { + $new = []; + + foreach ($parts as $part) { + if (\is_array($part)) { + $part = $this->glueFunctionSelectors($part); + $new[] = $part; + } else { + // a selector part finishing with a ) is the last part of a :not( or :nth-child( + // and need to be joined to this + if ( + \count($new) && \is_string($new[\count($new) - 1]) && + \strlen($part) && substr($part, -1) === ')' && strpos($part, '(') === false + ) { + while (\count($new) > 1 && substr($new[\count($new) - 1], -1) !== '(') { + $part = array_pop($new) . $part; + } + $new[\count($new) - 1] .= $part; + } else { + $new[] = $part; + } + } + } + + return $new; + } + + /** + * Match extends + * + * @param array $selector + * @param array $out + * @param int $from + * @param bool $initial + * + * @return void + */ + protected function matchExtends($selector, &$out, $from = 0, $initial = true) + { + static $partsPile = []; + $selector = $this->glueFunctionSelectors($selector); + + if (\count($selector) == 1 && \in_array(reset($selector), $partsPile)) { + return; + } + + $outRecurs = []; + + foreach ($selector as $i => $part) { + if ($i < $from) { + continue; + } + + // check that we are not building an infinite loop of extensions + // if the new part is just including a previous part don't try to extend anymore + if (\count($part) > 1) { + foreach ($partsPile as $previousPart) { + if (! \count(array_diff($previousPart, $part))) { + continue 2; + } + } + } + + $partsPile[] = $part; + + if ($this->matchExtendsSingle($part, $origin, $initial)) { + $after = \array_slice($selector, $i + 1); + $before = \array_slice($selector, 0, $i); + list($before, $nonBreakableBefore) = $this->extractRelationshipFromFragment($before); + + foreach ($origin as $new) { + $k = 0; + + // remove shared parts + if (\count($new) > 1) { + while ($k < $i && isset($new[$k]) && $selector[$k] === $new[$k]) { + $k++; + } + } + + if (\count($nonBreakableBefore) && $k === \count($new)) { + $k--; + } + + $replacement = []; + $tempReplacement = $k > 0 ? \array_slice($new, $k) : $new; + + for ($l = \count($tempReplacement) - 1; $l >= 0; $l--) { + $slice = []; + + foreach ($tempReplacement[$l] as $chunk) { + if (! \in_array($chunk, $slice)) { + $slice[] = $chunk; + } + } + + array_unshift($replacement, $slice); + + if (! $this->isImmediateRelationshipCombinator(end($slice))) { + break; + } + } + + $afterBefore = $l != 0 ? \array_slice($tempReplacement, 0, $l) : []; + + // Merge shared direct relationships. + $mergedBefore = $this->mergeDirectRelationships($afterBefore, $nonBreakableBefore); + + $result = array_merge( + $before, + $mergedBefore, + $replacement, + $after + ); + + if ($result === $selector) { + continue; + } + + $this->pushOrMergeExtentedSelector($out, $result); + + // recursively check for more matches + $startRecurseFrom = \count($before) + min(\count($nonBreakableBefore), \count($mergedBefore)); + + if (\count($origin) > 1) { + $this->matchExtends($result, $out, $startRecurseFrom, false); + } else { + $this->matchExtends($result, $outRecurs, $startRecurseFrom, false); + } + + // selector sequence merging + if (! empty($before) && \count($new) > 1) { + $preSharedParts = $k > 0 ? \array_slice($before, 0, $k) : []; + $postSharedParts = $k > 0 ? \array_slice($before, $k) : $before; + + list($betweenSharedParts, $nonBreakabl2) = $this->extractRelationshipFromFragment($afterBefore); + + $result2 = array_merge( + $preSharedParts, + $betweenSharedParts, + $postSharedParts, + $nonBreakabl2, + $nonBreakableBefore, + $replacement, + $after + ); + + $this->pushOrMergeExtentedSelector($out, $result2); + } + } + } + array_pop($partsPile); + } + + while (\count($outRecurs)) { + $result = array_shift($outRecurs); + $this->pushOrMergeExtentedSelector($out, $result); + } + } + + /** + * Test a part for being a pseudo selector + * + * @param string $part + * @param array $matches + * + * @return bool + */ + protected function isPseudoSelector($part, &$matches) + { + if ( + strpos($part, ':') === 0 && + preg_match(",^::?([\w-]+)\((.+)\)$,", $part, $matches) + ) { + return true; + } + + return false; + } + + /** + * Push extended selector except if + * - this is a pseudo selector + * - same as previous + * - in a white list + * in this case we merge the pseudo selector content + * + * @param array $out + * @param array $extended + * + * @return void + */ + protected function pushOrMergeExtentedSelector(&$out, $extended) + { + if (\count($out) && \count($extended) === 1 && \count(reset($extended)) === 1) { + $single = reset($extended); + $part = reset($single); + + if ( + $this->isPseudoSelector($part, $matchesExtended) && + \in_array($matchesExtended[1], [ 'slotted' ]) + ) { + $prev = end($out); + $prev = $this->glueFunctionSelectors($prev); + + if (\count($prev) === 1 && \count(reset($prev)) === 1) { + $single = reset($prev); + $part = reset($single); + + if ( + $this->isPseudoSelector($part, $matchesPrev) && + $matchesPrev[1] === $matchesExtended[1] + ) { + $extended = explode($matchesExtended[1] . '(', $matchesExtended[0], 2); + $extended[1] = $matchesPrev[2] . ', ' . $extended[1]; + $extended = implode($matchesExtended[1] . '(', $extended); + $extended = [ [ $extended ]]; + array_pop($out); + } + } + } + } + $out[] = $extended; + } + + /** + * Match extends single + * + * @param array $rawSingle + * @param array $outOrigin + * @param bool $initial + * + * @return bool + */ + protected function matchExtendsSingle($rawSingle, &$outOrigin, $initial = true) + { + $counts = []; + $single = []; + + // simple usual cases, no need to do the whole trick + if (\in_array($rawSingle, [['>'],['+'],['~']])) { + return false; + } + + foreach ($rawSingle as $part) { + // matches Number + if (! \is_string($part)) { + return false; + } + + if (! preg_match('/^[\[.:#%]/', $part) && \count($single)) { + $single[\count($single) - 1] .= $part; + } else { + $single[] = $part; + } + } + + $extendingDecoratedTag = false; + + if (\count($single) > 1) { + $matches = null; + $extendingDecoratedTag = preg_match('/^[a-z0-9]+$/i', $single[0], $matches) ? $matches[0] : false; + } + + $outOrigin = []; + $found = false; + + foreach ($single as $k => $part) { + if (isset($this->extendsMap[$part])) { + foreach ($this->extendsMap[$part] as $idx) { + $counts[$idx] = isset($counts[$idx]) ? $counts[$idx] + 1 : 1; + } + } + + if ( + $initial && + $this->isPseudoSelector($part, $matches) && + ! \in_array($matches[1], [ 'not' ]) + ) { + $buffer = $matches[2]; + $parser = $this->parserFactory(__METHOD__); + + if ($parser->parseSelector($buffer, $subSelectors, false)) { + foreach ($subSelectors as $ksub => $subSelector) { + $subExtended = []; + $this->matchExtends($subSelector, $subExtended, 0, false); + + if ($subExtended) { + $subSelectorsExtended = $subSelectors; + $subSelectorsExtended[$ksub] = $subExtended; + + foreach ($subSelectorsExtended as $ksse => $sse) { + $subSelectorsExtended[$ksse] = $this->collapseSelectors($sse); + } + + $subSelectorsExtended = implode(', ', $subSelectorsExtended); + $singleExtended = $single; + $singleExtended[$k] = str_replace('(' . $buffer . ')', "($subSelectorsExtended)", $part); + $outOrigin[] = [ $singleExtended ]; + $found = true; + } + } + } + } + } + + foreach ($counts as $idx => $count) { + list($target, $origin, /* $block */) = $this->extends[$idx]; + + $origin = $this->glueFunctionSelectors($origin); + + // check count + if ($count !== \count($target)) { + continue; + } + + $this->extends[$idx][3] = true; + + $rem = array_diff($single, $target); + + foreach ($origin as $j => $new) { + // prevent infinite loop when target extends itself + if ($this->isSelfExtend($single, $origin) && ! $initial) { + return false; + } + + $replacement = end($new); + + // Extending a decorated tag with another tag is not possible. + if ( + $extendingDecoratedTag && $replacement[0] != $extendingDecoratedTag && + preg_match('/^[a-z0-9]+$/i', $replacement[0]) + ) { + unset($origin[$j]); + continue; + } + + $combined = $this->combineSelectorSingle($replacement, $rem); + + if (\count(array_diff($combined, $origin[$j][\count($origin[$j]) - 1]))) { + $origin[$j][\count($origin[$j]) - 1] = $combined; + } + } + + $outOrigin = array_merge($outOrigin, $origin); + + $found = true; + } + + return $found; + } + + /** + * Extract a relationship from the fragment. + * + * When extracting the last portion of a selector we will be left with a + * fragment which may end with a direction relationship combinator. This + * method will extract the relationship fragment and return it along side + * the rest. + * + * @param array $fragment The selector fragment maybe ending with a direction relationship combinator. + * + * @return array The selector without the relationship fragment if any, the relationship fragment. + */ + protected function extractRelationshipFromFragment(array $fragment) + { + $parents = []; + $children = []; + + $j = $i = \count($fragment); + + for (;;) { + $children = $j != $i ? \array_slice($fragment, $j, $i - $j) : []; + $parents = \array_slice($fragment, 0, $j); + $slice = end($parents); + + if (empty($slice) || ! $this->isImmediateRelationshipCombinator($slice[0])) { + break; + } + + $j -= 2; + } + + return [$parents, $children]; + } + + /** + * Combine selector single + * + * @param array $base + * @param array $other + * + * @return array + */ + protected function combineSelectorSingle($base, $other) + { + $tag = []; + $out = []; + $wasTag = false; + $pseudo = []; + + while (\count($other) && strpos(end($other), ':') === 0) { + array_unshift($pseudo, array_pop($other)); + } + + foreach ([array_reverse($base), array_reverse($other)] as $single) { + $rang = count($single); + + foreach ($single as $part) { + if (preg_match('/^[\[:]/', $part)) { + $out[] = $part; + $wasTag = false; + } elseif (preg_match('/^[\.#]/', $part)) { + array_unshift($out, $part); + $wasTag = false; + } elseif (preg_match('/^[^_-]/', $part) && $rang === 1) { + $tag[] = $part; + $wasTag = true; + } elseif ($wasTag) { + $tag[\count($tag) - 1] .= $part; + } else { + array_unshift($out, $part); + } + $rang--; + } + } + + if (\count($tag)) { + array_unshift($out, $tag[0]); + } + + while (\count($pseudo)) { + $out[] = array_shift($pseudo); + } + + return $out; + } + + /** + * Compile media + * + * @param \ScssPhp\ScssPhp\Block $media + * + * @return void + */ + protected function compileMedia(Block $media) + { + assert($media instanceof MediaBlock); + $this->pushEnv($media); + + $mediaQueries = $this->compileMediaQuery($this->multiplyMedia($this->env)); + + if (! empty($mediaQueries)) { + assert($this->scope !== null); + $previousScope = $this->scope; + $parentScope = $this->mediaParent($this->scope); + + foreach ($mediaQueries as $mediaQuery) { + $this->scope = $this->makeOutputBlock(Type::T_MEDIA, [$mediaQuery]); + + $parentScope->children[] = $this->scope; + $parentScope = $this->scope; + } + + // top level properties in a media cause it to be wrapped + $needsWrap = false; + + foreach ($media->children as $child) { + $type = $child[0]; + + if ( + $type !== Type::T_BLOCK && + $type !== Type::T_MEDIA && + $type !== Type::T_DIRECTIVE && + $type !== Type::T_IMPORT + ) { + $needsWrap = true; + break; + } + } + + if ($needsWrap) { + $wrapped = new Block(); + $wrapped->sourceName = $media->sourceName; + $wrapped->sourceIndex = $media->sourceIndex; + $wrapped->sourceLine = $media->sourceLine; + $wrapped->sourceColumn = $media->sourceColumn; + $wrapped->selectors = []; + $wrapped->comments = []; + $wrapped->parent = $media; + $wrapped->children = $media->children; + + $media->children = [[Type::T_BLOCK, $wrapped]]; + } + + $this->compileChildrenNoReturn($media->children, $this->scope); + + $this->scope = $previousScope; + } + + $this->popEnv(); + } + + /** + * Media parent + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * + * @return \ScssPhp\ScssPhp\Formatter\OutputBlock + */ + protected function mediaParent(OutputBlock $scope) + { + while (! empty($scope->parent)) { + if (! empty($scope->type) && $scope->type !== Type::T_MEDIA) { + break; + } + + $scope = $scope->parent; + } + + return $scope; + } + + /** + * Compile directive + * + * @param DirectiveBlock|array $directive + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return void + */ + protected function compileDirective($directive, OutputBlock $out) + { + if (\is_array($directive)) { + $directiveName = $this->compileDirectiveName($directive[0]); + $s = '@' . $directiveName; + + if (! empty($directive[1])) { + $s .= ' ' . $this->compileValue($directive[1]); + } + // sass-spec compliance on newline after directives, a bit tricky :/ + $appendNewLine = (! empty($directive[2]) || strpos($s, "\n")) ? "\n" : ""; + if (\is_array($directive[0]) && empty($directive[1])) { + $appendNewLine = "\n"; + } + + if (empty($directive[3])) { + $this->appendRootDirective($s . ';' . $appendNewLine, $out, [Type::T_COMMENT, Type::T_DIRECTIVE]); + } else { + $this->appendOutputLine($out, Type::T_DIRECTIVE, $s . ';'); + } + } else { + $directive->name = $this->compileDirectiveName($directive->name); + $s = '@' . $directive->name; + + if (! empty($directive->value)) { + $s .= ' ' . $this->compileValue($directive->value); + } + + if ($directive->name === 'keyframes' || substr($directive->name, -10) === '-keyframes') { + $this->compileKeyframeBlock($directive, [$s]); + } else { + $this->compileNestedBlock($directive, [$s]); + } + } + } + + /** + * directive names can include some interpolation + * + * @param string|array $directiveName + * @return string + * @throws CompilerException + */ + protected function compileDirectiveName($directiveName) + { + if (is_string($directiveName)) { + return $directiveName; + } + + return $this->compileValue($directiveName); + } + + /** + * Compile at-root + * + * @param \ScssPhp\ScssPhp\Block $block + * + * @return void + */ + protected function compileAtRoot(Block $block) + { + assert($block instanceof AtRootBlock); + $env = $this->pushEnv($block); + $envs = $this->compactEnv($env); + list($with, $without) = $this->compileWith(isset($block->with) ? $block->with : null); + + // wrap inline selector + if ($block->selector) { + $wrapped = new Block(); + $wrapped->sourceName = $block->sourceName; + $wrapped->sourceIndex = $block->sourceIndex; + $wrapped->sourceLine = $block->sourceLine; + $wrapped->sourceColumn = $block->sourceColumn; + $wrapped->selectors = $block->selector; + $wrapped->comments = []; + $wrapped->parent = $block; + $wrapped->children = $block->children; + $wrapped->selfParent = $block->selfParent; + + $block->children = [[Type::T_BLOCK, $wrapped]]; + $block->selector = null; + } + + $selfParent = $block->selfParent; + assert($selfParent !== null, 'at-root blocks must have a selfParent set.'); + + if ( + ! $selfParent->selectors && + isset($block->parent) && + isset($block->parent->selectors) && $block->parent->selectors + ) { + $selfParent = $block->parent; + } + + $this->env = $this->filterWithWithout($envs, $with, $without); + + assert($this->scope !== null); + $saveScope = $this->scope; + $this->scope = $this->filterScopeWithWithout($saveScope, $with, $without); + + // propagate selfParent to the children where they still can be useful + $this->compileChildrenNoReturn($block->children, $this->scope, $selfParent); + + assert($this->scope !== null); + $this->completeScope($this->scope, $saveScope); + $this->scope = $saveScope; + $this->env = $this->extractEnv($envs); + + $this->popEnv(); + } + + /** + * Filter at-root scope depending on with/without option + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * @param array $with + * @param array $without + * + * @return OutputBlock + */ + protected function filterScopeWithWithout($scope, $with, $without) + { + $filteredScopes = []; + $childStash = []; + + if ($scope->type === Type::T_ROOT) { + return $scope; + } + assert($this->rootBlock !== null); + + // start from the root + while ($scope->parent && $scope->parent->type !== Type::T_ROOT) { + array_unshift($childStash, $scope); + \assert($scope->parent !== null); + $scope = $scope->parent; + } + + for (;;) { + if (! $scope) { + break; + } + + if ($this->isWith($scope, $with, $without)) { + $s = clone $scope; + $s->children = []; + $s->lines = []; + $s->parent = null; + + if ($s->type !== Type::T_MEDIA && $s->type !== Type::T_DIRECTIVE) { + $s->selectors = []; + } + + $filteredScopes[] = $s; + } + + if (\count($childStash)) { + $scope = array_shift($childStash); + } elseif ($scope->children) { + $scope = end($scope->children); + } else { + $scope = null; + } + } + + if (! \count($filteredScopes)) { + return $this->rootBlock; + } + + $newScope = array_shift($filteredScopes); + $newScope->parent = $this->rootBlock; + + $this->rootBlock->children[] = $newScope; + + $p = &$newScope; + + while (\count($filteredScopes)) { + $s = array_shift($filteredScopes); + $s->parent = $p; + $p->children[] = $s; + $newScope = &$p->children[0]; + $p = &$p->children[0]; + } + + return $newScope; + } + + /** + * found missing selector from a at-root compilation in the previous scope + * (if at-root is just enclosing a property, the selector is in the parent tree) + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $previousScope + * + * @return OutputBlock + */ + protected function completeScope($scope, $previousScope) + { + if (! $scope->type && ! $scope->selectors && \count($scope->lines)) { + $scope->selectors = $this->findScopeSelectors($previousScope, $scope->depth); + } + + if ($scope->children) { + foreach ($scope->children as $k => $c) { + $scope->children[$k] = $this->completeScope($c, $previousScope); + } + } + + return $scope; + } + + /** + * Find a selector by the depth node in the scope + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $scope + * @param int $depth + * + * @return array + */ + protected function findScopeSelectors($scope, $depth) + { + if ($scope->depth === $depth && $scope->selectors) { + return $scope->selectors; + } + + if ($scope->children) { + foreach (array_reverse($scope->children) as $c) { + if ($s = $this->findScopeSelectors($c, $depth)) { + return $s; + } + } + } + + return []; + } + + /** + * Compile @at-root's with: inclusion / without: exclusion into 2 lists uses to filter scope/env later + * + * @param array|null $withCondition + * + * @return array + * + * @phpstan-return array{array, array} + */ + protected function compileWith($withCondition) + { + // just compile what we have in 2 lists + $with = []; + $without = ['rule' => true]; + + if ($withCondition) { + if ($withCondition[0] === Type::T_INTERPOLATE) { + $w = $this->compileValue($withCondition); + + $buffer = "($w)"; + $parser = $this->parserFactory(__METHOD__); + + if ($parser->parseValue($buffer, $reParsedWith)) { + \assert(\is_array($reParsedWith)); + $withCondition = $reParsedWith; + } + } + + $withConfig = $this->mapGet($withCondition, static::$with); + if ($withConfig !== null) { + $without = []; // cancel the default + $list = $this->coerceList($withConfig); + + foreach ($list[2] as $item) { + $keyword = $this->compileStringContent($this->coerceString($item)); + + $with[$keyword] = true; + } + } + + $withoutConfig = $this->mapGet($withCondition, static::$without); + if ($withoutConfig !== null) { + $without = []; // cancel the default + $list = $this->coerceList($withoutConfig); + + foreach ($list[2] as $item) { + $keyword = $this->compileStringContent($this->coerceString($item)); + + $without[$keyword] = true; + } + } + } + + return [$with, $without]; + } + + /** + * Filter env stack + * + * @param Environment[] $envs + * @param array $with + * @param array $without + * + * @return Environment + * + * @phpstan-param non-empty-array $envs + */ + protected function filterWithWithout($envs, $with, $without) + { + $filtered = []; + + foreach ($envs as $e) { + if ($e->block && ! $this->isWith($e->block, $with, $without)) { + $ec = clone $e; + $ec->block = null; + $ec->selectors = []; + + $filtered[] = $ec; + } else { + $filtered[] = $e; + } + } + + return $this->extractEnv($filtered); + } + + /** + * Filter WITH rules + * + * @param \ScssPhp\ScssPhp\Block|\ScssPhp\ScssPhp\Formatter\OutputBlock $block + * @param array $with + * @param array $without + * + * @return bool + */ + protected function isWith($block, $with, $without) + { + if (isset($block->type)) { + if ($block->type === Type::T_MEDIA) { + return $this->testWithWithout('media', $with, $without); + } + + if ($block->type === Type::T_DIRECTIVE) { + assert($block instanceof DirectiveBlock || $block instanceof OutputBlock); + if (isset($block->name)) { + return $this->testWithWithout($this->compileDirectiveName($block->name), $with, $without); + } elseif (isset($block->selectors) && preg_match(',@(\w+),ims', json_encode($block->selectors), $m)) { + return $this->testWithWithout($m[1], $with, $without); + } else { + return $this->testWithWithout('???', $with, $without); + } + } + } elseif (isset($block->selectors)) { + // a selector starting with number is a keyframe rule + if (\count($block->selectors)) { + $s = reset($block->selectors); + + while (\is_array($s)) { + $s = reset($s); + } + + if (\is_object($s) && $s instanceof Number) { + return $this->testWithWithout('keyframes', $with, $without); + } + } + + return $this->testWithWithout('rule', $with, $without); + } + + return true; + } + + /** + * Test a single type of block against with/without lists + * + * @param string $what + * @param array $with + * @param array $without + * + * @return bool + * true if the block should be kept, false to reject + */ + protected function testWithWithout($what, $with, $without) + { + // if without, reject only if in the list (or 'all' is in the list) + if (\count($without)) { + return (isset($without[$what]) || isset($without['all'])) ? false : true; + } + + // otherwise reject all what is not in the with list + return (isset($with[$what]) || isset($with['all'])) ? true : false; + } + + + /** + * Compile keyframe block + * + * @param \ScssPhp\ScssPhp\Block $block + * @param string[] $selectors + * + * @return void + */ + protected function compileKeyframeBlock(Block $block, $selectors) + { + $env = $this->pushEnv($block); + + $envs = $this->compactEnv($env); + + $this->env = $this->extractEnv(array_filter($envs, function (Environment $e) { + return ! isset($e->block->selectors); + })); + + $this->scope = $this->makeOutputBlock($block->type, $selectors); + $this->scope->depth = 1; + assert($this->scope->parent !== null); + $this->scope->parent->children[] = $this->scope; + + $this->compileChildrenNoReturn($block->children, $this->scope); + + assert($this->scope !== null); + $this->scope = $this->scope->parent; + $this->env = $this->extractEnv($envs); + + $this->popEnv(); + } + + /** + * Compile nested properties lines + * + * @param \ScssPhp\ScssPhp\Block $block + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return void + */ + protected function compileNestedPropertiesBlock(Block $block, OutputBlock $out) + { + assert($block instanceof NestedPropertyBlock); + $prefix = $this->compileValue($block->prefix) . '-'; + + $nested = $this->makeOutputBlock($block->type); + $nested->parent = $out; + + if ($block->hasValue) { + $nested->depth = $out->depth + 1; + } + + $out->children[] = $nested; + + foreach ($block->children as $child) { + switch ($child[0]) { + case Type::T_ASSIGN: + array_unshift($child[1][2], $prefix); + break; + + case Type::T_NESTED_PROPERTY: + assert($child[1] instanceof NestedPropertyBlock); + array_unshift($child[1]->prefix[2], $prefix); + break; + } + + $this->compileChild($child, $nested); + } + } + + /** + * Compile nested block + * + * @param \ScssPhp\ScssPhp\Block $block + * @param string[] $selectors + * + * @return void + */ + protected function compileNestedBlock(Block $block, $selectors) + { + $this->pushEnv($block); + + $this->scope = $this->makeOutputBlock($block->type, $selectors); + assert($this->scope->parent !== null); + $this->scope->parent->children[] = $this->scope; + + // wrap assign children in a block + // except for @font-face + if (!$block instanceof DirectiveBlock || $this->compileDirectiveName($block->name) !== 'font-face') { + // need wrapping? + $needWrapping = false; + + foreach ($block->children as $child) { + if ($child[0] === Type::T_ASSIGN) { + $needWrapping = true; + break; + } + } + + if ($needWrapping) { + $wrapped = new Block(); + $wrapped->sourceName = $block->sourceName; + $wrapped->sourceIndex = $block->sourceIndex; + $wrapped->sourceLine = $block->sourceLine; + $wrapped->sourceColumn = $block->sourceColumn; + $wrapped->selectors = []; + $wrapped->comments = []; + $wrapped->parent = $block; + $wrapped->children = $block->children; + $wrapped->selfParent = $block->selfParent; + + $block->children = [[Type::T_BLOCK, $wrapped]]; + } + } + + $this->compileChildrenNoReturn($block->children, $this->scope); + + assert($this->scope !== null); + $this->scope = $this->scope->parent; + + $this->popEnv(); + } + + /** + * Recursively compiles a block. + * + * A block is analogous to a CSS block in most cases. A single SCSS document + * is encapsulated in a block when parsed, but it does not have parent tags + * so all of its children appear on the root level when compiled. + * + * Blocks are made up of selectors and children. + * + * The children of a block are just all the blocks that are defined within. + * + * Compiling the block involves pushing a fresh environment on the stack, + * and iterating through the props, compiling each one. + * + * @see Compiler::compileChild() + * + * @param \ScssPhp\ScssPhp\Block $block + * + * @return void + */ + protected function compileBlock(Block $block) + { + $env = $this->pushEnv($block); + assert($block->selectors !== null); + $env->selectors = $this->evalSelectors($block->selectors); + + $out = $this->makeOutputBlock(null); + + assert($this->scope !== null); + $this->scope->children[] = $out; + + if (\count($block->children)) { + $out->selectors = $this->multiplySelectors($env, $block->selfParent); + + // propagate selfParent to the children where they still can be useful + $selfParentSelectors = null; + + if (isset($block->selfParent->selectors)) { + $selfParentSelectors = $block->selfParent->selectors; + $block->selfParent->selectors = $out->selectors; + } + + $this->compileChildrenNoReturn($block->children, $out, $block->selfParent); + + // and revert for the following children of the same block + if ($selfParentSelectors) { + assert($block->selfParent !== null); + $block->selfParent->selectors = $selfParentSelectors; + } + } + + $this->popEnv(); + } + + + /** + * Compile the value of a comment that can have interpolation + * + * @param array $value + * @param bool $pushEnv + * + * @return string + */ + protected function compileCommentValue($value, $pushEnv = false) + { + $c = $value[1]; + + if (isset($value[2])) { + if ($pushEnv) { + $this->pushEnv(); + } + + try { + $c = $this->compileValue($value[2]); + } catch (SassScriptException $e) { + $this->logger->warn('Ignoring interpolation errors in multiline comments is deprecated and will be removed in ScssPhp 2.0. ' . $this->addLocationToMessage($e->getMessage()), true); + // ignore error in comment compilation which are only interpolation + } catch (SassException $e) { + $this->logger->warn('Ignoring interpolation errors in multiline comments is deprecated and will be removed in ScssPhp 2.0. ' . $e->getMessage(), true); + // ignore error in comment compilation which are only interpolation + } + + if ($pushEnv) { + $this->popEnv(); + } + } + + return $c; + } + + /** + * Compile root level comment + * + * @param array $block + * + * @return void + */ + protected function compileComment($block) + { + $out = $this->makeOutputBlock(Type::T_COMMENT); + $out->lines[] = $this->compileCommentValue($block, true); + + assert($this->scope !== null); + $this->scope->children[] = $out; + } + + /** + * Evaluate selectors + * + * @param array $selectors + * + * @return array + */ + protected function evalSelectors($selectors) + { + $this->shouldEvaluate = false; + + $evaluatedSelectors = []; + foreach ($selectors as $selector) { + $evaluatedSelectors[] = $this->evalSelector($selector); + } + $selectors = $evaluatedSelectors; + + // after evaluating interpolates, we might need a second pass + if ($this->shouldEvaluate) { + $selectors = $this->replaceSelfSelector($selectors, '&'); + $buffer = $this->collapseSelectors($selectors); + $parser = $this->parserFactory(__METHOD__); + + try { + $isValid = $parser->parseSelector($buffer, $newSelectors, true); + } catch (ParserException $e) { + throw $this->error($e->getMessage()); + } + + if ($isValid) { + $selectors = array_map([$this, 'evalSelector'], $newSelectors); + } + } + + return $selectors; + } + + /** + * Evaluate selector + * + * @param array $selector + * + * @return array + * + * @phpstan-impure + */ + protected function evalSelector($selector) + { + return array_map([$this, 'evalSelectorPart'], $selector); + } + + /** + * Evaluate selector part; replaces all the interpolates, stripping quotes + * + * @param array $part + * + * @return array + * + * @phpstan-impure + */ + protected function evalSelectorPart($part) + { + foreach ($part as &$p) { + if (\is_array($p) && ($p[0] === Type::T_INTERPOLATE || $p[0] === Type::T_STRING)) { + $p = $this->compileValue($p); + + // force re-evaluation if self char or non standard char + if (preg_match(',[^\w-],', $p)) { + $this->shouldEvaluate = true; + } + } elseif ( + \is_string($p) && \strlen($p) >= 2 && + ($p[0] === '"' || $p[0] === "'") && + substr($p, -1) === $p[0] + ) { + $p = substr($p, 1, -1); + } + } + + return $this->flattenSelectorSingle($part); + } + + /** + * Collapse selectors + * + * @param array $selectors + * + * @return string + */ + protected function collapseSelectors($selectors) + { + $parts = []; + + foreach ($selectors as $selector) { + $output = []; + + foreach ($selector as $node) { + $compound = ''; + + if (!is_array($node)) { + $output[] = $node; + continue; + } + + array_walk_recursive( + $node, + function ($value, $key) use (&$compound) { + $compound .= $value; + } + ); + + $output[] = $compound; + } + + $parts[] = implode(' ', $output); + } + + return implode(', ', $parts); + } + + /** + * Collapse selectors + * + * @param array $selectors + * + * @return array + */ + private function collapseSelectorsAsList($selectors) + { + $parts = []; + + foreach ($selectors as $selector) { + $output = []; + $glueNext = false; + + foreach ($selector as $node) { + $compound = ''; + + if (!is_array($node)) { + $compound .= $node; + } else { + array_walk_recursive( + $node, + function ($value, $key) use (&$compound) { + $compound .= $value; + } + ); + } + + if ($this->isImmediateRelationshipCombinator($compound)) { + if (\count($output)) { + $output[\count($output) - 1] .= ' ' . $compound; + } else { + $output[] = $compound; + } + + $glueNext = true; + } elseif ($glueNext) { + $output[\count($output) - 1] .= ' ' . $compound; + $glueNext = false; + } else { + $output[] = $compound; + } + } + + foreach ($output as &$o) { + $o = [Type::T_STRING, '', [$o]]; + } + + $parts[] = [Type::T_LIST, ' ', $output]; + } + + return [Type::T_LIST, ',', $parts]; + } + + /** + * Parse down the selector and revert [self] to "&" before a reparsing + * + * @param array $selectors + * @param string|null $replace + * + * @return array + */ + protected function replaceSelfSelector($selectors, $replace = null) + { + foreach ($selectors as &$part) { + if (\is_array($part)) { + if ($part === [Type::T_SELF]) { + if (\is_null($replace)) { + $replace = $this->reduce([Type::T_SELF]); + $replace = $this->compileValue($replace); + } + $part = $replace; + } else { + $part = $this->replaceSelfSelector($part, $replace); + } + } + } + + return $selectors; + } + + /** + * Flatten selector single; joins together .classes and #ids + * + * @param array $single + * + * @return array + */ + protected function flattenSelectorSingle($single) + { + $joined = []; + + foreach ($single as $part) { + if ( + empty($joined) || + ! \is_string($part) || + preg_match('/[\[.:#%]/', $part) + ) { + $joined[] = $part; + continue; + } + + if (\is_array(end($joined))) { + $joined[] = $part; + } else { + $joined[\count($joined) - 1] .= $part; + } + } + + return $joined; + } + + /** + * Compile selector to string; self(&) should have been replaced by now + * + * @param string|array $selector + * + * @return string + */ + protected function compileSelector($selector) + { + if (! \is_array($selector)) { + return $selector; // media and the like + } + + return implode( + ' ', + array_map( + [$this, 'compileSelectorPart'], + $selector + ) + ); + } + + /** + * Compile selector part + * + * @param array $piece + * + * @return string + */ + protected function compileSelectorPart($piece) + { + foreach ($piece as &$p) { + if (! \is_array($p)) { + continue; + } + + switch ($p[0]) { + case Type::T_SELF: + $p = '&'; + break; + + default: + $p = $this->compileValue($p); + break; + } + } + + return implode($piece); + } + + /** + * Has selector placeholder? + * + * @param array $selector + * + * @return bool + */ + protected function hasSelectorPlaceholder($selector) + { + if (! \is_array($selector)) { + return false; + } + + foreach ($selector as $parts) { + foreach ($parts as $part) { + if (\strlen($part) && '%' === $part[0]) { + return true; + } + } + } + + return false; + } + + /** + * @param string $name + * + * @return void + */ + protected function pushCallStack($name = '') + { + $this->callStack[] = [ + 'n' => $name, + Parser::SOURCE_INDEX => $this->sourceIndex, + Parser::SOURCE_LINE => $this->sourceLine, + Parser::SOURCE_COLUMN => $this->sourceColumn + ]; + + // infinite calling loop + if (\count($this->callStack) > 25000) { + // not displayed but you can var_dump it to deep debug + $msg = $this->callStackMessage(true, 100); + $msg = 'Infinite calling loop'; + + throw $this->error($msg); + } + } + + /** + * @return void + */ + protected function popCallStack() + { + array_pop($this->callStack); + } + + /** + * Compile children and return result + * + * @param array $stms + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param string $traceName + * + * @return array|Number|null + */ + protected function compileChildren($stms, OutputBlock $out, $traceName = '') + { + $this->pushCallStack($traceName); + + foreach ($stms as $stm) { + $ret = $this->compileChild($stm, $out); + + if (isset($ret)) { + $this->popCallStack(); + + return $ret; + } + } + + $this->popCallStack(); + + return null; + } + + /** + * Compile children and throw exception if unexpected at-return + * + * @param array[] $stms + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param \ScssPhp\ScssPhp\Block $selfParent + * @param string $traceName + * + * @return void + * + * @throws \Exception + */ + protected function compileChildrenNoReturn($stms, OutputBlock $out, $selfParent = null, $traceName = '') + { + $this->pushCallStack($traceName); + + foreach ($stms as $stm) { + if ($selfParent && isset($stm[1]) && \is_object($stm[1]) && $stm[1] instanceof Block) { + $oldSelfParent = $stm[1]->selfParent; + $stm[1]->selfParent = $selfParent; + $ret = $this->compileChild($stm, $out); + $stm[1]->selfParent = $oldSelfParent; + } elseif ($selfParent && \in_array($stm[0], [Type::T_INCLUDE, Type::T_EXTEND])) { + $stm['selfParent'] = $selfParent; + $ret = $this->compileChild($stm, $out); + } else { + $ret = $this->compileChild($stm, $out); + } + + if (isset($ret)) { + throw $this->error('@return may only be used within a function'); + } + } + + $this->popCallStack(); + } + + + /** + * evaluate media query : compile internal value keeping the structure unchanged + * + * @param array $queryList + * + * @return array + */ + protected function evaluateMediaQuery($queryList) + { + static $parser = null; + + $outQueryList = []; + + foreach ($queryList as $kql => $query) { + $shouldReparse = false; + + foreach ($query as $kq => $q) { + for ($i = 1; $i < \count($q); $i++) { + $value = $this->compileValue($q[$i]); + + // the parser had no mean to know if media type or expression if it was an interpolation + // so you need to reparse if the T_MEDIA_TYPE looks like anything else a media type + if ( + $q[0] == Type::T_MEDIA_TYPE && + (strpos($value, '(') !== false || + strpos($value, ')') !== false || + strpos($value, ':') !== false || + strpos($value, ',') !== false) + ) { + $shouldReparse = true; + } + + $queryList[$kql][$kq][$i] = [Type::T_KEYWORD, $value]; + } + } + + if ($shouldReparse) { + if (\is_null($parser)) { + $parser = $this->parserFactory(__METHOD__); + } + + $queryString = $this->compileMediaQuery([$queryList[$kql]]); + $queryString = reset($queryString); + + if ($queryString !== false && strpos($queryString, '@media ') === 0) { + $queryString = substr($queryString, 7); + $queries = []; + + if ($parser->parseMediaQueryList($queryString, $queries)) { + $queries = $this->evaluateMediaQuery($queries[2]); + + while (\count($queries)) { + $outQueryList[] = array_shift($queries); + } + + continue; + } + } + } + + $outQueryList[] = $queryList[$kql]; + } + + return $outQueryList; + } + + /** + * Compile media query + * + * @param array $queryList + * + * @return string[] + */ + protected function compileMediaQuery($queryList) + { + $start = '@media '; + $default = trim($start); + $out = []; + $current = ''; + + foreach ($queryList as $query) { + $type = null; + $parts = []; + + $mediaTypeOnly = true; + + foreach ($query as $q) { + if ($q[0] !== Type::T_MEDIA_TYPE) { + $mediaTypeOnly = false; + break; + } + } + + foreach ($query as $q) { + switch ($q[0]) { + case Type::T_MEDIA_TYPE: + $newType = array_map([$this, 'compileValue'], \array_slice($q, 1)); + + // combining not and anything else than media type is too risky and should be avoided + if (! $mediaTypeOnly) { + if (\in_array(Type::T_NOT, $newType) || ($type && \in_array(Type::T_NOT, $type) )) { + if ($type) { + array_unshift($parts, implode(' ', array_filter($type))); + } + + if (! empty($parts)) { + if (\strlen($current)) { + $current .= $this->formatter->tagSeparator; + } + + $current .= implode(' and ', $parts); + } + + if ($current) { + $out[] = $start . $current; + } + + $current = ''; + $type = null; + $parts = []; + } + } + + if ($newType === ['all'] && $default) { + $default = $start . 'all'; + } + + // all can be safely ignored and mixed with whatever else + if ($newType !== ['all']) { + if ($type) { + $type = $this->mergeMediaTypes($type, $newType); + + if (empty($type)) { + // merge failed : ignore this query that is not valid, skip to the next one + $parts = []; + $default = ''; // if everything fail, no @media at all + continue 3; + } + } else { + $type = $newType; + } + } + break; + + case Type::T_MEDIA_EXPRESSION: + if (isset($q[2])) { + $parts[] = '(' + . $this->compileValue($q[1]) + . $this->formatter->assignSeparator + . $this->compileValue($q[2]) + . ')'; + } else { + $parts[] = '(' + . $this->compileValue($q[1]) + . ')'; + } + break; + + case Type::T_MEDIA_VALUE: + $parts[] = $this->compileValue($q[1]); + break; + } + } + + if ($type) { + array_unshift($parts, implode(' ', array_filter($type))); + } + + if (! empty($parts)) { + if (\strlen($current)) { + $current .= $this->formatter->tagSeparator; + } + + $current .= implode(' and ', $parts); + } + } + + if ($current) { + $out[] = $start . $current; + } + + // no @media type except all, and no conflict? + if (! $out && $default) { + $out[] = $default; + } + + return $out; + } + + /** + * Merge direct relationships between selectors + * + * @param array $selectors1 + * @param array $selectors2 + * + * @return array + */ + protected function mergeDirectRelationships($selectors1, $selectors2) + { + if (empty($selectors1) || empty($selectors2)) { + return array_merge($selectors1, $selectors2); + } + + $part1 = end($selectors1); + $part2 = end($selectors2); + + if (! $this->isImmediateRelationshipCombinator($part1[0]) && $part1 !== $part2) { + return array_merge($selectors1, $selectors2); + } + + $merged = []; + + do { + $part1 = array_pop($selectors1); + $part2 = array_pop($selectors2); + + if (! $this->isImmediateRelationshipCombinator($part1[0]) && $part1 !== $part2) { + if ($this->isImmediateRelationshipCombinator(reset($merged)[0])) { + array_unshift($merged, [$part1[0] . $part2[0]]); + $merged = array_merge($selectors1, $selectors2, $merged); + } else { + $merged = array_merge($selectors1, [$part1], $selectors2, [$part2], $merged); + } + + break; + } + + array_unshift($merged, $part1); + } while (! empty($selectors1) && ! empty($selectors2)); + + return $merged; + } + + /** + * Merge media types + * + * @param array $type1 + * @param array $type2 + * + * @return array|null + */ + protected function mergeMediaTypes($type1, $type2) + { + if (empty($type1)) { + return $type2; + } + + if (empty($type2)) { + return $type1; + } + + if (\count($type1) > 1) { + $m1 = strtolower($type1[0]); + $t1 = strtolower($type1[1]); + } else { + $m1 = ''; + $t1 = strtolower($type1[0]); + } + + if (\count($type2) > 1) { + $m2 = strtolower($type2[0]); + $t2 = strtolower($type2[1]); + } else { + $m2 = ''; + $t2 = strtolower($type2[0]); + } + + if (($m1 === Type::T_NOT) ^ ($m2 === Type::T_NOT)) { + if ($t1 === $t2) { + return null; + } + + return [ + $m1 === Type::T_NOT ? $m2 : $m1, + $m1 === Type::T_NOT ? $t2 : $t1, + ]; + } + + if ($m1 === Type::T_NOT && $m2 === Type::T_NOT) { + // CSS has no way of representing "neither screen nor print" + if ($t1 !== $t2) { + return null; + } + + return [Type::T_NOT, $t1]; + } + + if ($t1 !== $t2) { + return null; + } + + // t1 == t2, neither m1 nor m2 are "not" + return [empty($m1) ? $m2 : $m1, $t1]; + } + + /** + * Compile import; returns true if the value was something that could be imported + * + * @param array $rawPath + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param bool $once + * + * @return bool + */ + protected function compileImport($rawPath, OutputBlock $out, $once = false) + { + if ($rawPath[0] === Type::T_STRING) { + $path = $this->compileStringContent($rawPath); + + if (strpos($path, 'url(') !== 0 && $filePath = $this->findImport($path, $this->currentDirectory)) { + $this->registerImport($this->currentDirectory, $path, $filePath); + + if (! $once || ! \in_array($filePath, $this->importedFiles)) { + $this->importFile($filePath, $out); + $this->importedFiles[] = $filePath; + } + + return true; + } + + $this->appendRootDirective('@import ' . $this->compileImportPath($rawPath) . ';', $out); + + return false; + } + + if ($rawPath[0] === Type::T_LIST) { + // handle a list of strings + if (\count($rawPath[2]) === 0) { + return false; + } + + foreach ($rawPath[2] as $path) { + if ($path[0] !== Type::T_STRING) { + $this->appendRootDirective('@import ' . $this->compileImportPath($rawPath) . ';', $out); + + return false; + } + } + + foreach ($rawPath[2] as $path) { + $this->compileImport($path, $out, $once); + } + + return true; + } + + $this->appendRootDirective('@import ' . $this->compileImportPath($rawPath) . ';', $out); + + return false; + } + + /** + * @param array $rawPath + * @return string + * @throws CompilerException + */ + protected function compileImportPath($rawPath) + { + $path = $this->compileValue($rawPath); + + // case url() without quotes : suppress \r \n remaining in the path + // if this is a real string there can not be CR or LF char + if (strpos($path, 'url(') === 0) { + $path = str_replace(array("\r", "\n"), array('', ' '), $path); + } else { + // if this is a file name in a string, spaces should be escaped + $path = $this->reduce($rawPath); + $path = $this->escapeImportPathString($path); + $path = $this->compileValue($path); + } + + return $path; + } + + /** + * @param array $path + * @return array + * @throws CompilerException + */ + protected function escapeImportPathString($path) + { + switch ($path[0]) { + case Type::T_LIST: + foreach ($path[2] as $k => $v) { + $path[2][$k] = $this->escapeImportPathString($v); + } + break; + case Type::T_STRING: + if ($path[1]) { + $path = $this->compileValue($path); + $path = str_replace(' ', '\\ ', $path); + $path = [Type::T_KEYWORD, $path]; + } + break; + } + + return $path; + } + + /** + * Append a root directive like @import or @charset as near as the possible from the source code + * (keeping before comments, @import and @charset coming before in the source code) + * + * @param string $line + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param array $allowed + * + * @return void + */ + protected function appendRootDirective($line, $out, $allowed = [Type::T_COMMENT]) + { + $root = $out; + + while ($root->parent) { + $root = $root->parent; + } + + $i = 0; + + while ($i < \count($root->children)) { + if (! isset($root->children[$i]->type) || ! \in_array($root->children[$i]->type, $allowed)) { + break; + } + + $i++; + } + + // remove incompatible children from the bottom of the list + $saveChildren = []; + + while ($i < \count($root->children)) { + $saveChildren[] = array_pop($root->children); + } + + // insert the directive as a comment + $child = $this->makeOutputBlock(Type::T_COMMENT); + $child->lines[] = $line; + $child->sourceName = $this->sourceNames[$this->sourceIndex] ?: '(stdin)'; + $child->sourceLine = $this->sourceLine; + $child->sourceColumn = $this->sourceColumn; + + $root->children[] = $child; + + // repush children + while (\count($saveChildren)) { + $root->children[] = array_pop($saveChildren); + } + } + + /** + * Append lines to the current output block: + * directly to the block or through a child if necessary + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * @param string $type + * @param string $line + * + * @return void + */ + protected function appendOutputLine(OutputBlock $out, $type, $line) + { + $outWrite = &$out; + + // check if it's a flat output or not + if (\count($out->children)) { + $lastChild = &$out->children[\count($out->children) - 1]; + + if ( + $lastChild->depth === $out->depth && + \is_null($lastChild->selectors) && + ! \count($lastChild->children) + ) { + $outWrite = $lastChild; + } else { + $nextLines = $this->makeOutputBlock($type); + $nextLines->parent = $out; + $nextLines->depth = $out->depth; + + $out->children[] = $nextLines; + $outWrite = &$nextLines; + } + } + + $outWrite->lines[] = $line; + } + + /** + * Compile child; returns a value to halt execution + * + * @param array $child + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return array|Number|null + */ + protected function compileChild($child, OutputBlock $out) + { + if (isset($child[Parser::SOURCE_LINE])) { + $this->sourceIndex = isset($child[Parser::SOURCE_INDEX]) ? $child[Parser::SOURCE_INDEX] : null; + $this->sourceLine = $child[Parser::SOURCE_LINE]; + $this->sourceColumn = isset($child[Parser::SOURCE_COLUMN]) ? $child[Parser::SOURCE_COLUMN] : -1; + } elseif (\is_array($child) && isset($child[1]->sourceLine) && $child[1] instanceof Block) { + $this->sourceIndex = $child[1]->sourceIndex; + $this->sourceLine = $child[1]->sourceLine; + $this->sourceColumn = $child[1]->sourceColumn; + } elseif (! empty($out->sourceLine) && ! empty($out->sourceName)) { + $this->sourceLine = $out->sourceLine; + $sourceIndex = array_search($out->sourceName, $this->sourceNames); + $this->sourceColumn = $out->sourceColumn; + + if ($sourceIndex === false) { + $sourceIndex = null; + } + $this->sourceIndex = $sourceIndex; + } + + switch ($child[0]) { + case Type::T_SCSSPHP_IMPORT_ONCE: + $rawPath = $this->reduce($child[1]); + + $this->compileImport($rawPath, $out, true); + break; + + case Type::T_IMPORT: + $rawPath = $this->reduce($child[1]); + + $this->compileImport($rawPath, $out); + break; + + case Type::T_DIRECTIVE: + $this->compileDirective($child[1], $out); + break; + + case Type::T_AT_ROOT: + $this->compileAtRoot($child[1]); + break; + + case Type::T_MEDIA: + $this->compileMedia($child[1]); + break; + + case Type::T_BLOCK: + $this->compileBlock($child[1]); + break; + + case Type::T_CHARSET: + break; + + case Type::T_CUSTOM_PROPERTY: + list(, $name, $value) = $child; + $compiledName = $this->compileValue($name); + + // if the value reduces to null from something else then + // the property should be discarded + if ($value[0] !== Type::T_NULL) { + $value = $this->reduce($value); + + if ($value[0] === Type::T_NULL || $value === static::$nullString) { + break; + } + } + + $compiledValue = $this->compileValue($value); + + $line = $this->formatter->customProperty( + $compiledName, + $compiledValue + ); + + $this->appendOutputLine($out, Type::T_ASSIGN, $line); + break; + + case Type::T_ASSIGN: + list(, $name, $value) = $child; + + if ($name[0] === Type::T_VARIABLE) { + $flags = isset($child[3]) ? $child[3] : []; + $isDefault = \in_array('!default', $flags); + $isGlobal = \in_array('!global', $flags); + + if ($isGlobal) { + $this->set($name[1], $this->reduce($value), false, $this->rootEnv, $value); + break; + } + + $shouldSet = $isDefault && + (\is_null($result = $this->get($name[1], false)) || + $result === static::$null); + + if (! $isDefault || $shouldSet) { + $this->set($name[1], $this->reduce($value), true, null, $value); + } + break; + } + + $compiledName = $this->compileValue($name); + + // handle shorthand syntaxes : size / line-height... + if (\in_array($compiledName, ['font', 'grid-row', 'grid-column', 'border-radius'])) { + if ($value[0] === Type::T_VARIABLE) { + // if the font value comes from variable, the content is already reduced + // (i.e., formulas were already calculated), so we need the original unreduced value + $value = $this->get($value[1], true, null, true); + } + + $shorthandValue=&$value; + + $shorthandDividerNeedsUnit = false; + $maxListElements = null; + $maxShorthandDividers = 1; + + switch ($compiledName) { + case 'border-radius': + $maxListElements = 4; + $shorthandDividerNeedsUnit = true; + break; + } + + if ($compiledName === 'font' && $value[0] === Type::T_LIST && $value[1] === ',') { + // this is the case if more than one font is given: example: "font: 400 1em/1.3 arial,helvetica" + // we need to handle the first list element + $shorthandValue=&$value[2][0]; + } + + if ($shorthandValue[0] === Type::T_EXPRESSION && $shorthandValue[1] === '/') { + $revert = true; + + if ($shorthandDividerNeedsUnit) { + $divider = $shorthandValue[3]; + + if (\is_array($divider)) { + $divider = $this->reduce($divider, true); + } + + if ($divider instanceof Number && \intval($divider->getDimension()) && $divider->unitless()) { + $revert = false; + } + } + + if ($revert) { + $shorthandValue = $this->expToString($shorthandValue); + } + } elseif ($shorthandValue[0] === Type::T_LIST) { + foreach ($shorthandValue[2] as &$item) { + if ($item[0] === Type::T_EXPRESSION && $item[1] === '/') { + if ($maxShorthandDividers > 0) { + $revert = true; + + // if the list of values is too long, this has to be a shorthand, + // otherwise it could be a real division + if (\is_null($maxListElements) || \count($shorthandValue[2]) <= $maxListElements) { + if ($shorthandDividerNeedsUnit) { + $divider = $item[3]; + + if (\is_array($divider)) { + $divider = $this->reduce($divider, true); + } + + if ($divider instanceof Number && \intval($divider->getDimension()) && $divider->unitless()) { + $revert = false; + } + } + } + + if ($revert) { + $item = $this->expToString($item); + $maxShorthandDividers--; + } + } + } + } + } + } + + // if the value reduces to null from something else then + // the property should be discarded + if ($value[0] !== Type::T_NULL) { + $value = $this->reduce($value); + + if ($value[0] === Type::T_NULL || $value === static::$nullString) { + break; + } + } + + $compiledValue = $this->compileValue($value); + + // ignore empty value + if (\strlen($compiledValue)) { + $line = $this->formatter->property( + $compiledName, + $compiledValue + ); + $this->appendOutputLine($out, Type::T_ASSIGN, $line); + } + break; + + case Type::T_COMMENT: + if ($out->type === Type::T_ROOT) { + $this->compileComment($child); + break; + } + + $line = $this->compileCommentValue($child, true); + $this->appendOutputLine($out, Type::T_COMMENT, $line); + break; + + case Type::T_MIXIN: + case Type::T_FUNCTION: + list(, $block) = $child; + assert($block instanceof CallableBlock); + // the block need to be able to go up to it's parent env to resolve vars + $block->parentEnv = $this->getStoreEnv(); + $this->set(static::$namespaces[$block->type] . $block->name, $block, true); + break; + + case Type::T_EXTEND: + foreach ($child[1] as $sel) { + $replacedSel = $this->replaceSelfSelector($sel); + + if ($replacedSel !== $sel) { + throw $this->error('Parent selectors aren\'t allowed here.'); + } + + $results = $this->evalSelectors([$sel]); + + foreach ($results as $result) { + if (\count($result) !== 1) { + throw $this->error('complex selectors may not be extended.'); + } + + // only use the first one + $result = $result[0]; + $selectors = $out->selectors; + + if (! $selectors && isset($child['selfParent'])) { + $selectors = $this->multiplySelectors($this->env, $child['selfParent']); + } + assert($selectors !== null); + + if (\count($result) > 1) { + $replacement = implode(', ', $result); + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + + $message = <<logger->warn($message); + } + + $this->pushExtends($result, $selectors, $child); + } + } + break; + + case Type::T_IF: + list(, $if) = $child; + assert($if instanceof IfBlock); + + if ($this->isTruthy($this->reduce($if->cond, true))) { + return $this->compileChildren($if->children, $out); + } + + foreach ($if->cases as $case) { + if ( + $case instanceof ElseBlock || + $case instanceof ElseifBlock && $this->isTruthy($this->reduce($case->cond)) + ) { + return $this->compileChildren($case->children, $out); + } + } + break; + + case Type::T_EACH: + list(, $each) = $child; + assert($each instanceof EachBlock); + + $list = $this->coerceList($this->reduce($each->list), ',', true); + + $this->pushEnv(); + + foreach ($list[2] as $item) { + if (\count($each->vars) === 1) { + $this->set($each->vars[0], $item, true); + } else { + list(,, $values) = $this->coerceList($item); + + foreach ($each->vars as $i => $var) { + $this->set($var, isset($values[$i]) ? $values[$i] : static::$null, true); + } + } + + $ret = $this->compileChildren($each->children, $out); + + if ($ret) { + $store = $this->env->store; + $this->popEnv(); + $this->backPropagateEnv($store, $each->vars); + + return $ret; + } + } + $store = $this->env->store; + $this->popEnv(); + $this->backPropagateEnv($store, $each->vars); + + break; + + case Type::T_WHILE: + list(, $while) = $child; + assert($while instanceof WhileBlock); + + while ($this->isTruthy($this->reduce($while->cond, true))) { + $ret = $this->compileChildren($while->children, $out); + + if ($ret) { + return $ret; + } + } + break; + + case Type::T_FOR: + list(, $for) = $child; + assert($for instanceof ForBlock); + + $startNumber = $this->assertNumber($this->reduce($for->start, true)); + $endNumber = $this->assertNumber($this->reduce($for->end, true)); + + $start = $this->assertInteger($startNumber); + + $numeratorUnits = $startNumber->getNumeratorUnits(); + $denominatorUnits = $startNumber->getDenominatorUnits(); + + $end = $this->assertInteger($endNumber->coerce($numeratorUnits, $denominatorUnits)); + + $d = $start < $end ? 1 : -1; + + $this->pushEnv(); + + for (;;) { + if ( + (! $for->until && $start - $d == $end) || + ($for->until && $start == $end) + ) { + break; + } + + $this->set($for->var, new Number($start, $numeratorUnits, $denominatorUnits)); + $start += $d; + + $ret = $this->compileChildren($for->children, $out); + + if ($ret) { + $store = $this->env->store; + $this->popEnv(); + $this->backPropagateEnv($store, [$for->var]); + + return $ret; + } + } + + $store = $this->env->store; + $this->popEnv(); + $this->backPropagateEnv($store, [$for->var]); + + break; + + case Type::T_RETURN: + return $this->reduce($child[1], true); + + case Type::T_NESTED_PROPERTY: + $this->compileNestedPropertiesBlock($child[1], $out); + break; + + case Type::T_INCLUDE: + // including a mixin + list(, $name, $argValues, $content, $argUsing) = $child; + + $mixin = $this->get(static::$namespaces['mixin'] . $name, false); + + if (! $mixin) { + throw $this->error("Undefined mixin $name"); + } + + assert($mixin instanceof CallableBlock); + + $callingScope = $this->getStoreEnv(); + + // push scope, apply args + $this->pushEnv(); + $this->env->depth--; + + // Find the parent selectors in the env to be able to know what '&' refers to in the mixin + // and assign this fake parent to childs + $selfParent = null; + + if (isset($child['selfParent']) && $child['selfParent'] instanceof Block && isset($child['selfParent']->selectors)) { + $selfParent = $child['selfParent']; + } else { + $parentSelectors = $this->multiplySelectors($this->env); + + if ($parentSelectors) { + $parent = new Block(); + $parent->selectors = $parentSelectors; + + foreach ($mixin->children as $k => $child) { + if (isset($child[1]) && $child[1] instanceof Block) { + $mixin->children[$k][1]->parent = $parent; + } + } + } + } + + // clone the stored content to not have its scope spoiled by a further call to the same mixin + // i.e., recursive @include of the same mixin + if (isset($content)) { + $copyContent = clone $content; + $copyContent->scope = clone $callingScope; + + $this->setRaw(static::$namespaces['special'] . 'content', $copyContent, $this->env); + } else { + $this->setRaw(static::$namespaces['special'] . 'content', null, $this->env); + } + + // save the "using" argument list for applying it to when "@content" is invoked + if (isset($argUsing)) { + $this->setRaw(static::$namespaces['special'] . 'using', $argUsing, $this->env); + } else { + $this->setRaw(static::$namespaces['special'] . 'using', null, $this->env); + } + + if (isset($mixin->args)) { + $this->applyArguments($mixin->args, $argValues); + } + + $this->env->marker = 'mixin'; + + if (! empty($mixin->parentEnv)) { + $this->env->declarationScopeParent = $mixin->parentEnv; + } else { + throw $this->error("@mixin $name() without parentEnv"); + } + + $this->compileChildrenNoReturn($mixin->children, $out, $selfParent, $this->env->marker . ' ' . $name); + + $this->popEnv(); + break; + + case Type::T_MIXIN_CONTENT: + $env = isset($this->storeEnv) ? $this->storeEnv : $this->env; + $content = $this->get(static::$namespaces['special'] . 'content', false, $env); + $argUsing = $this->get(static::$namespaces['special'] . 'using', false, $env); + $argContent = $child[1]; + + if (! $content) { + break; + } + + $storeEnv = $this->storeEnv; + $varsUsing = []; + + if (isset($argUsing) && isset($argContent)) { + // Get the arguments provided for the content with the names provided in the "using" argument list + $this->storeEnv = null; + $varsUsing = $this->applyArguments($argUsing, $argContent, false); + } + + // restore the scope from the @content + $this->storeEnv = $content->scope; + + // append the vars from using if any + foreach ($varsUsing as $name => $val) { + $this->set($name, $val, true, $this->storeEnv); + } + + $this->compileChildrenNoReturn($content->children, $out); + + $this->storeEnv = $storeEnv; + break; + + case Type::T_DEBUG: + list(, $value) = $child; + + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + $value = $this->compileDebugValue($value); + + $this->logger->debug("$fname:$line DEBUG: $value"); + break; + + case Type::T_WARN: + list(, $value) = $child; + + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + $value = $this->compileDebugValue($value); + + $this->logger->warn("$value\n on line $line of $fname"); + break; + + case Type::T_ERROR: + list(, $value) = $child; + + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + $value = $this->compileValue($this->reduce($value, true)); + + throw $this->error("File $fname on line $line ERROR: $value\n"); + + default: + throw $this->error("unknown child type: $child[0]"); + } + + return null; + } + + /** + * Reduce expression to string + * + * @param array $exp + * @param bool $keepParens + * + * @return array + */ + protected function expToString($exp, $keepParens = false) + { + list(, $op, $left, $right, $inParens, $whiteLeft, $whiteRight) = $exp; + + $content = []; + + if ($keepParens && $inParens) { + $content[] = '('; + } + + $content[] = $this->reduce($left); + + if ($whiteLeft) { + $content[] = ' '; + } + + $content[] = $op; + + if ($whiteRight) { + $content[] = ' '; + } + + $content[] = $this->reduce($right); + + if ($keepParens && $inParens) { + $content[] = ')'; + } + + return [Type::T_STRING, '', $content]; + } + + /** + * Is truthy? + * + * @param array|Number $value + * + * @return bool + */ + public function isTruthy($value) + { + return $value !== static::$false && $value !== static::$null; + } + + /** + * Is the value a direct relationship combinator? + * + * @param string $value + * + * @return bool + */ + protected function isImmediateRelationshipCombinator($value) + { + return $value === '>' || $value === '+' || $value === '~'; + } + + /** + * Should $value cause its operand to eval + * + * @param array $value + * + * @return bool + */ + protected function shouldEval($value) + { + switch ($value[0]) { + case Type::T_EXPRESSION: + if ($value[1] === '/') { + return $this->shouldEval($value[2]) || $this->shouldEval($value[3]); + } + + // fall-thru + case Type::T_VARIABLE: + case Type::T_FUNCTION_CALL: + return true; + } + + return false; + } + + /** + * Reduce value + * + * @param array|Number $value + * @param bool $inExp + * + * @return array|Number + */ + protected function reduce($value, $inExp = false) + { + if ($value instanceof Number) { + return $value; + } + + switch ($value[0]) { + case Type::T_EXPRESSION: + list(, $op, $left, $right, $inParens) = $value; + + $opName = isset(static::$operatorNames[$op]) ? static::$operatorNames[$op] : $op; + $inExp = $inExp || $this->shouldEval($left) || $this->shouldEval($right); + + $left = $this->reduce($left, true); + + if ($op !== 'and' && $op !== 'or') { + $right = $this->reduce($right, true); + } + + // special case: looks like css shorthand + if ( + $opName == 'div' && ! $inParens && ! $inExp && + (($right[0] !== Type::T_NUMBER && isset($right[2]) && $right[2] != '') || + ($right[0] === Type::T_NUMBER && ! $right->unitless())) + ) { + return $this->expToString($value); + } + + $left = $this->coerceForExpression($left); + $right = $this->coerceForExpression($right); + $ltype = $left[0]; + $rtype = $right[0]; + + $ucOpName = ucfirst($opName); + $ucLType = ucfirst($ltype); + $ucRType = ucfirst($rtype); + + $shouldEval = $inParens || $inExp; + + // this tries: + // 1. op[op name][left type][right type] + // 2. op[left type][right type] (passing the op as first arg) + // 3. op[op name] + if (\is_callable([$this, $fn = "op{$ucOpName}{$ucLType}{$ucRType}"])) { + $out = $this->$fn($left, $right, $shouldEval); + } elseif (\is_callable([$this, $fn = "op{$ucLType}{$ucRType}"])) { + $out = $this->$fn($op, $left, $right, $shouldEval); + } elseif (\is_callable([$this, $fn = "op{$ucOpName}"])) { + $out = $this->$fn($left, $right, $shouldEval); + } else { + $out = null; + } + + if (isset($out)) { + return $out; + } + + return $this->expToString($value); + + case Type::T_UNARY: + list(, $op, $exp, $inParens) = $value; + + $inExp = $inExp || $this->shouldEval($exp); + $exp = $this->reduce($exp); + + if ($exp instanceof Number) { + switch ($op) { + case '+': + return $exp; + + case '-': + return $exp->unaryMinus(); + } + } + + if ($op === 'not') { + if ($inExp || $inParens) { + if ($exp === static::$false || $exp === static::$null) { + return static::$true; + } + + return static::$false; + } + + $op = $op . ' '; + } + + return [Type::T_STRING, '', [$op, $exp]]; + + case Type::T_VARIABLE: + return $this->reduce($this->get($value[1])); + + case Type::T_LIST: + foreach ($value[2] as &$item) { + $item = $this->reduce($item); + } + unset($item); + + if (isset($value[3]) && \is_array($value[3])) { + foreach ($value[3] as &$item) { + $item = $this->reduce($item); + } + unset($item); + } + + return $value; + + case Type::T_MAP: + foreach ($value[1] as &$item) { + $item = $this->reduce($item); + } + + foreach ($value[2] as &$item) { + $item = $this->reduce($item); + } + + return $value; + + case Type::T_STRING: + foreach ($value[2] as &$item) { + if (\is_array($item) || $item instanceof Number) { + $item = $this->reduce($item); + } + } + + return $value; + + case Type::T_INTERPOLATE: + $value[1] = $this->reduce($value[1]); + + if ($inExp) { + return [Type::T_KEYWORD, $this->compileValue($value, false)]; + } + + return $value; + + case Type::T_FUNCTION_CALL: + return $this->fncall($value[1], $value[2]); + + case Type::T_SELF: + $selfParent = ! empty($this->env->block->selfParent) ? $this->env->block->selfParent : null; + $selfSelector = $this->multiplySelectors($this->env, $selfParent); + $selfSelector = $this->collapseSelectorsAsList($selfSelector); + + return $selfSelector; + + default: + return $value; + } + } + + /** + * Function caller + * + * @param string|array $functionReference + * @param array $argValues + * + * @return array|Number + */ + protected function fncall($functionReference, $argValues) + { + // a string means this is a static hard reference coming from the parsing + if (is_string($functionReference)) { + $name = $functionReference; + + $functionReference = $this->getFunctionReference($name); + if ($functionReference === static::$null || $functionReference[0] !== Type::T_FUNCTION_REFERENCE) { + $functionReference = [Type::T_FUNCTION, $name, [Type::T_LIST, ',', []]]; + } + } + + // a function type means we just want a plain css function call + if ($functionReference[0] === Type::T_FUNCTION) { + // for CSS functions, simply flatten the arguments into a list + $listArgs = []; + + foreach ((array) $argValues as $arg) { + if (empty($arg[0]) || count($argValues) === 1) { + $listArgs[] = $this->reduce($this->stringifyFncallArgs($arg[1])); + } + } + + return [Type::T_FUNCTION, $functionReference[1], [Type::T_LIST, ',', $listArgs]]; + } + + if ($functionReference === static::$null || $functionReference[0] !== Type::T_FUNCTION_REFERENCE) { + return static::$defaultValue; + } + + + switch ($functionReference[1]) { + // SCSS @function + case 'scss': + return $this->callScssFunction($functionReference[3], $argValues); + + // native PHP functions + case 'user': + case 'native': + list(,,$name, $fn, $prototype) = $functionReference; + + // special cases of css valid functions min/max + $name = strtolower($name); + if (\in_array($name, ['min', 'max']) && count($argValues) >= 1) { + $cssFunction = $this->cssValidArg( + [Type::T_FUNCTION_CALL, $name, $argValues], + ['min', 'max', 'calc', 'env', 'var'] + ); + if ($cssFunction !== false) { + return $cssFunction; + } + } + $returnValue = $this->callNativeFunction($name, $fn, $prototype, $argValues); + + if (! isset($returnValue)) { + return $this->fncall([Type::T_FUNCTION, $name, [Type::T_LIST, ',', []]], $argValues); + } + + return $returnValue; + + default: + return static::$defaultValue; + } + } + + /** + * @param array|Number $arg + * @param string[] $allowed_function + * @param bool $inFunction + * + * @return array|Number|false + */ + protected function cssValidArg($arg, $allowed_function = [], $inFunction = false) + { + if ($arg instanceof Number) { + return $this->stringifyFncallArgs($arg); + } + + switch ($arg[0]) { + case Type::T_INTERPOLATE: + return [Type::T_KEYWORD, $this->CompileValue($arg)]; + + case Type::T_FUNCTION: + if (! \in_array($arg[1], $allowed_function)) { + return false; + } + if ($arg[2][0] === Type::T_LIST) { + foreach ($arg[2][2] as $k => $subarg) { + $arg[2][2][$k] = $this->cssValidArg($subarg, $allowed_function, $arg[1]); + if ($arg[2][2][$k] === false) { + return false; + } + } + } + return $arg; + + case Type::T_FUNCTION_CALL: + if (! \in_array($arg[1], $allowed_function)) { + return false; + } + $cssArgs = []; + foreach ($arg[2] as $argValue) { + if ($argValue === static::$null) { + return false; + } + $cssArg = $this->cssValidArg($argValue[1], $allowed_function, $arg[1]); + if (empty($argValue[0]) && $cssArg !== false) { + $cssArgs[] = [$argValue[0], $cssArg]; + } else { + return false; + } + } + + return $this->fncall([Type::T_FUNCTION, $arg[1], [Type::T_LIST, ',', []]], $cssArgs); + + case Type::T_STRING: + case Type::T_KEYWORD: + if (!$inFunction or !\in_array($inFunction, ['calc', 'env', 'var'])) { + return false; + } + return $this->stringifyFncallArgs($arg); + + case Type::T_LIST: + if (!$inFunction) { + return false; + } + if (empty($arg['enclosing']) and $arg[1] === '') { + foreach ($arg[2] as $k => $subarg) { + $arg[2][$k] = $this->cssValidArg($subarg, $allowed_function, $inFunction); + if ($arg[2][$k] === false) { + return false; + } + } + $arg[0] = Type::T_STRING; + return $arg; + } + return false; + + case Type::T_EXPRESSION: + if (! \in_array($arg[1], ['+', '-', '/', '*'])) { + return false; + } + $arg[2] = $this->cssValidArg($arg[2], $allowed_function, $inFunction); + $arg[3] = $this->cssValidArg($arg[3], $allowed_function, $inFunction); + if ($arg[2] === false || $arg[3] === false) { + return false; + } + return $this->expToString($arg, true); + + case Type::T_VARIABLE: + case Type::T_SELF: + default: + return false; + } + } + + + /** + * Reformat fncall arguments to proper css function output + * + * @param array|Number $arg + * + * @return array|Number + */ + protected function stringifyFncallArgs($arg) + { + if ($arg instanceof Number) { + return $arg; + } + + switch ($arg[0]) { + case Type::T_LIST: + foreach ($arg[2] as $k => $v) { + $arg[2][$k] = $this->stringifyFncallArgs($v); + } + break; + + case Type::T_EXPRESSION: + if ($arg[1] === '/') { + $arg[2] = $this->stringifyFncallArgs($arg[2]); + $arg[3] = $this->stringifyFncallArgs($arg[3]); + $arg[5] = $arg[6] = false; // no space around / + $arg = $this->expToString($arg); + } + break; + + case Type::T_FUNCTION_CALL: + $name = strtolower($arg[1]); + + if (in_array($name, ['max', 'min', 'calc'])) { + $args = $arg[2]; + $arg = $this->fncall([Type::T_FUNCTION, $name, [Type::T_LIST, ',', []]], $args); + } + break; + } + + return $arg; + } + + /** + * Find a function reference + * @param string $name + * @param bool $safeCopy + * @return array + */ + protected function getFunctionReference($name, $safeCopy = false) + { + // SCSS @function + if ($func = $this->get(static::$namespaces['function'] . $name, false)) { + if ($safeCopy) { + $func = clone $func; + } + + return [Type::T_FUNCTION_REFERENCE, 'scss', $name, $func]; + } + + // native PHP functions + + // try to find a native lib function + $normalizedName = $this->normalizeName($name); + + if (isset($this->userFunctions[$normalizedName])) { + // see if we can find a user function + list($f, $prototype) = $this->userFunctions[$normalizedName]; + + return [Type::T_FUNCTION_REFERENCE, 'user', $name, $f, $prototype]; + } + + $lowercasedName = strtolower($normalizedName); + + // Special functions overriding a CSS function are case-insensitive. We normalize them as lowercase + // to avoid the deprecation warning about the wrong case being used. + if ($lowercasedName === 'min' || $lowercasedName === 'max' || $lowercasedName === 'rgb' || $lowercasedName === 'rgba' || $lowercasedName === 'hsl' || $lowercasedName === 'hsla') { + $normalizedName = $lowercasedName; + } + + if (($f = $this->getBuiltinFunction($normalizedName)) && \is_callable($f)) { + /** @var string $libName */ + $libName = $f[1]; + $prototype = isset(static::$$libName) ? static::$$libName : null; + + // All core functions have a prototype defined. Not finding the + // prototype can mean 2 things: + // - the function comes from a child class (deprecated just after) + // - the function was found with a different case, which relates to calling the + // wrong Sass function due to our camelCase usage (`fade-in()` vs `fadein()`), + // because PHP method names are case-insensitive while property names are + // case-sensitive. + if ($prototype === null || strtolower($normalizedName) !== $normalizedName) { + $r = new \ReflectionMethod($this, $libName); + $actualLibName = $r->name; + + if ($actualLibName !== $libName || strtolower($normalizedName) !== $normalizedName) { + $kebabCaseName = preg_replace('~(?<=\\w)([A-Z])~', '-$1', substr($actualLibName, 3)); + assert($kebabCaseName !== null); + $originalName = strtolower($kebabCaseName); + $warning = "Calling built-in functions with a non-standard name is deprecated since Scssphp 1.8.0 and will not work anymore in 2.0 (they will be treated as CSS function calls instead).\nUse \"$originalName\" instead of \"$name\"."; + @trigger_error($warning, E_USER_DEPRECATED); + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + Warn::deprecation("$warning\n on line $line of $fname"); + + // Use the actual function definition + $prototype = isset(static::$$actualLibName) ? static::$$actualLibName : null; + $f[1] = $libName = $actualLibName; + } + } + + if (\get_class($this) !== __CLASS__ && !isset($this->warnedChildFunctions[$libName])) { + $r = new \ReflectionMethod($this, $libName); + $declaringClass = $r->getDeclaringClass()->name; + + $needsWarning = $this->warnedChildFunctions[$libName] = $declaringClass !== __CLASS__; + + if ($needsWarning) { + if (method_exists(__CLASS__, $libName)) { + @trigger_error(sprintf('Overriding the "%s" core function by extending the Compiler is deprecated and will be unsupported in 2.0. Remove the "%s::%s" method.', $normalizedName, $declaringClass, $libName), E_USER_DEPRECATED); + } else { + @trigger_error(sprintf('Registering custom functions by extending the Compiler and using the lib* discovery mechanism is deprecated and will be removed in 2.0. Replace the "%s::%s" method with registering the "%s" function through "Compiler::registerFunction".', $declaringClass, $libName, $normalizedName), E_USER_DEPRECATED); + } + } + } + + return [Type::T_FUNCTION_REFERENCE, 'native', $name, $f, $prototype]; + } + + return static::$null; + } + + + /** + * Normalize name + * + * @param string $name + * + * @return string + */ + protected function normalizeName($name) + { + return str_replace('-', '_', $name); + } + + /** + * Normalize value + * + * @internal + * + * @param array|Number $value + * + * @return array|Number + */ + public function normalizeValue($value) + { + $value = $this->coerceForExpression($this->reduce($value)); + + if ($value instanceof Number) { + return $value; + } + + switch ($value[0]) { + case Type::T_LIST: + $value = $this->extractInterpolation($value); + + if ($value[0] !== Type::T_LIST) { + return [Type::T_KEYWORD, $this->compileValue($value)]; + } + + foreach ($value[2] as $key => $item) { + $value[2][$key] = $this->normalizeValue($item); + } + + if (! empty($value['enclosing'])) { + unset($value['enclosing']); + } + + if ($value[1] === '' && count($value[2]) > 1) { + $value[1] = ' '; + } + + return $value; + + case Type::T_STRING: + return [$value[0], '"', [$this->compileStringContent($value)]]; + + case Type::T_INTERPOLATE: + return [Type::T_KEYWORD, $this->compileValue($value)]; + + default: + return $value; + } + } + + /** + * Add numbers + * + * @param Number $left + * @param Number $right + * + * @return Number + */ + protected function opAddNumberNumber(Number $left, Number $right) + { + return $left->plus($right); + } + + /** + * Multiply numbers + * + * @param Number $left + * @param Number $right + * + * @return Number + */ + protected function opMulNumberNumber(Number $left, Number $right) + { + return $left->times($right); + } + + /** + * Subtract numbers + * + * @param Number $left + * @param Number $right + * + * @return Number + */ + protected function opSubNumberNumber(Number $left, Number $right) + { + return $left->minus($right); + } + + /** + * Divide numbers + * + * @param Number $left + * @param Number $right + * + * @return Number + */ + protected function opDivNumberNumber(Number $left, Number $right) + { + return $left->dividedBy($right); + } + + /** + * Mod numbers + * + * @param Number $left + * @param Number $right + * + * @return Number + */ + protected function opModNumberNumber(Number $left, Number $right) + { + return $left->modulo($right); + } + + /** + * Add strings + * + * @param array $left + * @param array $right + * + * @return array|null + */ + protected function opAdd($left, $right) + { + if ($strLeft = $this->coerceString($left)) { + if ($right[0] === Type::T_STRING) { + $right[1] = ''; + } + + $strLeft[2][] = $right; + + return $strLeft; + } + + if ($strRight = $this->coerceString($right)) { + if ($left[0] === Type::T_STRING) { + $left[1] = ''; + } + + array_unshift($strRight[2], $left); + + return $strRight; + } + + return null; + } + + /** + * Boolean and + * + * @param array|Number $left + * @param array|Number $right + * @param bool $shouldEval + * + * @return array|Number|null + */ + protected function opAnd($left, $right, $shouldEval) + { + $truthy = ($left === static::$null || $right === static::$null) || + ($left === static::$false || $left === static::$true) && + ($right === static::$false || $right === static::$true); + + if (! $shouldEval) { + if (! $truthy) { + return null; + } + } + + if ($left !== static::$false && $left !== static::$null) { + return $this->reduce($right, true); + } + + return $left; + } + + /** + * Boolean or + * + * @param array|Number $left + * @param array|Number $right + * @param bool $shouldEval + * + * @return array|Number|null + */ + protected function opOr($left, $right, $shouldEval) + { + $truthy = ($left === static::$null || $right === static::$null) || + ($left === static::$false || $left === static::$true) && + ($right === static::$false || $right === static::$true); + + if (! $shouldEval) { + if (! $truthy) { + return null; + } + } + + if ($left !== static::$false && $left !== static::$null) { + return $left; + } + + return $this->reduce($right, true); + } + + /** + * Compare colors + * + * @param string $op + * @param array $left + * @param array $right + * + * @return array + */ + protected function opColorColor($op, $left, $right) + { + if ($op !== '==' && $op !== '!=') { + $warning = "Color arithmetic is deprecated and will be an error in future versions.\n" + . "Consider using Sass's color functions instead."; + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + + Warn::deprecation("$warning\n on line $line of $fname"); + } + + $out = [Type::T_COLOR]; + + foreach ([1, 2, 3] as $i) { + $lval = isset($left[$i]) ? $left[$i] : 0; + $rval = isset($right[$i]) ? $right[$i] : 0; + + switch ($op) { + case '+': + $out[] = $lval + $rval; + break; + + case '-': + $out[] = $lval - $rval; + break; + + case '*': + $out[] = $lval * $rval; + break; + + case '%': + if ($rval == 0) { + throw $this->error("color: Can't take modulo by zero"); + } + + $out[] = $lval % $rval; + break; + + case '/': + if ($rval == 0) { + throw $this->error("color: Can't divide by zero"); + } + + $out[] = (int) ($lval / $rval); + break; + + case '==': + return $this->opEq($left, $right); + + case '!=': + return $this->opNeq($left, $right); + + default: + throw $this->error("color: unknown op $op"); + } + } + + if (isset($left[4])) { + $out[4] = $left[4]; + } elseif (isset($right[4])) { + $out[4] = $right[4]; + } + + return $this->fixColor($out); + } + + /** + * Compare color and number + * + * @param string $op + * @param array $left + * @param Number $right + * + * @return array + */ + protected function opColorNumber($op, $left, Number $right) + { + if ($op === '==') { + return static::$false; + } + + if ($op === '!=') { + return static::$true; + } + + $value = $right->getDimension(); + + return $this->opColorColor( + $op, + $left, + [Type::T_COLOR, $value, $value, $value] + ); + } + + /** + * Compare number and color + * + * @param string $op + * @param Number $left + * @param array $right + * + * @return array + */ + protected function opNumberColor($op, Number $left, $right) + { + if ($op === '==') { + return static::$false; + } + + if ($op === '!=') { + return static::$true; + } + + $value = $left->getDimension(); + + return $this->opColorColor( + $op, + [Type::T_COLOR, $value, $value, $value], + $right + ); + } + + /** + * Compare number1 == number2 + * + * @param array|Number $left + * @param array|Number $right + * + * @return array + */ + protected function opEq($left, $right) + { + if (($lStr = $this->coerceString($left)) && ($rStr = $this->coerceString($right))) { + $lStr[1] = ''; + $rStr[1] = ''; + + $left = $this->compileValue($lStr); + $right = $this->compileValue($rStr); + } + + return $this->toBool($left === $right); + } + + /** + * Compare number1 != number2 + * + * @param array|Number $left + * @param array|Number $right + * + * @return array + */ + protected function opNeq($left, $right) + { + if (($lStr = $this->coerceString($left)) && ($rStr = $this->coerceString($right))) { + $lStr[1] = ''; + $rStr[1] = ''; + + $left = $this->compileValue($lStr); + $right = $this->compileValue($rStr); + } + + return $this->toBool($left !== $right); + } + + /** + * Compare number1 == number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opEqNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->equals($right)); + } + + /** + * Compare number1 != number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opNeqNumberNumber(Number $left, Number $right) + { + return $this->toBool(!$left->equals($right)); + } + + /** + * Compare number1 >= number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opGteNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->greaterThanOrEqual($right)); + } + + /** + * Compare number1 > number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opGtNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->greaterThan($right)); + } + + /** + * Compare number1 <= number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opLteNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->lessThanOrEqual($right)); + } + + /** + * Compare number1 < number2 + * + * @param Number $left + * @param Number $right + * + * @return array + */ + protected function opLtNumberNumber(Number $left, Number $right) + { + return $this->toBool($left->lessThan($right)); + } + + /** + * Cast to boolean + * + * @api + * + * @param bool $thing + * + * @return array + */ + public function toBool($thing) + { + return $thing ? static::$true : static::$false; + } + + /** + * Escape non printable chars in strings output as in dart-sass + * + * @internal + * + * @param string $string + * @param bool $inKeyword + * + * @return string + */ + public function escapeNonPrintableChars($string, $inKeyword = false) + { + static $replacement = []; + if (empty($replacement[$inKeyword])) { + for ($i = 0; $i < 32; $i++) { + if ($i !== 9 || $inKeyword) { + $replacement[$inKeyword][chr($i)] = '\\' . dechex($i) . ($inKeyword ? ' ' : chr(0)); + } + } + } + $string = str_replace(array_keys($replacement[$inKeyword]), array_values($replacement[$inKeyword]), $string); + // chr(0) is not a possible char from the input, so any chr(0) comes from our escaping replacement + if (strpos($string, chr(0)) !== false) { + if (substr($string, -1) === chr(0)) { + $string = substr($string, 0, -1); + } + $string = str_replace( + [chr(0) . '\\',chr(0) . ' '], + [ '\\', ' '], + $string + ); + if (strpos($string, chr(0)) !== false) { + $parts = explode(chr(0), $string); + $string = array_shift($parts); + while (count($parts)) { + $next = array_shift($parts); + if (strpos("0123456789abcdefABCDEF" . chr(9), $next[0]) !== false) { + $string .= " "; + } + $string .= $next; + } + } + } + + return $string; + } + + /** + * Compiles a primitive value into a CSS property value. + * + * Values in scssphp are typed by being wrapped in arrays, their format is + * typically: + * + * array(type, contents [, additional_contents]*) + * + * The input is expected to be reduced. This function will not work on + * things like expressions and variables. + * + * @api + * + * @param array|Number $value + * @param bool $quote + * + * @return string + */ + public function compileValue($value, $quote = true) + { + $value = $this->reduce($value); + + if ($value instanceof Number) { + return $value->output($this); + } + + switch ($value[0]) { + case Type::T_KEYWORD: + return $this->escapeNonPrintableChars($value[1], true); + + case Type::T_COLOR: + // [1] - red component (either number for a %) + // [2] - green component + // [3] - blue component + // [4] - optional alpha component + list(, $r, $g, $b) = $value; + + $r = $this->compileRGBAValue($r); + $g = $this->compileRGBAValue($g); + $b = $this->compileRGBAValue($b); + + if (\count($value) === 5) { + $alpha = $this->compileRGBAValue($value[4], true); + + if (! is_numeric($alpha) || $alpha < 1) { + $colorName = Colors::RGBaToColorName($r, $g, $b, $alpha); + + if (! \is_null($colorName)) { + return $colorName; + } + + if (\is_int($alpha) || \is_float($alpha)) { + $a = new Number($alpha, ''); + } elseif (is_numeric($alpha)) { + $a = new Number((float) $alpha, ''); + } else { + $a = $alpha; + } + + return 'rgba(' . $r . ', ' . $g . ', ' . $b . ', ' . $a . ')'; + } + } + + if (! is_numeric($r) || ! is_numeric($g) || ! is_numeric($b)) { + return 'rgb(' . $r . ', ' . $g . ', ' . $b . ')'; + } + + $colorName = Colors::RGBaToColorName($r, $g, $b); + + if (! \is_null($colorName)) { + return $colorName; + } + + $h = sprintf('#%02x%02x%02x', $r, $g, $b); + + // Converting hex color to short notation (e.g. #003399 to #039) + if ($h[1] === $h[2] && $h[3] === $h[4] && $h[5] === $h[6]) { + $h = '#' . $h[1] . $h[3] . $h[5]; + } + + return $h; + + case Type::T_STRING: + $content = $this->compileStringContent($value, $quote); + + if ($value[1] && $quote) { + $content = str_replace('\\', '\\\\', $content); + + $content = $this->escapeNonPrintableChars($content); + + // force double quote as string quote for the output in certain cases + if ( + $value[1] === "'" && + (strpos($content, '"') === false or strpos($content, "'") !== false) + ) { + $value[1] = '"'; + } elseif ( + $value[1] === '"' && + (strpos($content, '"') !== false and strpos($content, "'") === false) + ) { + $value[1] = "'"; + } + + $content = str_replace($value[1], '\\' . $value[1], $content); + } + + return $value[1] . $content . $value[1]; + + case Type::T_FUNCTION: + $args = ! empty($value[2]) ? $this->compileValue($value[2], $quote) : ''; + + return "$value[1]($args)"; + + case Type::T_FUNCTION_REFERENCE: + $name = ! empty($value[2]) ? $value[2] : ''; + + return "get-function(\"$name\")"; + + case Type::T_LIST: + $value = $this->extractInterpolation($value); + + if ($value[0] !== Type::T_LIST) { + return $this->compileValue($value, $quote); + } + + list(, $delim, $items) = $value; + $pre = $post = ''; + + if (! empty($value['enclosing'])) { + switch ($value['enclosing']) { + case 'parent': + //$pre = '('; + //$post = ')'; + break; + case 'forced_parent': + $pre = '('; + $post = ')'; + break; + case 'bracket': + case 'forced_bracket': + $pre = '['; + $post = ']'; + break; + } + } + + $separator = $delim === '/' ? ' /' : $delim; + + $prefix_value = ''; + + if ($delim !== ' ') { + $prefix_value = ' '; + } + + $filtered = []; + + $same_string_quote = null; + foreach ($items as $item) { + if (\is_null($same_string_quote)) { + $same_string_quote = false; + if ($item[0] === Type::T_STRING) { + $same_string_quote = $item[1]; + foreach ($items as $ii) { + if ($ii[0] !== Type::T_STRING) { + $same_string_quote = false; + break; + } + } + } + } + if ($item[0] === Type::T_NULL) { + continue; + } + if ($same_string_quote === '"' && $item[0] === Type::T_STRING && $item[1]) { + $item[1] = $same_string_quote; + } + + $compiled = $this->compileValue($item, $quote); + + if ($prefix_value && \strlen($compiled)) { + $compiled = $prefix_value . $compiled; + } + + $filtered[] = $compiled; + } + + return $pre . substr(implode($separator, $filtered), \strlen($prefix_value)) . $post; + + case Type::T_MAP: + $keys = $value[1]; + $values = $value[2]; + $filtered = []; + + for ($i = 0, $s = \count($keys); $i < $s; $i++) { + $filtered[$this->compileValue($keys[$i], $quote)] = $this->compileValue($values[$i], $quote); + } + + array_walk($filtered, function (&$value, $key) { + $value = $key . ': ' . $value; + }); + + return '(' . implode(', ', $filtered) . ')'; + + case Type::T_INTERPOLATED: + // node created by extractInterpolation + list(, $interpolate, $left, $right) = $value; + list(,, $whiteLeft, $whiteRight) = $interpolate; + + $delim = $left[1]; + + if ($delim && $delim !== ' ' && ! $whiteLeft) { + $delim .= ' '; + } + + $left = \count($left[2]) > 0 + ? $this->compileValue($left, $quote) . $delim . $whiteLeft + : ''; + + $delim = $right[1]; + + if ($delim && $delim !== ' ') { + $delim .= ' '; + } + + $right = \count($right[2]) > 0 ? + $whiteRight . $delim . $this->compileValue($right, $quote) : ''; + + return $left . $this->compileValue($interpolate, $quote) . $right; + + case Type::T_INTERPOLATE: + // strip quotes if it's a string + $reduced = $this->reduce($value[1]); + + if ($reduced instanceof Number) { + return $this->compileValue($reduced, $quote); + } + + switch ($reduced[0]) { + case Type::T_LIST: + $reduced = $this->extractInterpolation($reduced); + + if ($reduced[0] !== Type::T_LIST) { + break; + } + + list(, $delim, $items) = $reduced; + + if ($delim !== ' ') { + $delim .= ' '; + } + + $filtered = []; + + foreach ($items as $item) { + if ($item[0] === Type::T_NULL) { + continue; + } + + if ($item[0] === Type::T_STRING) { + $filtered[] = $this->compileStringContent($item, $quote); + } elseif ($item[0] === Type::T_KEYWORD) { + $filtered[] = $item[1]; + } else { + $filtered[] = $this->compileValue($item, $quote); + } + } + + $reduced = [Type::T_KEYWORD, implode("$delim", $filtered)]; + break; + + case Type::T_STRING: + $reduced = [Type::T_STRING, '', [$this->compileStringContent($reduced)]]; + break; + + case Type::T_NULL: + $reduced = [Type::T_KEYWORD, '']; + } + + return $this->compileValue($reduced, $quote); + + case Type::T_NULL: + return 'null'; + + case Type::T_COMMENT: + return $this->compileCommentValue($value); + + default: + throw $this->error('unknown value type: ' . json_encode($value)); + } + } + + /** + * @param array|Number $value + * + * @return string + */ + protected function compileDebugValue($value) + { + $value = $this->reduce($value, true); + + if ($value instanceof Number) { + return $this->compileValue($value); + } + + switch ($value[0]) { + case Type::T_STRING: + return $this->compileStringContent($value); + + default: + return $this->compileValue($value); + } + } + + /** + * Flatten list + * + * @param array $list + * + * @return string + * + * @deprecated + */ + protected function flattenList($list) + { + @trigger_error(sprintf('The "%s" method is deprecated.', __METHOD__), E_USER_DEPRECATED); + + return $this->compileValue($list); + } + + /** + * Gets the text of a Sass string + * + * Calling this method on anything else than a SassString is unsupported. Use {@see assertString} first + * to ensure that the value is indeed a string. + * + * @param array $value + * + * @return string + */ + public function getStringText(array $value) + { + if ($value[0] !== Type::T_STRING) { + throw new \InvalidArgumentException('The argument is not a sass string. Did you forgot to use "assertString"?'); + } + + return $this->compileStringContent($value); + } + + /** + * Compile string content + * + * @param array $string + * @param bool $quote + * + * @return string + */ + protected function compileStringContent($string, $quote = true) + { + $parts = []; + + foreach ($string[2] as $part) { + if (\is_array($part) || $part instanceof Number) { + $parts[] = $this->compileValue($part, $quote); + } else { + $parts[] = $part; + } + } + + return implode($parts); + } + + /** + * Extract interpolation; it doesn't need to be recursive, compileValue will handle that + * + * @param array $list + * + * @return array + */ + protected function extractInterpolation($list) + { + $items = $list[2]; + + foreach ($items as $i => $item) { + if ($item[0] === Type::T_INTERPOLATE) { + $before = [Type::T_LIST, $list[1], \array_slice($items, 0, $i)]; + $after = [Type::T_LIST, $list[1], \array_slice($items, $i + 1)]; + + return [Type::T_INTERPOLATED, $item, $before, $after]; + } + } + + return $list; + } + + /** + * Find the final set of selectors + * + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param \ScssPhp\ScssPhp\Block $selfParent + * + * @return array + */ + protected function multiplySelectors(Environment $env, $selfParent = null) + { + $envs = $this->compactEnv($env); + $selectors = []; + $parentSelectors = [[]]; + + $selfParentSelectors = null; + + if (! \is_null($selfParent) && $selfParent->selectors) { + $selfParentSelectors = $this->evalSelectors($selfParent->selectors); + } + + while ($env = array_pop($envs)) { + if (empty($env->selectors)) { + continue; + } + + $selectors = $env->selectors; + + do { + $stillHasSelf = false; + $prevSelectors = $selectors; + $selectors = []; + + foreach ($parentSelectors as $parent) { + foreach ($prevSelectors as $selector) { + if ($selfParentSelectors) { + foreach ($selfParentSelectors as $selfParent) { + // if no '&' in the selector, each call will give same result, only add once + $s = $this->joinSelectors($parent, $selector, $stillHasSelf, $selfParent); + $selectors[serialize($s)] = $s; + } + } else { + $s = $this->joinSelectors($parent, $selector, $stillHasSelf); + $selectors[serialize($s)] = $s; + } + } + } + } while ($stillHasSelf); + + $parentSelectors = $selectors; + } + + $selectors = array_values($selectors); + + // case we are just starting a at-root : nothing to multiply but parentSelectors + if (! $selectors && $selfParentSelectors) { + $selectors = $selfParentSelectors; + } + + return $selectors; + } + + /** + * Join selectors; looks for & to replace, or append parent before child + * + * @param array $parent + * @param array $child + * @param bool $stillHasSelf + * @param array $selfParentSelectors + + * @return array + */ + protected function joinSelectors($parent, $child, &$stillHasSelf, $selfParentSelectors = null) + { + $setSelf = false; + $out = []; + + foreach ($child as $part) { + $newPart = []; + + foreach ($part as $p) { + // only replace & once and should be recalled to be able to make combinations + if ($p === static::$selfSelector && $setSelf) { + $stillHasSelf = true; + } + + if ($p === static::$selfSelector && ! $setSelf) { + $setSelf = true; + + if (\is_null($selfParentSelectors)) { + $selfParentSelectors = $parent; + } + + foreach ($selfParentSelectors as $i => $parentPart) { + if ($i > 0) { + $out[] = $newPart; + $newPart = []; + } + + foreach ($parentPart as $pp) { + if (\is_array($pp)) { + $flatten = []; + + array_walk_recursive($pp, function ($a) use (&$flatten) { + $flatten[] = $a; + }); + + $pp = implode($flatten); + } + + $newPart[] = $pp; + } + } + } else { + $newPart[] = $p; + } + } + + $out[] = $newPart; + } + + return $setSelf ? $out : array_merge($parent, $child); + } + + /** + * Multiply media + * + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param array $childQueries + * + * @return array + */ + protected function multiplyMedia(Environment $env = null, $childQueries = null) + { + if ( + ! isset($env) || + ! empty($env->block->type) && $env->block->type !== Type::T_MEDIA + ) { + return $childQueries; + } + + // plain old block, skip + if (empty($env->block->type)) { + return $this->multiplyMedia($env->parent, $childQueries); + } + + assert($env->block instanceof MediaBlock); + + $parentQueries = isset($env->block->queryList) + ? $env->block->queryList + : [[[Type::T_MEDIA_VALUE, $env->block->value]]]; + + $store = [$this->env, $this->storeEnv]; + + $this->env = $env; + $this->storeEnv = null; + $parentQueries = $this->evaluateMediaQuery($parentQueries); + + list($this->env, $this->storeEnv) = $store; + + if (\is_null($childQueries)) { + $childQueries = $parentQueries; + } else { + $originalQueries = $childQueries; + $childQueries = []; + + foreach ($parentQueries as $parentQuery) { + foreach ($originalQueries as $childQuery) { + $childQueries[] = array_merge( + $parentQuery, + [[Type::T_MEDIA_TYPE, [Type::T_KEYWORD, 'all']]], + $childQuery + ); + } + } + } + + return $this->multiplyMedia($env->parent, $childQueries); + } + + /** + * Convert env linked list to stack + * + * @param Environment $env + * + * @return Environment[] + * + * @phpstan-return non-empty-array + */ + protected function compactEnv(Environment $env) + { + for ($envs = []; $env; $env = $env->parent) { + $envs[] = $env; + } + + return $envs; + } + + /** + * Convert env stack to singly linked list + * + * @param Environment[] $envs + * + * @return Environment + * + * @phpstan-param non-empty-array $envs + */ + protected function extractEnv($envs) + { + for ($env = null; $e = array_pop($envs);) { + $e->parent = $env; + $env = $e; + } + + return $env; + } + + /** + * Push environment + * + * @param \ScssPhp\ScssPhp\Block $block + * + * @return \ScssPhp\ScssPhp\Compiler\Environment + */ + protected function pushEnv(Block $block = null) + { + $env = new Environment(); + $env->parent = $this->env; + $env->parentStore = $this->storeEnv; + $env->store = []; + $env->block = $block; + $env->depth = isset($this->env->depth) ? $this->env->depth + 1 : 0; + + $this->env = $env; + $this->storeEnv = null; + + return $env; + } + + /** + * Pop environment + * + * @return void + */ + protected function popEnv() + { + $this->storeEnv = $this->env->parentStore; + $this->env = $this->env->parent; + } + + /** + * Propagate vars from a just poped Env (used in @each and @for) + * + * @param array $store + * @param null|string[] $excludedVars + * + * @return void + */ + protected function backPropagateEnv($store, $excludedVars = null) + { + foreach ($store as $key => $value) { + if (empty($excludedVars) || ! \in_array($key, $excludedVars)) { + $this->set($key, $value, true); + } + } + } + + /** + * Get store environment + * + * @return \ScssPhp\ScssPhp\Compiler\Environment + */ + protected function getStoreEnv() + { + return isset($this->storeEnv) ? $this->storeEnv : $this->env; + } + + /** + * Set variable + * + * @param string $name + * @param mixed $value + * @param bool $shadow + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param mixed $valueUnreduced + * + * @return void + */ + protected function set($name, $value, $shadow = false, Environment $env = null, $valueUnreduced = null) + { + $name = $this->normalizeName($name); + + if (! isset($env)) { + $env = $this->getStoreEnv(); + } + + if ($shadow) { + $this->setRaw($name, $value, $env, $valueUnreduced); + } else { + $this->setExisting($name, $value, $env, $valueUnreduced); + } + } + + /** + * Set existing variable + * + * @param string $name + * @param mixed $value + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param mixed $valueUnreduced + * + * @return void + */ + protected function setExisting($name, $value, Environment $env, $valueUnreduced = null) + { + $storeEnv = $env; + $specialContentKey = static::$namespaces['special'] . 'content'; + + $hasNamespace = $name[0] === '^' || $name[0] === '@' || $name[0] === '%'; + + $maxDepth = 10000; + + for (;;) { + if ($maxDepth-- <= 0) { + break; + } + + if (\array_key_exists($name, $env->store)) { + break; + } + + if (! $hasNamespace && isset($env->marker)) { + if (! empty($env->store[$specialContentKey])) { + $env = $env->store[$specialContentKey]->scope; + continue; + } + + if (! empty($env->declarationScopeParent)) { + $env = $env->declarationScopeParent; + continue; + } else { + $env = $storeEnv; + break; + } + } + + if (isset($env->parentStore)) { + $env = $env->parentStore; + } elseif (isset($env->parent)) { + $env = $env->parent; + } else { + $env = $storeEnv; + break; + } + } + + $env->store[$name] = $value; + + if ($valueUnreduced) { + $env->storeUnreduced[$name] = $valueUnreduced; + } + } + + /** + * Set raw variable + * + * @param string $name + * @param mixed $value + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param mixed $valueUnreduced + * + * @return void + */ + protected function setRaw($name, $value, Environment $env, $valueUnreduced = null) + { + $env->store[$name] = $value; + + if ($valueUnreduced) { + $env->storeUnreduced[$name] = $valueUnreduced; + } + } + + /** + * Get variable + * + * @internal + * + * @param string $name + * @param bool $shouldThrow + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * @param bool $unreduced + * + * @return mixed|null + */ + public function get($name, $shouldThrow = true, Environment $env = null, $unreduced = false) + { + $normalizedName = $this->normalizeName($name); + $specialContentKey = static::$namespaces['special'] . 'content'; + + if (! isset($env)) { + $env = $this->getStoreEnv(); + } + + $hasNamespace = $normalizedName[0] === '^' || $normalizedName[0] === '@' || $normalizedName[0] === '%'; + + $maxDepth = 10000; + + for (;;) { + if ($maxDepth-- <= 0) { + break; + } + + if (\array_key_exists($normalizedName, $env->store)) { + if ($unreduced && isset($env->storeUnreduced[$normalizedName])) { + return $env->storeUnreduced[$normalizedName]; + } + + return $env->store[$normalizedName]; + } + + if (! $hasNamespace && isset($env->marker)) { + if (! empty($env->store[$specialContentKey])) { + $env = $env->store[$specialContentKey]->scope; + continue; + } + + if (! empty($env->declarationScopeParent)) { + $env = $env->declarationScopeParent; + } else { + $env = $this->rootEnv; + } + continue; + } + + if (isset($env->parentStore)) { + $env = $env->parentStore; + } elseif (isset($env->parent)) { + $env = $env->parent; + } else { + break; + } + } + + if ($shouldThrow) { + throw $this->error("Undefined variable \$$name" . ($maxDepth <= 0 ? ' (infinite recursion)' : '')); + } + + // found nothing + return null; + } + + /** + * Has variable? + * + * @param string $name + * @param \ScssPhp\ScssPhp\Compiler\Environment $env + * + * @return bool + */ + protected function has($name, Environment $env = null) + { + return ! \is_null($this->get($name, false, $env)); + } + + /** + * Inject variables + * + * @param array $args + * + * @return void + */ + protected function injectVariables(array $args) + { + if (empty($args)) { + return; + } + + $parser = $this->parserFactory(__METHOD__); + + foreach ($args as $name => $strValue) { + if ($name[0] === '$') { + $name = substr($name, 1); + } + + if (!\is_string($strValue) || ! $parser->parseValue($strValue, $value)) { + $value = $this->coerceValue($strValue); + } + + $this->set($name, $value); + } + } + + /** + * Replaces variables. + * + * @param array $variables + * + * @return void + */ + public function replaceVariables(array $variables) + { + $this->registeredVars = []; + $this->addVariables($variables); + } + + /** + * Replaces variables. + * + * @param array $variables + * + * @return void + */ + public function addVariables(array $variables) + { + $triggerWarning = false; + + foreach ($variables as $name => $value) { + if (!$value instanceof Number && !\is_array($value)) { + $triggerWarning = true; + } + + $this->registeredVars[$name] = $value; + } + + if ($triggerWarning) { + @trigger_error('Passing raw values to as custom variables to the Compiler is deprecated. Use "\ScssPhp\ScssPhp\ValueConverter::parseValue" or "\ScssPhp\ScssPhp\ValueConverter::fromPhp" to convert them instead.', E_USER_DEPRECATED); + } + } + + /** + * Set variables + * + * @api + * + * @param array $variables + * + * @return void + * + * @deprecated Use "addVariables" or "replaceVariables" instead. + */ + public function setVariables(array $variables) + { + @trigger_error('The method "setVariables" of the Compiler is deprecated. Use the "addVariables" method for the equivalent behavior or "replaceVariables" if merging with previous variables was not desired.'); + + $this->addVariables($variables); + } + + /** + * Unset variable + * + * @api + * + * @param string $name + * + * @return void + */ + public function unsetVariable($name) + { + unset($this->registeredVars[$name]); + } + + /** + * Returns list of variables + * + * @api + * + * @return array + */ + public function getVariables() + { + return $this->registeredVars; + } + + /** + * Adds to list of parsed files + * + * @internal + * + * @param string|null $path + * + * @return void + */ + public function addParsedFile($path) + { + if (! \is_null($path) && is_file($path)) { + $this->parsedFiles[realpath($path)] = filemtime($path); + } + } + + /** + * Returns list of parsed files + * + * @deprecated + * @return array + */ + public function getParsedFiles() + { + @trigger_error('The method "getParsedFiles" of the Compiler is deprecated. Use the "getIncludedFiles" method on the CompilationResult instance returned by compileString() instead. Be careful that the signature of the method is different.', E_USER_DEPRECATED); + return $this->parsedFiles; + } + + /** + * Add import path + * + * @api + * + * @param string|callable $path + * + * @return void + */ + public function addImportPath($path) + { + if (! \in_array($path, $this->importPaths)) { + $this->importPaths[] = $path; + } + } + + /** + * Set import paths + * + * @api + * + * @param string|array $path + * + * @return void + */ + public function setImportPaths($path) + { + $paths = (array) $path; + $actualImportPaths = array_filter($paths, function ($path) { + return $path !== ''; + }); + + $this->legacyCwdImportPath = \count($actualImportPaths) !== \count($paths); + + if ($this->legacyCwdImportPath) { + @trigger_error('Passing an empty string in the import paths to refer to the current working directory is deprecated. If that\'s the intended behavior, the value of "getcwd()" should be used directly instead. If this was used for resolving relative imports of the input alongside "chdir" with the source directory, the path of the input file should be passed to "compileString()" instead.', E_USER_DEPRECATED); + } + + $this->importPaths = $actualImportPaths; + } + + /** + * Set number precision + * + * @api + * + * @param int $numberPrecision + * + * @return void + * + * @deprecated The number precision is not configurable anymore. The default is enough for all browsers. + */ + public function setNumberPrecision($numberPrecision) + { + @trigger_error('The number precision is not configurable anymore. ' + . 'The default is enough for all browsers.', E_USER_DEPRECATED); + } + + /** + * Sets the output style. + * + * @api + * + * @param string $style One of the OutputStyle constants + * + * @return void + * + * @phpstan-param OutputStyle::* $style + */ + public function setOutputStyle($style) + { + switch ($style) { + case OutputStyle::EXPANDED: + $this->configuredFormatter = Expanded::class; + break; + + case OutputStyle::COMPRESSED: + $this->configuredFormatter = Compressed::class; + break; + + default: + throw new \InvalidArgumentException(sprintf('Invalid output style "%s".', $style)); + } + } + + /** + * Set formatter + * + * @api + * + * @param string $formatterName + * + * @return void + * + * @deprecated Use {@see setOutputStyle} instead. + * + * @phpstan-param class-string $formatterName + */ + public function setFormatter($formatterName) + { + if (!\in_array($formatterName, [Expanded::class, Compressed::class], true)) { + @trigger_error('Formatters other than Expanded and Compressed are deprecated.', E_USER_DEPRECATED); + } + @trigger_error('The method "setFormatter" is deprecated. Use "setOutputStyle" instead.', E_USER_DEPRECATED); + + $this->configuredFormatter = $formatterName; + } + + /** + * Set line number style + * + * @api + * + * @param string $lineNumberStyle + * + * @return void + * + * @deprecated The line number output is not supported anymore. Use source maps instead. + */ + public function setLineNumberStyle($lineNumberStyle) + { + @trigger_error('The line number output is not supported anymore. ' + . 'Use source maps instead.', E_USER_DEPRECATED); + } + + /** + * Configures the handling of non-ASCII outputs. + * + * If $charset is `true`, this will include a `@charset` declaration or a + * UTF-8 [byte-order mark][] if the stylesheet contains any non-ASCII + * characters. Otherwise, it will never include a `@charset` declaration or a + * byte-order mark. + * + * [byte-order mark]: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8 + * + * @param bool $charset + * + * @return void + */ + public function setCharset($charset) + { + $this->charset = $charset; + } + + /** + * Enable/disable source maps + * + * @api + * + * @param int $sourceMap + * + * @return void + * + * @phpstan-param self::SOURCE_MAP_* $sourceMap + */ + public function setSourceMap($sourceMap) + { + $this->sourceMap = $sourceMap; + } + + /** + * Set source map options + * + * @api + * + * @param array $sourceMapOptions + * + * @phpstan-param array{sourceRoot?: string, sourceMapFilename?: string|null, sourceMapURL?: string|null, sourceMapWriteTo?: string|null, outputSourceFiles?: bool, sourceMapRootpath?: string, sourceMapBasepath?: string} $sourceMapOptions + * + * @return void + */ + public function setSourceMapOptions($sourceMapOptions) + { + $this->sourceMapOptions = $sourceMapOptions; + } + + /** + * Register function + * + * @api + * + * @param string $name + * @param callable $callback + * @param string[]|null $argumentDeclaration + * + * @return void + */ + public function registerFunction($name, $callback, $argumentDeclaration = null) + { + if (self::isNativeFunction($name)) { + @trigger_error(sprintf('The "%s" function is a core sass function. Overriding it with a custom implementation through "%s" is deprecated and won\'t be supported in ScssPhp 2.0 anymore.', $name, __METHOD__), E_USER_DEPRECATED); + } + + if ($argumentDeclaration === null) { + @trigger_error('Omitting the argument declaration when registering custom function is deprecated and won\'t be supported in ScssPhp 2.0 anymore.', E_USER_DEPRECATED); + } + + if ($this->reflectCallable($callback)->getNumberOfRequiredParameters() > 1) { + @trigger_error('The second argument passed to the callback of custom functions is deprecated and won\'t be supported in ScssPhp 2.0 anymore. Register a callback accepting only 1 parameter instead.', E_USER_DEPRECATED); + } + + $this->userFunctions[$this->normalizeName($name)] = [$callback, $argumentDeclaration]; + } + + /** + * @return \ReflectionFunctionAbstract + */ + private function reflectCallable(callable $c) + { + if (\is_object($c) && !$c instanceof \Closure) { + $c = [$c, '__invoke']; + } + + if (\is_string($c) && false !== strpos($c, '::')) { + $c = explode('::', $c, 2); + } + + if (\is_array($c)) { + return new \ReflectionMethod($c[0], $c[1]); + } + + \assert(\is_string($c) || $c instanceof \Closure); + + return new \ReflectionFunction($c); + } + + /** + * Unregister function + * + * @api + * + * @param string $name + * + * @return void + */ + public function unregisterFunction($name) + { + unset($this->userFunctions[$this->normalizeName($name)]); + } + + /** + * Add feature + * + * @api + * + * @param string $name + * + * @return void + * + * @deprecated Registering additional features is deprecated. + */ + public function addFeature($name) + { + @trigger_error('Registering additional features is deprecated.', E_USER_DEPRECATED); + + $this->registeredFeatures[$name] = true; + } + + /** + * Import file + * + * @param string $path + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $out + * + * @return void + */ + protected function importFile($path, OutputBlock $out) + { + $this->pushCallStack('import ' . $this->getPrettyPath($path)); + // see if tree is cached + $realPath = realpath($path); + + if ($realPath === false) { + $realPath = $path; + } + + if (substr($path, -5) === '.sass') { + $this->sourceIndex = \count($this->sourceNames); + $this->sourceNames[] = $path; + $this->sourceLine = 1; + $this->sourceColumn = 1; + + throw $this->error('The Sass indented syntax is not implemented.'); + } + + if (isset($this->importCache[$realPath])) { + $this->handleImportLoop($realPath); + + $tree = $this->importCache[$realPath]; + } else { + $code = file_get_contents($path); + $parser = $this->parserFactory($path); + $tree = $parser->parse($code); + + $this->importCache[$realPath] = $tree; + } + + $currentDirectory = $this->currentDirectory; + $this->currentDirectory = dirname($path); + + $this->compileChildrenNoReturn($tree->children, $out); + $this->currentDirectory = $currentDirectory; + $this->popCallStack(); + } + + /** + * Save the imported files with their resolving path context + * + * @param string|null $currentDirectory + * @param string $path + * @param string $filePath + * + * @return void + */ + private function registerImport($currentDirectory, $path, $filePath) + { + $this->resolvedImports[] = ['currentDir' => $currentDirectory, 'path' => $path, 'filePath' => $filePath]; + } + + /** + * Detects whether the import is a CSS import. + * + * For legacy reasons, custom importers are called for those, allowing them + * to replace them with an actual Sass import. However this behavior is + * deprecated. Custom importers are expected to return null when they receive + * a CSS import. + * + * @param string $url + * + * @return bool + */ + public static function isCssImport($url) + { + return 1 === preg_match('~\.css$|^https?://|^//~', $url); + } + + /** + * Return the file path for an import url if it exists + * + * @internal + * + * @param string $url + * @param string|null $currentDir + * + * @return string|null + */ + public function findImport($url, $currentDir = null) + { + // Vanilla css and external requests. These are not meant to be Sass imports. + // Callback importers are still called for BC. + if (self::isCssImport($url)) { + foreach ($this->importPaths as $dir) { + if (\is_string($dir)) { + continue; + } + + if (\is_callable($dir)) { + // check custom callback for import path + $file = \call_user_func($dir, $url); + + if (! \is_null($file)) { + if (\is_array($dir)) { + $callableDescription = (\is_object($dir[0]) ? \get_class($dir[0]) : $dir[0]) . '::' . $dir[1]; + } elseif ($dir instanceof \Closure) { + $r = new \ReflectionFunction($dir); + if (false !== strpos($r->name, '{closure}')) { + $callableDescription = sprintf('closure{%s:%s}', $r->getFileName(), $r->getStartLine()); + } elseif ($class = $r->getClosureScopeClass()) { + $callableDescription = $class->name . '::' . $r->name; + } else { + $callableDescription = $r->name; + } + } elseif (\is_object($dir)) { + $callableDescription = \get_class($dir) . '::__invoke'; + } else { + $callableDescription = 'callable'; // Fallback if we don't have a dedicated description + } + @trigger_error(sprintf('Returning a file to import for CSS or external references in custom importer callables is deprecated and will not be supported anymore in ScssPhp 2.0. This behavior is not compliant with the Sass specification. Update your "%s" importer.', $callableDescription), E_USER_DEPRECATED); + + return $file; + } + } + } + return null; + } + + if (!\is_null($currentDir)) { + $relativePath = $this->resolveImportPath($url, $currentDir); + + if (!\is_null($relativePath)) { + return $relativePath; + } + } + + foreach ($this->importPaths as $dir) { + if (\is_string($dir)) { + $path = $this->resolveImportPath($url, $dir); + + if (!\is_null($path)) { + return $path; + } + } elseif (\is_callable($dir)) { + // check custom callback for import path + $file = \call_user_func($dir, $url); + + if (! \is_null($file)) { + return $file; + } + } + } + + if ($this->legacyCwdImportPath) { + $path = $this->resolveImportPath($url, getcwd()); + + if (!\is_null($path)) { + @trigger_error('Resolving imports relatively to the current working directory is deprecated. If that\'s the intended behavior, the value of "getcwd()" should be added as an import path explicitly instead. If this was used for resolving relative imports of the input alongside "chdir" with the source directory, the path of the input file should be passed to "compileString()" instead.', E_USER_DEPRECATED); + + return $path; + } + } + + throw $this->error("`$url` file not found for @import"); + } + + /** + * @param string $url + * @param string $baseDir + * + * @return string|null + */ + private function resolveImportPath($url, $baseDir) + { + $path = Path::join($baseDir, $url); + + $hasExtension = preg_match('/.s[ac]ss$/', $url); + + if ($hasExtension) { + return $this->checkImportPathConflicts($this->tryImportPath($path)); + } + + $result = $this->checkImportPathConflicts($this->tryImportPathWithExtensions($path)); + + if (!\is_null($result)) { + return $result; + } + + return $this->tryImportPathAsDirectory($path); + } + + /** + * @param string[] $paths + * + * @return string|null + */ + private function checkImportPathConflicts(array $paths) + { + if (\count($paths) === 0) { + return null; + } + + if (\count($paths) === 1) { + return $paths[0]; + } + + $formattedPrettyPaths = []; + + foreach ($paths as $path) { + $formattedPrettyPaths[] = ' ' . $this->getPrettyPath($path); + } + + throw $this->error("It's not clear which file to import. Found:\n" . implode("\n", $formattedPrettyPaths)); + } + + /** + * @param string $path + * + * @return string[] + */ + private function tryImportPathWithExtensions($path) + { + $result = array_merge( + $this->tryImportPath($path . '.sass'), + $this->tryImportPath($path . '.scss') + ); + + if ($result) { + return $result; + } + + return $this->tryImportPath($path . '.css'); + } + + /** + * @param string $path + * + * @return string[] + */ + private function tryImportPath($path) + { + $partial = dirname($path) . '/_' . basename($path); + + $candidates = []; + + if (is_file($partial)) { + $candidates[] = $partial; + } + + if (is_file($path)) { + $candidates[] = $path; + } + + return $candidates; + } + + /** + * @param string $path + * + * @return string|null + */ + private function tryImportPathAsDirectory($path) + { + if (!is_dir($path)) { + return null; + } + + return $this->checkImportPathConflicts($this->tryImportPathWithExtensions($path . '/index')); + } + + /** + * @param string|null $path + * + * @return string + */ + private function getPrettyPath($path) + { + if ($path === null) { + return '(unknown file)'; + } + + $normalizedPath = $path; + $normalizedRootDirectory = $this->rootDirectory . '/'; + + if (\DIRECTORY_SEPARATOR === '\\') { + $normalizedRootDirectory = str_replace('\\', '/', $normalizedRootDirectory); + $normalizedPath = str_replace('\\', '/', $path); + } + + if (0 === strpos($normalizedPath, $normalizedRootDirectory)) { + return substr($path, \strlen($normalizedRootDirectory)); + } + + return $path; + } + + /** + * Set encoding + * + * @api + * + * @param string|null $encoding + * + * @return void + * + * @deprecated Non-compliant support for other encodings than UTF-8 is deprecated. + */ + public function setEncoding($encoding) + { + if (!$encoding || strtolower($encoding) === 'utf-8') { + @trigger_error(sprintf('The "%s" method is deprecated.', __METHOD__), E_USER_DEPRECATED); + } else { + @trigger_error(sprintf('The "%s" method is deprecated. Parsing will only support UTF-8 in ScssPhp 2.0. The non-UTF-8 parsing of ScssPhp 1.x is not spec compliant.', __METHOD__), E_USER_DEPRECATED); + } + + $this->encoding = $encoding; + } + + /** + * Ignore errors? + * + * @api + * + * @param bool $ignoreErrors + * + * @return \ScssPhp\ScssPhp\Compiler + * + * @deprecated Ignoring Sass errors is not longer supported. + */ + public function setIgnoreErrors($ignoreErrors) + { + @trigger_error('Ignoring Sass errors is not longer supported.', E_USER_DEPRECATED); + + return $this; + } + + /** + * Get source position + * + * @api + * + * @return array + * + * @deprecated + */ + public function getSourcePosition() + { + @trigger_error(sprintf('The "%s" method is deprecated.', __METHOD__), E_USER_DEPRECATED); + + $sourceFile = isset($this->sourceNames[$this->sourceIndex]) ? $this->sourceNames[$this->sourceIndex] : ''; + + return [$sourceFile, $this->sourceLine, $this->sourceColumn]; + } + + /** + * Throw error (exception) + * + * @api + * + * @param string $msg Message with optional sprintf()-style vararg parameters + * + * @return never + * + * @throws \ScssPhp\ScssPhp\Exception\CompilerException + * + * @deprecated use "error" and throw the exception in the caller instead. + */ + public function throwError($msg) + { + @trigger_error( + 'The method "throwError" is deprecated. Use "error" and throw the exception in the caller instead', + E_USER_DEPRECATED + ); + + throw $this->error(...func_get_args()); + } + + /** + * Build an error (exception) + * + * @internal + * + * @param string $msg Message with optional sprintf()-style vararg parameters + * @param bool|float|int|string|null ...$args + * + * @return CompilerException + */ + public function error($msg, ...$args) + { + if ($args) { + $msg = sprintf($msg, ...$args); + } + + if (! $this->ignoreCallStackMessage) { + $msg = $this->addLocationToMessage($msg); + } + + return new CompilerException($msg); + } + + /** + * @param string $msg + * + * @return string + */ + private function addLocationToMessage($msg) + { + $line = $this->sourceLine; + $column = $this->sourceColumn; + + $loc = isset($this->sourceNames[$this->sourceIndex]) + ? $this->getPrettyPath($this->sourceNames[$this->sourceIndex]) . " on line $line, at column $column" + : "line: $line, column: $column"; + + $msg = "$msg: $loc"; + + $callStackMsg = $this->callStackMessage(); + + if ($callStackMsg) { + $msg .= "\nCall Stack:\n" . $callStackMsg; + } + + return $msg; + } + + /** + * @param string $functionName + * @param array $ExpectedArgs + * @param int $nbActual + * @return CompilerException + * + * @deprecated + */ + public function errorArgsNumber($functionName, $ExpectedArgs, $nbActual) + { + @trigger_error(sprintf('The "%s" method is deprecated.', __METHOD__), E_USER_DEPRECATED); + + $nbExpected = \count($ExpectedArgs); + + if ($nbActual > $nbExpected) { + return $this->error( + 'Error: Only %d arguments allowed in %s(), but %d were passed.', + $nbExpected, + $functionName, + $nbActual + ); + } else { + $missing = []; + + while (count($ExpectedArgs) && count($ExpectedArgs) > $nbActual) { + array_unshift($missing, array_pop($ExpectedArgs)); + } + + return $this->error( + 'Error: %s() argument%s %s missing.', + $functionName, + count($missing) > 1 ? 's' : '', + implode(', ', $missing) + ); + } + } + + /** + * Beautify call stack for output + * + * @param bool $all + * @param int|null $limit + * + * @return string + */ + protected function callStackMessage($all = false, $limit = null) + { + $callStackMsg = []; + $ncall = 0; + + if ($this->callStack) { + foreach (array_reverse($this->callStack) as $call) { + if ($all || (isset($call['n']) && $call['n'])) { + $msg = '#' . $ncall++ . ' ' . $call['n'] . ' '; + $msg .= (isset($this->sourceNames[$call[Parser::SOURCE_INDEX]]) + ? $this->getPrettyPath($this->sourceNames[$call[Parser::SOURCE_INDEX]]) + : '(unknown file)'); + $msg .= ' on line ' . $call[Parser::SOURCE_LINE]; + + $callStackMsg[] = $msg; + + if (! \is_null($limit) && $ncall > $limit) { + break; + } + } + } + } + + return implode("\n", $callStackMsg); + } + + /** + * Handle import loop + * + * @param string $name + * + * @return void + * + * @throws \Exception + */ + protected function handleImportLoop($name) + { + for ($env = $this->env; $env; $env = $env->parent) { + if (! $env->block) { + continue; + } + + $file = $this->sourceNames[$env->block->sourceIndex]; + + if ($file === null) { + continue; + } + + if (realpath($file) === $name) { + throw $this->error('An @import loop has been found: %s imports %s', $file, basename($file)); + } + } + } + + /** + * Call SCSS @function + * + * @param CallableBlock|null $func + * @param array $argValues + * + * @return array|Number + */ + protected function callScssFunction($func, $argValues) + { + if (! $func) { + return static::$defaultValue; + } + $name = $func->name; + + $this->pushEnv(); + + // set the args + if (isset($func->args)) { + $this->applyArguments($func->args, $argValues); + } + + // throw away lines and children + $tmp = new OutputBlock(); + $tmp->lines = []; + $tmp->children = []; + + $this->env->marker = 'function'; + + if (! empty($func->parentEnv)) { + $this->env->declarationScopeParent = $func->parentEnv; + } else { + throw $this->error("@function $name() without parentEnv"); + } + + $ret = $this->compileChildren($func->children, $tmp, $this->env->marker . ' ' . $name); + + $this->popEnv(); + + return ! isset($ret) ? static::$defaultValue : $ret; + } + + /** + * Call built-in and registered (PHP) functions + * + * @param string $name + * @param callable $function + * @param array $prototype + * @param array $args + * + * @return array|Number|null + */ + protected function callNativeFunction($name, $function, $prototype, $args) + { + $libName = (is_array($function) ? end($function) : null); + $sorted_kwargs = $this->sortNativeFunctionArgs($libName, $prototype, $args); + + if (\is_null($sorted_kwargs)) { + return null; + } + @list($sorted, $kwargs) = $sorted_kwargs; + + if ($name !== 'if') { + foreach ($sorted as &$val) { + if ($val !== null) { + $val = $this->reduce($val, true); + } + } + } + + $returnValue = \call_user_func($function, $sorted, $kwargs); + + if (! isset($returnValue)) { + return null; + } + + if (\is_array($returnValue) || $returnValue instanceof Number) { + return $returnValue; + } + + @trigger_error(sprintf('Returning a PHP value from the "%s" custom function is deprecated. A sass value must be returned instead.', $name), E_USER_DEPRECATED); + + return $this->coerceValue($returnValue); + } + + /** + * Get built-in function + * + * @param string $name Normalized name + * + * @return array + */ + protected function getBuiltinFunction($name) + { + $libName = self::normalizeNativeFunctionName($name); + return [$this, $libName]; + } + + /** + * Normalize native function name + * + * @internal + * + * @param string $name + * + * @return string + */ + public static function normalizeNativeFunctionName($name) + { + $name = str_replace("-", "_", $name); + $libName = 'lib' . preg_replace_callback( + '/_(.)/', + function ($m) { + return ucfirst($m[1]); + }, + ucfirst($name) + ); + return $libName; + } + + /** + * Check if a function is a native built-in scss function, for css parsing + * + * @internal + * + * @param string $name + * + * @return bool + */ + public static function isNativeFunction($name) + { + return method_exists(Compiler::class, self::normalizeNativeFunctionName($name)); + } + + /** + * Sorts keyword arguments + * + * @param string $functionName + * @param array|null $prototypes + * @param array $args + * + * @return array|null + */ + protected function sortNativeFunctionArgs($functionName, $prototypes, $args) + { + if (! isset($prototypes)) { + $keyArgs = []; + $posArgs = []; + + if (\is_array($args) && \count($args) && \end($args) === static::$null) { + array_pop($args); + } + + // separate positional and keyword arguments + foreach ($args as $arg) { + list($key, $value) = $arg; + + if (empty($key) or empty($key[1])) { + $posArgs[] = empty($arg[2]) ? $value : $arg; + } else { + $keyArgs[$key[1]] = $value; + } + } + + return [$posArgs, $keyArgs]; + } + + // specific cases ? + if (\in_array($functionName, ['libRgb', 'libRgba', 'libHsl', 'libHsla'])) { + // notation 100 127 255 / 0 is in fact a simple list of 4 values + foreach ($args as $k => $arg) { + if (!isset($arg[1])) { + continue; // This happens when using a trailing comma + } + if ($arg[1][0] === Type::T_LIST && \count($arg[1][2]) === 3) { + $args[$k][1][2] = $this->extractSlashAlphaInColorFunction($arg[1][2]); + } + } + } + + list($positionalArgs, $namedArgs, $names, $separator, $hasSplat) = $this->evaluateArguments($args, false); + + if (! \is_array(reset($prototypes))) { + $prototypes = [$prototypes]; + } + + $parsedPrototypes = array_map([$this, 'parseFunctionPrototype'], $prototypes); + assert(!empty($parsedPrototypes)); + $matchedPrototype = $this->selectFunctionPrototype($parsedPrototypes, \count($positionalArgs), $names); + + $this->verifyPrototype($matchedPrototype, \count($positionalArgs), $names, $hasSplat); + + $vars = $this->applyArgumentsToDeclaration($matchedPrototype, $positionalArgs, $namedArgs, $separator); + + $finalArgs = []; + $keyArgs = []; + + foreach ($matchedPrototype['arguments'] as $argument) { + list($normalizedName, $originalName, $default) = $argument; + + if (isset($vars[$normalizedName])) { + $value = $vars[$normalizedName]; + } else { + $value = $default; + } + + // special null value as default: translate to real null here + if ($value === [Type::T_KEYWORD, 'null']) { + $value = null; + } + + $finalArgs[] = $value; + $keyArgs[$originalName] = $value; + } + + if ($matchedPrototype['rest_argument'] !== null) { + $value = $vars[$matchedPrototype['rest_argument']]; + + $finalArgs[] = $value; + $keyArgs[$matchedPrototype['rest_argument']] = $value; + } + + return [$finalArgs, $keyArgs]; + } + + /** + * Parses a function prototype to the internal representation of arguments. + * + * The input is an array of strings describing each argument, as supported + * in {@see registerFunction}. Argument names don't include the `$`. + * The output contains the list of positional argument, with their normalized + * name (underscores are replaced by dashes), their original name (to be used + * in case of error reporting) and their default value. The output also contains + * the normalized name of the rest argument, or null if the function prototype + * is not variadic. + * + * @param string[] $prototype + * + * @return array + * @phpstan-return array{arguments: list, rest_argument: string|null} + */ + private function parseFunctionPrototype(array $prototype) + { + static $parser = null; + + $arguments = []; + $restArgument = null; + + foreach ($prototype as $p) { + if (null !== $restArgument) { + throw new \InvalidArgumentException('The argument declaration is invalid. The rest argument must be the last one.'); + } + + $default = null; + $p = explode(':', $p, 2); + $name = str_replace('_', '-', $p[0]); + + if (isset($p[1])) { + $defaultSource = trim($p[1]); + + if ($defaultSource === 'null') { + // differentiate this null from the static::$null + $default = [Type::T_KEYWORD, 'null']; + } else { + if (\is_null($parser)) { + $parser = $this->parserFactory(__METHOD__); + } + + $parser->parseValue($defaultSource, $default); + } + } + + if (substr($name, -3) === '...') { + $restArgument = substr($name, 0, -3); + } else { + $arguments[] = [$name, $p[0], $default]; + } + } + + return [ + 'arguments' => $arguments, + 'rest_argument' => $restArgument, + ]; + } + + /** + * Returns the function prototype for the given positional and named arguments. + * + * If no exact match is found, finds the closest approximation. Note that this + * doesn't guarantee that $positional and $names are valid for the returned + * prototype. + * + * @param array[] $prototypes + * @param int $positional + * @param array $names A set of names, as both keys and values + * + * @return array + * + * @phpstan-param non-empty-array, rest_argument: string|null}> $prototypes + * @phpstan-return array{arguments: list, rest_argument: string|null} + */ + private function selectFunctionPrototype(array $prototypes, $positional, array $names) + { + $fuzzyMatch = null; + $minMismatchDistance = null; + + foreach ($prototypes as $prototype) { + // Ideally, find an exact match. + if ($this->checkPrototypeMatches($prototype, $positional, $names)) { + return $prototype; + } + + $mismatchDistance = \count($prototype['arguments']) - $positional; + + if ($minMismatchDistance !== null) { + if (abs($mismatchDistance) > abs($minMismatchDistance)) { + continue; + } + + // If two overloads have the same mismatch distance, favor the overload + // that has more arguments. + if (abs($mismatchDistance) === abs($minMismatchDistance) && $mismatchDistance < 0) { + continue; + } + } + + $minMismatchDistance = $mismatchDistance; + $fuzzyMatch = $prototype; + } + + return $fuzzyMatch; + } + + /** + * Checks whether the argument invocation matches the callable prototype. + * + * The rules are similar to {@see verifyPrototype}. The boolean return value + * avoids the overhead of building and catching exceptions when the reason of + * not matching the prototype does not need to be known. + * + * @param array $prototype + * @param int $positional + * @param array $names + * + * @return bool + * + * @phpstan-param array{arguments: list, rest_argument: string|null} $prototype + */ + private function checkPrototypeMatches(array $prototype, $positional, array $names) + { + $nameUsed = 0; + + foreach ($prototype['arguments'] as $i => $argument) { + list ($name, $originalName, $default) = $argument; + + if ($i < $positional) { + if (isset($names[$name])) { + return false; + } + } elseif (isset($names[$name])) { + $nameUsed++; + } elseif ($default === null) { + return false; + } + } + + if ($prototype['rest_argument'] !== null) { + return true; + } + + if ($positional > \count($prototype['arguments'])) { + return false; + } + + if ($nameUsed < \count($names)) { + return false; + } + + return true; + } + + /** + * Verifies that the argument invocation is valid for the callable prototype. + * + * @param array $prototype + * @param int $positional + * @param array $names + * @param bool $hasSplat + * + * @return void + * + * @throws SassScriptException + * + * @phpstan-param array{arguments: list, rest_argument: string|null} $prototype + */ + private function verifyPrototype(array $prototype, $positional, array $names, $hasSplat) + { + $nameUsed = 0; + + foreach ($prototype['arguments'] as $i => $argument) { + list ($name, $originalName, $default) = $argument; + + if ($i < $positional) { + if (isset($names[$name])) { + throw new SassScriptException(sprintf('Argument $%s was passed both by position and by name.', $originalName)); + } + } elseif (isset($names[$name])) { + $nameUsed++; + } elseif ($default === null) { + throw new SassScriptException(sprintf('Missing argument $%s', $originalName)); + } + } + + if ($prototype['rest_argument'] !== null) { + return; + } + + if ($positional > \count($prototype['arguments'])) { + $message = sprintf( + 'Only %d %sargument%s allowed, but %d %s passed.', + \count($prototype['arguments']), + empty($names) ? '' : 'positional ', + \count($prototype['arguments']) === 1 ? '' : 's', + $positional, + $positional === 1 ? 'was' : 'were' + ); + if (!$hasSplat) { + throw new SassScriptException($message); + } + + $message = $this->addLocationToMessage($message); + $message .= "\nThis will be an error in future versions of Sass."; + $this->logger->warn($message, true); + } + + if ($nameUsed < \count($names)) { + $unknownNames = array_values(array_diff($names, array_column($prototype['arguments'], 0))); + $lastName = array_pop($unknownNames); + $message = sprintf( + 'No argument%s named $%s%s.', + $unknownNames ? 's' : '', + $unknownNames ? implode(', $', $unknownNames) . ' or $' : '', + $lastName + ); + throw new SassScriptException($message); + } + } + + /** + * Evaluates the argument from the invocation. + * + * This returns several things about this invocation: + * - the list of positional arguments + * - the map of named arguments, indexed by normalized names + * - the set of names used in the arguments (that's an array using the normalized names as keys for O(1) access) + * - the separator used by the list using the splat operator, if any + * - a boolean indicator whether any splat argument (list or map) was used, to support the incomplete error reporting. + * + * @param array[] $args + * @param bool $reduce Whether arguments should be reduced to their value + * + * @return array + * + * @throws SassScriptException + * + * @phpstan-return array{0: list, 1: array, 2: array, 3: string|null, 4: bool} + */ + private function evaluateArguments(array $args, $reduce = true) + { + // this represents trailing commas + if (\count($args) && end($args) === static::$null) { + array_pop($args); + } + + $splatSeparator = null; + $keywordArgs = []; + $names = []; + $positionalArgs = []; + $hasKeywordArgument = false; + $hasSplat = false; + + foreach ($args as $arg) { + if (!empty($arg[0])) { + $hasKeywordArgument = true; + + assert(\is_string($arg[0][1])); + $name = str_replace('_', '-', $arg[0][1]); + + if (isset($keywordArgs[$name])) { + throw new SassScriptException(sprintf('Duplicate named argument $%s.', $arg[0][1])); + } + + $keywordArgs[$name] = $this->maybeReduce($reduce, $arg[1]); + $names[$name] = $name; + } elseif (! empty($arg[2])) { + // $arg[2] means a var followed by ... in the arg ($list... ) + $val = $this->reduce($arg[1], true); + $hasSplat = true; + + if ($val[0] === Type::T_LIST) { + foreach ($val[2] as $item) { + if (\is_null($splatSeparator)) { + $splatSeparator = $val[1]; + } + + $positionalArgs[] = $this->maybeReduce($reduce, $item); + } + + if (isset($val[3]) && \is_array($val[3])) { + foreach ($val[3] as $name => $item) { + assert(\is_string($name)); + + $normalizedName = str_replace('_', '-', $name); + + if (isset($keywordArgs[$normalizedName])) { + throw new SassScriptException(sprintf('Duplicate named argument $%s.', $name)); + } + + $keywordArgs[$normalizedName] = $this->maybeReduce($reduce, $item); + $names[$normalizedName] = $normalizedName; + $hasKeywordArgument = true; + } + } + } elseif ($val[0] === Type::T_MAP) { + foreach ($val[1] as $i => $name) { + $name = $this->compileStringContent($this->coerceString($name)); + $item = $val[2][$i]; + + if (! is_numeric($name)) { + $normalizedName = str_replace('_', '-', $name); + + if (isset($keywordArgs[$normalizedName])) { + throw new SassScriptException(sprintf('Duplicate named argument $%s.', $name)); + } + + $keywordArgs[$normalizedName] = $this->maybeReduce($reduce, $item); + $names[$normalizedName] = $normalizedName; + $hasKeywordArgument = true; + } else { + if (\is_null($splatSeparator)) { + $splatSeparator = $val[1]; + } + + $positionalArgs[] = $this->maybeReduce($reduce, $item); + } + } + } elseif ($val[0] !== Type::T_NULL) { // values other than null are treated a single-element lists, while null is the empty list + $positionalArgs[] = $this->maybeReduce($reduce, $val); + } + } elseif ($hasKeywordArgument) { + throw new SassScriptException('Positional arguments must come before keyword arguments.'); + } else { + $positionalArgs[] = $this->maybeReduce($reduce, $arg[1]); + } + } + + return [$positionalArgs, $keywordArgs, $names, $splatSeparator, $hasSplat]; + } + + /** + * @param bool $reduce + * @param array|Number $value + * + * @return array|Number + */ + private function maybeReduce($reduce, $value) + { + if ($reduce) { + return $this->reduce($value, true); + } + + return $value; + } + + /** + * Apply argument values per definition + * + * @param array[] $argDef + * @param array|null $argValues + * @param bool $storeInEnv + * @param bool $reduce only used if $storeInEnv = false + * + * @return array + * + * @phpstan-param list $argDef + * + * @throws \Exception + */ + protected function applyArguments($argDef, $argValues, $storeInEnv = true, $reduce = true) + { + $output = []; + + if (\is_null($argValues)) { + $argValues = []; + } + + if ($storeInEnv) { + $storeEnv = $this->getStoreEnv(); + + $env = new Environment(); + $env->store = $storeEnv->store; + } + + $prototype = ['arguments' => [], 'rest_argument' => null]; + $originalRestArgumentName = null; + + foreach ($argDef as $arg) { + list($name, $default, $isVariable) = $arg; + $normalizedName = str_replace('_', '-', $name); + + if ($isVariable) { + $originalRestArgumentName = $name; + $prototype['rest_argument'] = $normalizedName; + } else { + $prototype['arguments'][] = [$normalizedName, $name, !empty($default) ? $default : null]; + } + } + + list($positionalArgs, $namedArgs, $names, $splatSeparator, $hasSplat) = $this->evaluateArguments($argValues, $reduce); + + $this->verifyPrototype($prototype, \count($positionalArgs), $names, $hasSplat); + + $vars = $this->applyArgumentsToDeclaration($prototype, $positionalArgs, $namedArgs, $splatSeparator); + + foreach ($prototype['arguments'] as $argument) { + list($normalizedName, $name) = $argument; + + if (!isset($vars[$normalizedName])) { + continue; + } + + $val = $vars[$normalizedName]; + + if ($storeInEnv) { + $this->set($name, $this->reduce($val, true), true, $env); + } else { + $output[$name] = ($reduce ? $this->reduce($val, true) : $val); + } + } + + if ($prototype['rest_argument'] !== null) { + assert($originalRestArgumentName !== null); + $name = $originalRestArgumentName; + $val = $vars[$prototype['rest_argument']]; + + if ($storeInEnv) { + $this->set($name, $this->reduce($val, true), true, $env); + } else { + $output[$name] = ($reduce ? $this->reduce($val, true) : $val); + } + } + + if ($storeInEnv) { + $storeEnv->store = $env->store; + } + + foreach ($prototype['arguments'] as $argument) { + list($normalizedName, $name, $default) = $argument; + + if (isset($vars[$normalizedName])) { + continue; + } + assert($default !== null); + + if ($storeInEnv) { + $this->set($name, $this->reduce($default, true), true); + } else { + $output[$name] = ($reduce ? $this->reduce($default, true) : $default); + } + } + + return $output; + } + + /** + * Apply argument values per definition. + * + * This method assumes that the arguments are valid for the provided prototype. + * The validation with {@see verifyPrototype} must have been run before calling + * it. + * Arguments are returned as a map from the normalized argument names to the + * value. Additional arguments are collected in a sass argument list available + * under the name of the rest argument in the result. + * + * Defaults are not applied as they are resolved in a different environment. + * + * @param array $prototype + * @param array $positionalArgs + * @param array $namedArgs + * @param string|null $splatSeparator + * + * @return array + * + * @phpstan-param array{arguments: list, rest_argument: string|null} $prototype + */ + private function applyArgumentsToDeclaration(array $prototype, array $positionalArgs, array $namedArgs, $splatSeparator) + { + $output = []; + $minLength = min(\count($positionalArgs), \count($prototype['arguments'])); + + for ($i = 0; $i < $minLength; $i++) { + list($name) = $prototype['arguments'][$i]; + $val = $positionalArgs[$i]; + + $output[$name] = $val; + } + + $restNamed = $namedArgs; + + for ($i = \count($positionalArgs); $i < \count($prototype['arguments']); $i++) { + $argument = $prototype['arguments'][$i]; + list($name) = $argument; + + if (isset($namedArgs[$name])) { + $val = $namedArgs[$name]; + unset($restNamed[$name]); + } else { + continue; + } + + $output[$name] = $val; + } + + if ($prototype['rest_argument'] !== null) { + $name = $prototype['rest_argument']; + $rest = array_values(array_slice($positionalArgs, \count($prototype['arguments']))); + + $val = [Type::T_LIST, \is_null($splatSeparator) ? ',' : $splatSeparator , $rest, $restNamed]; + + $output[$name] = $val; + } + + return $output; + } + + /** + * Coerce a php value into a scss one + * + * @param mixed $value + * + * @return array|Number + */ + protected function coerceValue($value) + { + if (\is_array($value) || $value instanceof Number) { + return $value; + } + + if (\is_bool($value)) { + return $this->toBool($value); + } + + if (\is_null($value)) { + return static::$null; + } + + if (\is_int($value) || \is_float($value)) { + return new Number($value, ''); + } + + if (is_numeric($value)) { + return new Number((float) $value, ''); + } + + if ($value === '') { + return static::$emptyString; + } + + $value = [Type::T_KEYWORD, $value]; + $color = $this->coerceColor($value); + + if ($color) { + return $color; + } + + return $value; + } + + /** + * Tries to convert an item to a Sass map + * + * @param Number|array $item + * + * @return array|null + */ + private function tryMap($item) + { + if ($item instanceof Number) { + return null; + } + + if ($item[0] === Type::T_MAP) { + return $item; + } + + if ( + $item[0] === Type::T_LIST && + $item[2] === [] + ) { + return static::$emptyMap; + } + + return null; + } + + /** + * Coerce something to map + * + * @param array|Number $item + * + * @return array|Number + */ + protected function coerceMap($item) + { + $map = $this->tryMap($item); + + if ($map !== null) { + return $map; + } + + return $item; + } + + /** + * Coerce something to list + * + * @param array|Number $item + * @param string $delim + * @param bool $removeTrailingNull + * + * @return array + */ + protected function coerceList($item, $delim = ',', $removeTrailingNull = false) + { + if ($item instanceof Number) { + return [Type::T_LIST, '', [$item]]; + } + + if ($item[0] === Type::T_LIST) { + // remove trailing null from the list + if ($removeTrailingNull && end($item[2]) === static::$null) { + array_pop($item[2]); + } + + return $item; + } + + if ($item[0] === Type::T_MAP) { + $keys = $item[1]; + $values = $item[2]; + $list = []; + + for ($i = 0, $s = \count($keys); $i < $s; $i++) { + $key = $keys[$i]; + $value = $values[$i]; + + $list[] = [ + Type::T_LIST, + ' ', + [$key, $value] + ]; + } + + return [Type::T_LIST, $list ? ',' : '', $list]; + } + + return [Type::T_LIST, '', [$item]]; + } + + /** + * Coerce color for expression + * + * @param array|Number $value + * + * @return array|Number + */ + protected function coerceForExpression($value) + { + if ($color = $this->coerceColor($value)) { + return $color; + } + + return $value; + } + + /** + * Coerce value to color + * + * @param array|Number $value + * @param bool $inRGBFunction + * + * @return array|null + */ + protected function coerceColor($value, $inRGBFunction = false) + { + if ($value instanceof Number) { + return null; + } + + switch ($value[0]) { + case Type::T_COLOR: + for ($i = 1; $i <= 3; $i++) { + if (! is_numeric($value[$i])) { + $cv = $this->compileRGBAValue($value[$i]); + + if (! is_numeric($cv)) { + return null; + } + + $value[$i] = $cv; + } + + if (isset($value[4])) { + if (! is_numeric($value[4])) { + $cv = $this->compileRGBAValue($value[4], true); + + if (! is_numeric($cv)) { + return null; + } + + $value[4] = $cv; + } + } + } + + return $value; + + case Type::T_LIST: + if ($inRGBFunction) { + if (\count($value[2]) == 3 || \count($value[2]) == 4) { + $color = $value[2]; + array_unshift($color, Type::T_COLOR); + + return $this->coerceColor($color); + } + } + + return null; + + case Type::T_KEYWORD: + if (! \is_string($value[1])) { + return null; + } + + $name = strtolower($value[1]); + + // hexa color? + if (preg_match('/^#([0-9a-f]+)$/i', $name, $m)) { + $nofValues = \strlen($m[1]); + + if (\in_array($nofValues, [3, 4, 6, 8])) { + $nbChannels = 3; + $color = []; + $num = hexdec($m[1]); + + switch ($nofValues) { + case 4: + $nbChannels = 4; + // then continuing with the case 3: + case 3: + for ($i = 0; $i < $nbChannels; $i++) { + $t = $num & 0xf; + array_unshift($color, $t << 4 | $t); + $num >>= 4; + } + + break; + + case 8: + $nbChannels = 4; + // then continuing with the case 6: + case 6: + for ($i = 0; $i < $nbChannels; $i++) { + array_unshift($color, $num & 0xff); + $num >>= 8; + } + + break; + } + + if ($nbChannels === 4) { + if ($color[3] === 255) { + $color[3] = 1; // fully opaque + } else { + $color[3] = round($color[3] / 255, Number::PRECISION); + } + } + + array_unshift($color, Type::T_COLOR); + + return $color; + } + } + + if ($rgba = Colors::colorNameToRGBa($name)) { + return isset($rgba[3]) + ? [Type::T_COLOR, $rgba[0], $rgba[1], $rgba[2], $rgba[3]] + : [Type::T_COLOR, $rgba[0], $rgba[1], $rgba[2]]; + } + + return null; + } + + return null; + } + + /** + * @param int|Number $value + * @param bool $isAlpha + * + * @return int|mixed + */ + protected function compileRGBAValue($value, $isAlpha = false) + { + if ($isAlpha) { + return $this->compileColorPartValue($value, 0, 1, false); + } + + return $this->compileColorPartValue($value, 0, 255, true); + } + + /** + * @param mixed $value + * @param int|float $min + * @param int|float $max + * @param bool $isInt + * + * @return int|mixed + */ + protected function compileColorPartValue($value, $min, $max, $isInt = true) + { + if (! is_numeric($value)) { + if (\is_array($value)) { + $reduced = $this->reduce($value); + + if ($reduced instanceof Number) { + $value = $reduced; + } + } + + if ($value instanceof Number) { + if ($value->unitless()) { + $num = $value->getDimension(); + } elseif ($value->hasUnit('%')) { + $num = $max * $value->getDimension() / 100; + } else { + throw $this->error('Expected %s to have no units or "%%".', $value); + } + + $value = $num; + } elseif (\is_array($value)) { + $value = $this->compileValue($value); + } + } + + if (is_numeric($value)) { + if ($isInt) { + $value = round($value); + } + + $value = min($max, max($min, $value)); + + return $value; + } + + return $value; + } + + /** + * Coerce value to string + * + * @param array|Number $value + * + * @return array + */ + protected function coerceString($value) + { + if ($value[0] === Type::T_STRING) { + assert(\is_array($value)); + + return $value; + } + + return [Type::T_STRING, '', [$this->compileValue($value)]]; + } + + /** + * Assert value is a string + * + * This method deals with internal implementation details of the value + * representation where unquoted strings can sometimes be stored under + * other types. + * The returned value is always using the T_STRING type. + * + * @api + * + * @param array|Number $value + * @param string|null $varName + * + * @return array + * + * @throws SassScriptException + */ + public function assertString($value, $varName = null) + { + // case of url(...) parsed a a function + if ($value[0] === Type::T_FUNCTION) { + $value = $this->coerceString($value); + } + + if (! \in_array($value[0], [Type::T_STRING, Type::T_KEYWORD])) { + $value = $this->compileValue($value); + throw SassScriptException::forArgument("$value is not a string.", $varName); + } + + return $this->coerceString($value); + } + + /** + * Coerce value to a percentage + * + * @param array|Number $value + * + * @return int|float + * + * @deprecated + */ + protected function coercePercent($value) + { + @trigger_error(sprintf('"%s" is deprecated since 1.7.0.', __METHOD__), E_USER_DEPRECATED); + + if ($value instanceof Number) { + if ($value->hasUnit('%')) { + return $value->getDimension() / 100; + } + + return $value->getDimension(); + } + + return 0; + } + + /** + * Assert value is a map + * + * @api + * + * @param array|Number $value + * @param string|null $varName + * + * @return array + * + * @throws SassScriptException + */ + public function assertMap($value, $varName = null) + { + $map = $this->tryMap($value); + + if ($map === null) { + $value = $this->compileValue($value); + + throw SassScriptException::forArgument("$value is not a map.", $varName); + } + + return $map; + } + + /** + * Assert value is a list + * + * @api + * + * @param array|Number $value + * + * @return array + * + * @throws \Exception + */ + public function assertList($value) + { + if ($value[0] !== Type::T_LIST) { + throw $this->error('expecting list, %s received', $value[0]); + } + assert(\is_array($value)); + + return $value; + } + + /** + * Gets the keywords of an argument list. + * + * Keys in the returned array are normalized names (underscores are replaced with dashes) + * without the leading `$`. + * Calling this helper with anything that an argument list received for a rest argument + * of the function argument declaration is not supported. + * + * @param array|Number $value + * + * @return array + */ + public function getArgumentListKeywords($value) + { + if ($value[0] !== Type::T_LIST || !isset($value[3]) || !\is_array($value[3])) { + throw new \InvalidArgumentException('The argument is not a sass argument list.'); + } + + return $value[3]; + } + + /** + * Assert value is a color + * + * @api + * + * @param array|Number $value + * @param string|null $varName + * + * @return array + * + * @throws SassScriptException + */ + public function assertColor($value, $varName = null) + { + if ($color = $this->coerceColor($value)) { + return $color; + } + + $value = $this->compileValue($value); + + throw SassScriptException::forArgument("$value is not a color.", $varName); + } + + /** + * Assert value is a number + * + * @api + * + * @param array|Number $value + * @param string|null $varName + * + * @return Number + * + * @throws SassScriptException + */ + public function assertNumber($value, $varName = null) + { + if (!$value instanceof Number) { + $value = $this->compileValue($value); + throw SassScriptException::forArgument("$value is not a number.", $varName); + } + + return $value; + } + + /** + * Assert value is a integer + * + * @api + * + * @param array|Number $value + * @param string|null $varName + * + * @return int + * + * @throws SassScriptException + */ + public function assertInteger($value, $varName = null) + { + $value = $this->assertNumber($value, $varName)->getDimension(); + if (round($value - \intval($value), Number::PRECISION) > 0) { + throw SassScriptException::forArgument("$value is not an integer.", $varName); + } + + return intval($value); + } + + /** + * Extract the ... / alpha on the last argument of channel arg + * in color functions + * + * @param array $args + * @return array + */ + private function extractSlashAlphaInColorFunction($args) + { + $last = end($args); + if (\count($args) === 3 && $last[0] === Type::T_EXPRESSION && $last[1] === '/') { + array_pop($args); + $args[] = $last[2]; + $args[] = $last[3]; + } + return $args; + } + + + /** + * Make sure a color's components don't go out of bounds + * + * @param array $c + * + * @return array + */ + protected function fixColor($c) + { + foreach ([1, 2, 3] as $i) { + if ($c[$i] < 0) { + $c[$i] = 0; + } + + if ($c[$i] > 255) { + $c[$i] = 255; + } + + if (!\is_int($c[$i])) { + $c[$i] = round($c[$i]); + } + } + + return $c; + } + + /** + * Convert RGB to HSL + * + * @internal + * + * @param int $red + * @param int $green + * @param int $blue + * + * @return array + */ + public function toHSL($red, $green, $blue) + { + $min = min($red, $green, $blue); + $max = max($red, $green, $blue); + + $l = $min + $max; + $d = $max - $min; + + if ((int) $d === 0) { + $h = $s = 0; + } else { + if ($l < 255) { + $s = $d / $l; + } else { + $s = $d / (510 - $l); + } + + if ($red == $max) { + $h = 60 * ($green - $blue) / $d; + } elseif ($green == $max) { + $h = 60 * ($blue - $red) / $d + 120; + } else { + $h = 60 * ($red - $green) / $d + 240; + } + } + + return [Type::T_HSL, fmod($h + 360, 360), $s * 100, $l / 5.1]; + } + + /** + * Hue to RGB helper + * + * @param float $m1 + * @param float $m2 + * @param float $h + * + * @return float + */ + protected function hueToRGB($m1, $m2, $h) + { + if ($h < 0) { + $h += 1; + } elseif ($h > 1) { + $h -= 1; + } + + if ($h * 6 < 1) { + return $m1 + ($m2 - $m1) * $h * 6; + } + + if ($h * 2 < 1) { + return $m2; + } + + if ($h * 3 < 2) { + return $m1 + ($m2 - $m1) * (2 / 3 - $h) * 6; + } + + return $m1; + } + + /** + * Convert HSL to RGB + * + * @internal + * + * @param int|float $hue H from 0 to 360 + * @param int|float $saturation S from 0 to 100 + * @param int|float $lightness L from 0 to 100 + * + * @return array + */ + public function toRGB($hue, $saturation, $lightness) + { + if ($hue < 0) { + $hue += 360; + } + + $h = $hue / 360; + $s = min(100, max(0, $saturation)) / 100; + $l = min(100, max(0, $lightness)) / 100; + + $m2 = $l <= 0.5 ? $l * ($s + 1) : $l + $s - $l * $s; + $m1 = $l * 2 - $m2; + + $r = $this->hueToRGB($m1, $m2, $h + 1 / 3) * 255; + $g = $this->hueToRGB($m1, $m2, $h) * 255; + $b = $this->hueToRGB($m1, $m2, $h - 1 / 3) * 255; + + $out = [Type::T_COLOR, $r, $g, $b]; + + return $out; + } + + /** + * Convert HWB to RGB + * https://www.w3.org/TR/css-color-4/#hwb-to-rgb + * + * @api + * + * @param int|float $hue H from 0 to 360 + * @param int|float $whiteness W from 0 to 100 + * @param int|float $blackness B from 0 to 100 + * + * @return array + */ + private function HWBtoRGB($hue, $whiteness, $blackness) + { + $w = min(100, max(0, $whiteness)) / 100; + $b = min(100, max(0, $blackness)) / 100; + + $sum = $w + $b; + if ($sum > 1.0) { + $w = $w / $sum; + $b = $b / $sum; + } + $b = min(1.0 - $w, $b); + + $rgb = $this->toRGB($hue, 100, 50); + for ($i = 1; $i < 4; $i++) { + $rgb[$i] *= (1.0 - $w - $b); + $rgb[$i] = round($rgb[$i] + 255 * $w + 0.0001); + } + + return $rgb; + } + + /** + * Convert RGB to HWB + * + * @api + * + * @param int $red + * @param int $green + * @param int $blue + * + * @return array + */ + private function RGBtoHWB($red, $green, $blue) + { + $min = min($red, $green, $blue); + $max = max($red, $green, $blue); + + $d = $max - $min; + + if ((int) $d === 0) { + $h = 0; + } else { + if ($red == $max) { + $h = 60 * ($green - $blue) / $d; + } elseif ($green == $max) { + $h = 60 * ($blue - $red) / $d + 120; + } else { + $h = 60 * ($red - $green) / $d + 240; + } + } + + return [Type::T_HWB, fmod($h, 360), $min / 255 * 100, 100 - $max / 255 * 100]; + } + + + // Built in functions + + protected static $libCall = ['function', 'args...']; + protected function libCall($args) + { + $functionReference = $args[0]; + + if (in_array($functionReference[0], [Type::T_STRING, Type::T_KEYWORD])) { + $name = $this->compileStringContent($this->coerceString($functionReference)); + $warning = "Passing a string to call() is deprecated and will be illegal\n" + . "in Sass 4.0. Use call(function-reference($name)) instead."; + Warn::deprecation($warning); + $functionReference = $this->libGetFunction([$this->assertString($functionReference, 'function')]); + } + + if ($functionReference === static::$null) { + return static::$null; + } + + if (! in_array($functionReference[0], [Type::T_FUNCTION_REFERENCE, Type::T_FUNCTION])) { + throw $this->error('Function reference expected, got ' . $functionReference[0]); + } + + $callArgs = [ + [null, $args[1], true] + ]; + + return $this->reduce([Type::T_FUNCTION_CALL, $functionReference, $callArgs]); + } + + + protected static $libGetFunction = [ + ['name'], + ['name', 'css'] + ]; + protected function libGetFunction($args) + { + $name = $this->compileStringContent($this->assertString(array_shift($args), 'name')); + $isCss = false; + + if (count($args)) { + $isCss = array_shift($args); + $isCss = (($isCss === static::$true) ? true : false); + } + + if ($isCss) { + return [Type::T_FUNCTION, $name, [Type::T_LIST, ',', []]]; + } + + return $this->getFunctionReference($name, true); + } + + protected static $libIf = ['condition', 'if-true', 'if-false:']; + protected function libIf($args) + { + list($cond, $t, $f) = $args; + + if (! $this->isTruthy($this->reduce($cond, true))) { + return $this->reduce($f, true); + } + + return $this->reduce($t, true); + } + + protected static $libIndex = ['list', 'value']; + protected function libIndex($args) + { + list($list, $value) = $args; + + if ( + $list[0] === Type::T_MAP || + $list[0] === Type::T_STRING || + $list[0] === Type::T_KEYWORD || + $list[0] === Type::T_INTERPOLATE + ) { + $list = $this->coerceList($list, ' '); + } + + if ($list[0] !== Type::T_LIST) { + return static::$null; + } + + // Numbers are represented with value objects, for which the PHP equality operator does not + // match the Sass rules (and we cannot overload it). As they are the only type of values + // represented with a value object for now, they require a special case. + if ($value instanceof Number) { + $key = 0; + foreach ($list[2] as $item) { + $key++; + $itemValue = $this->normalizeValue($item); + + if ($itemValue instanceof Number && $value->equals($itemValue)) { + return new Number($key, ''); + } + } + return static::$null; + } + + $values = []; + + foreach ($list[2] as $item) { + $values[] = $this->normalizeValue($item); + } + + $key = array_search($this->normalizeValue($value), $values); + + return false === $key ? static::$null : new Number($key + 1, ''); + } + + protected static $libRgb = [ + ['color'], + ['color', 'alpha'], + ['channels'], + ['red', 'green', 'blue'], + ['red', 'green', 'blue', 'alpha'] ]; + + /** + * @param array $args + * @param array $kwargs + * @param string $funcName + * + * @return array + */ + protected function libRgb($args, $kwargs, $funcName = 'rgb') + { + switch (\count($args)) { + case 1: + if (! $color = $this->coerceColor($args[0], true)) { + $color = [Type::T_STRING, '', [$funcName . '(', $args[0], ')']]; + } + break; + + case 3: + $color = [Type::T_COLOR, $args[0], $args[1], $args[2]]; + + if (! $color = $this->coerceColor($color)) { + $color = [Type::T_STRING, '', [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ')']]; + } + + return $color; + + case 2: + if ($color = $this->coerceColor($args[0], true)) { + $alpha = $this->compileRGBAValue($args[1], true); + + if (is_numeric($alpha)) { + $color[4] = $alpha; + } else { + $color = [Type::T_STRING, '', + [$funcName . '(', $color[1], ', ', $color[2], ', ', $color[3], ', ', $alpha, ')']]; + } + } else { + $color = [Type::T_STRING, '', [$funcName . '(', $args[0], ', ', $args[1], ')']]; + } + break; + + case 4: + default: + $color = [Type::T_COLOR, $args[0], $args[1], $args[2], $args[3]]; + + if (! $color = $this->coerceColor($color)) { + $color = [Type::T_STRING, '', + [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ', ', $args[3], ')']]; + } + break; + } + + return $color; + } + + protected static $libRgba = [ + ['color'], + ['color', 'alpha'], + ['channels'], + ['red', 'green', 'blue'], + ['red', 'green', 'blue', 'alpha'] ]; + protected function libRgba($args, $kwargs) + { + return $this->libRgb($args, $kwargs, 'rgba'); + } + + /** + * Helper function for adjust_color, change_color, and scale_color + * + * @param array $args + * @param string $operation + * @param callable $fn + * + * @return array + * + * @phpstan-param callable(float|int, float|int|null, float|int): (float|int) $fn + */ + protected function alterColor(array $args, $operation, $fn) + { + $color = $this->assertColor($args[0], 'color'); + + if ($args[1][2]) { + throw new SassScriptException('Only one positional argument is allowed. All other arguments must be passed by name.'); + } + + $kwargs = $this->getArgumentListKeywords($args[1]); + + $scale = $operation === 'scale'; + $change = $operation === 'change'; + + /** + * @param string $name + * @param float|int $max + * @param bool $checkPercent + * @param bool $assertPercent + * @return float|int|null + */ + $getParam = function ($name, $max, $checkPercent = false, $assertPercent = false) use (&$kwargs, $scale, $change) { + if (!isset($kwargs[$name])) { + return null; + } + + $number = $this->assertNumber($kwargs[$name], $name); + unset($kwargs[$name]); + + if (!$scale && $checkPercent) { + if (!$number->hasUnit('%')) { + $warning = $this->error("{$name} Passing a number `$number` without unit % is deprecated."); + $this->logger->warn($warning->getMessage(), true); + } + } + + if ($scale || $assertPercent) { + $number->assertUnit('%', $name); + } + + if ($scale) { + $max = 100; + } + + if ($scale || $assertPercent) { + return $number->valueInRange($change ? 0 : -$max, $max, $name); + } + + return $number->valueInRangeWithUnit($change ? 0 : -$max, $max, $name, $checkPercent ? '%' : ''); + }; + + $alpha = $getParam('alpha', 1); + $red = $getParam('red', 255); + $green = $getParam('green', 255); + $blue = $getParam('blue', 255); + + if ($scale || !isset($kwargs['hue'])) { + $hue = null; + } else { + $hueNumber = $this->assertNumber($kwargs['hue'], 'hue'); + unset($kwargs['hue']); + $hue = $hueNumber->getDimension(); + } + $saturation = $getParam('saturation', 100, true); + $lightness = $getParam('lightness', 100, true); + $whiteness = $getParam('whiteness', 100, false, true); + $blackness = $getParam('blackness', 100, false, true); + + if (!empty($kwargs)) { + $unknownNames = array_keys($kwargs); + $lastName = array_pop($unknownNames); + $message = sprintf( + 'No argument%s named $%s%s.', + $unknownNames ? 's' : '', + $unknownNames ? implode(', $', $unknownNames) . ' or $' : '', + $lastName + ); + throw new SassScriptException($message); + } + + $hasRgb = $red !== null || $green !== null || $blue !== null; + $hasSL = $saturation !== null || $lightness !== null; + $hasWB = $whiteness !== null || $blackness !== null; + + if ($hasRgb && ($hasSL || $hasWB || $hue !== null)) { + throw new SassScriptException(sprintf('RGB parameters may not be passed along with %s parameters.', $hasWB ? 'HWB' : 'HSL')); + } + + if ($hasWB && $hasSL) { + throw new SassScriptException('HSL parameters may not be passed along with HWB parameters.'); + } + + if ($hasRgb) { + $color[1] = round($fn($color[1], $red, 255)); + $color[2] = round($fn($color[2], $green, 255)); + $color[3] = round($fn($color[3], $blue, 255)); + } elseif ($hasWB) { + $hwb = $this->RGBtoHWB($color[1], $color[2], $color[3]); + if ($hue !== null) { + $hwb[1] = $change ? $hue : $hwb[1] + $hue; + } + $hwb[2] = $fn($hwb[2], $whiteness, 100); + $hwb[3] = $fn($hwb[3], $blackness, 100); + + $rgb = $this->HWBtoRGB($hwb[1], $hwb[2], $hwb[3]); + + if (isset($color[4])) { + $rgb[4] = $color[4]; + } + + $color = $rgb; + } elseif ($hue !== null || $hasSL) { + $hsl = $this->toHSL($color[1], $color[2], $color[3]); + + if ($hue !== null) { + $hsl[1] = $change ? $hue : $hsl[1] + $hue; + } + $hsl[2] = $fn($hsl[2], $saturation, 100); + $hsl[3] = $fn($hsl[3], $lightness, 100); + + $rgb = $this->toRGB($hsl[1], $hsl[2], $hsl[3]); + + if (isset($color[4])) { + $rgb[4] = $color[4]; + } + + $color = $rgb; + } + + if ($alpha !== null) { + $existingAlpha = isset($color[4]) ? $color[4] : 1; + $color[4] = $fn($existingAlpha, $alpha, 1); + } + + return $color; + } + + protected static $libAdjustColor = ['color', 'kwargs...']; + protected function libAdjustColor($args) + { + return $this->alterColor($args, 'adjust', function ($base, $alter, $max) { + if ($alter === null) { + return $base; + } + + $new = $base + $alter; + + if ($new < 0) { + return 0; + } + + if ($new > $max) { + return $max; + } + + return $new; + }); + } + + protected static $libChangeColor = ['color', 'kwargs...']; + protected function libChangeColor($args) + { + return $this->alterColor($args, 'change', function ($base, $alter, $max) { + if ($alter === null) { + return $base; + } + + return $alter; + }); + } + + protected static $libScaleColor = ['color', 'kwargs...']; + protected function libScaleColor($args) + { + return $this->alterColor($args, 'scale', function ($base, $scale, $max) { + if ($scale === null) { + return $base; + } + + $scale = $scale / 100; + + if ($scale < 0) { + return $base * $scale + $base; + } + + return ($max - $base) * $scale + $base; + }); + } + + protected static $libIeHexStr = ['color']; + protected function libIeHexStr($args) + { + $color = $this->coerceColor($args[0]); + + if (\is_null($color)) { + throw $this->error('Error: argument `$color` of `ie-hex-str($color)` must be a color'); + } + + $color[4] = isset($color[4]) ? round(255 * $color[4]) : 255; + + return [Type::T_STRING, '', [sprintf('#%02X%02X%02X%02X', $color[4], $color[1], $color[2], $color[3])]]; + } + + protected static $libRed = ['color']; + protected function libRed($args) + { + $color = $this->coerceColor($args[0]); + + if (\is_null($color)) { + throw $this->error('Error: argument `$color` of `red($color)` must be a color'); + } + + return new Number((int) $color[1], ''); + } + + protected static $libGreen = ['color']; + protected function libGreen($args) + { + $color = $this->coerceColor($args[0]); + + if (\is_null($color)) { + throw $this->error('Error: argument `$color` of `green($color)` must be a color'); + } + + return new Number((int) $color[2], ''); + } + + protected static $libBlue = ['color']; + protected function libBlue($args) + { + $color = $this->coerceColor($args[0]); + + if (\is_null($color)) { + throw $this->error('Error: argument `$color` of `blue($color)` must be a color'); + } + + return new Number((int) $color[3], ''); + } + + protected static $libAlpha = ['color']; + protected function libAlpha($args) + { + if ($color = $this->coerceColor($args[0])) { + return new Number(isset($color[4]) ? $color[4] : 1, ''); + } + + // this might be the IE function, so return value unchanged + return null; + } + + protected static $libOpacity = ['color']; + protected function libOpacity($args) + { + $value = $args[0]; + + if ($value instanceof Number) { + return null; + } + + return $this->libAlpha($args); + } + + // mix two colors + protected static $libMix = [ + ['color1', 'color2', 'weight:50%'], + ['color-1', 'color-2', 'weight:50%'] + ]; + protected function libMix($args) + { + list($first, $second, $weight) = $args; + + $first = $this->assertColor($first, 'color1'); + $second = $this->assertColor($second, 'color2'); + $weightScale = $this->assertNumber($weight, 'weight')->valueInRange(0, 100, 'weight') / 100; + + $firstAlpha = isset($first[4]) ? $first[4] : 1; + $secondAlpha = isset($second[4]) ? $second[4] : 1; + + $normalizedWeight = $weightScale * 2 - 1; + $alphaDistance = $firstAlpha - $secondAlpha; + + $combinedWeight = $normalizedWeight * $alphaDistance == -1 ? $normalizedWeight : ($normalizedWeight + $alphaDistance) / (1 + $normalizedWeight * $alphaDistance); + $weight1 = ($combinedWeight + 1) / 2.0; + $weight2 = 1.0 - $weight1; + + $new = [Type::T_COLOR, + $weight1 * $first[1] + $weight2 * $second[1], + $weight1 * $first[2] + $weight2 * $second[2], + $weight1 * $first[3] + $weight2 * $second[3], + ]; + + if ($firstAlpha != 1.0 || $secondAlpha != 1.0) { + $new[] = $firstAlpha * $weightScale + $secondAlpha * (1 - $weightScale); + } + + return $this->fixColor($new); + } + + protected static $libHsl = [ + ['channels'], + ['hue', 'saturation'], + ['hue', 'saturation', 'lightness'], + ['hue', 'saturation', 'lightness', 'alpha'] ]; + + /** + * @param array $args + * @param array $kwargs + * @param string $funcName + * + * @return array|null + */ + protected function libHsl($args, $kwargs, $funcName = 'hsl') + { + $args_to_check = $args; + + if (\count($args) == 1) { + if ($args[0][0] !== Type::T_LIST || \count($args[0][2]) < 3 || \count($args[0][2]) > 4) { + return [Type::T_STRING, '', [$funcName . '(', $args[0], ')']]; + } + + $args = $args[0][2]; + $args_to_check = $kwargs['channels'][2]; + } + + if (\count($args) === 2) { + // if var() is used as an argument, return as a css function + foreach ($args as $arg) { + if ($arg[0] === Type::T_FUNCTION && in_array($arg[1], ['var'])) { + return null; + } + } + + throw new SassScriptException('Missing argument $lightness.'); + } + + foreach ($kwargs as $arg) { + if (in_array($arg[0], [Type::T_FUNCTION_CALL, Type::T_FUNCTION]) && in_array($arg[1], ['min', 'max'])) { + return null; + } + } + + foreach ($args_to_check as $k => $arg) { + if (in_array($arg[0], [Type::T_FUNCTION_CALL, Type::T_FUNCTION]) && in_array($arg[1], ['min', 'max'])) { + if (count($kwargs) > 1 || ($k >= 2 && count($args) === 4)) { + return null; + } + + $args[$k] = $this->stringifyFncallArgs($arg); + } + + if ( + $k >= 2 && count($args) === 4 && + in_array($arg[0], [Type::T_FUNCTION_CALL, Type::T_FUNCTION]) && + in_array($arg[1], ['calc','env']) + ) { + return null; + } + } + + $hue = $this->reduce($args[0]); + $saturation = $this->reduce($args[1]); + $lightness = $this->reduce($args[2]); + $alpha = null; + + if (\count($args) === 4) { + $alpha = $this->compileColorPartValue($args[3], 0, 100, false); + + if (!$hue instanceof Number || !$saturation instanceof Number || ! $lightness instanceof Number || ! is_numeric($alpha)) { + return [Type::T_STRING, '', + [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ', ', $args[3], ')']]; + } + } else { + if (!$hue instanceof Number || !$saturation instanceof Number || ! $lightness instanceof Number) { + return [Type::T_STRING, '', [$funcName . '(', $args[0], ', ', $args[1], ', ', $args[2], ')']]; + } + } + + $hueValue = fmod($hue->getDimension(), 360); + + while ($hueValue < 0) { + $hueValue += 360; + } + + $color = $this->toRGB($hueValue, max(0, min($saturation->getDimension(), 100)), max(0, min($lightness->getDimension(), 100))); + + if (! \is_null($alpha)) { + $color[4] = $alpha; + } + + return $color; + } + + protected static $libHsla = [ + ['channels'], + ['hue', 'saturation'], + ['hue', 'saturation', 'lightness'], + ['hue', 'saturation', 'lightness', 'alpha']]; + protected function libHsla($args, $kwargs) + { + return $this->libHsl($args, $kwargs, 'hsla'); + } + + protected static $libHue = ['color']; + protected function libHue($args) + { + $color = $this->assertColor($args[0], 'color'); + $hsl = $this->toHSL($color[1], $color[2], $color[3]); + + return new Number($hsl[1], 'deg'); + } + + protected static $libSaturation = ['color']; + protected function libSaturation($args) + { + $color = $this->assertColor($args[0], 'color'); + $hsl = $this->toHSL($color[1], $color[2], $color[3]); + + return new Number($hsl[2], '%'); + } + + protected static $libLightness = ['color']; + protected function libLightness($args) + { + $color = $this->assertColor($args[0], 'color'); + $hsl = $this->toHSL($color[1], $color[2], $color[3]); + + return new Number($hsl[3], '%'); + } + + /* + * Todo : a integrer dans le futur module color + protected static $libHwb = [ + ['channels'], + ['hue', 'whiteness', 'blackness'], + ['hue', 'whiteness', 'blackness', 'alpha'] ]; + protected function libHwb($args, $kwargs, $funcName = 'hwb') + { + $args_to_check = $args; + + if (\count($args) == 1) { + if ($args[0][0] !== Type::T_LIST) { + throw $this->error("Missing elements \$whiteness and \$blackness"); + } + + if (\trim($args[0][1])) { + throw $this->error("\$channels must be a space-separated list."); + } + + if (! empty($args[0]['enclosing'])) { + throw $this->error("\$channels must be an unbracketed list."); + } + + $args = $args[0][2]; + if (\count($args) > 3) { + throw $this->error("hwb() : Only 3 elements are allowed but ". \count($args) . "were passed"); + } + + $args_to_check = $this->extractSlashAlphaInColorFunction($kwargs['channels'][2]); + if (\count($args_to_check) !== \count($kwargs['channels'][2])) { + $args = $args_to_check; + } + } + + if (\count($args_to_check) < 2) { + throw $this->error("Missing elements \$whiteness and \$blackness"); + } + if (\count($args_to_check) < 3) { + throw $this->error("Missing element \$blackness"); + } + if (\count($args_to_check) > 4) { + throw $this->error("hwb() : Only 4 elements are allowed but ". \count($args) . "were passed"); + } + + foreach ($kwargs as $k => $arg) { + if (in_array($arg[0], [Type::T_FUNCTION_CALL]) && in_array($arg[1], ['min', 'max'])) { + return null; + } + } + + foreach ($args_to_check as $k => $arg) { + if (in_array($arg[0], [Type::T_FUNCTION_CALL]) && in_array($arg[1], ['min', 'max'])) { + if (count($kwargs) > 1 || ($k >= 2 && count($args) === 4)) { + return null; + } + + $args[$k] = $this->stringifyFncallArgs($arg); + } + + if ( + $k >= 2 && count($args) === 4 && + in_array($arg[0], [Type::T_FUNCTION_CALL, Type::T_FUNCTION]) && + in_array($arg[1], ['calc','env']) + ) { + return null; + } + } + + $hue = $this->reduce($args[0]); + $whiteness = $this->reduce($args[1]); + $blackness = $this->reduce($args[2]); + $alpha = null; + + if (\count($args) === 4) { + $alpha = $this->compileColorPartValue($args[3], 0, 1, false); + + if (! \is_numeric($alpha)) { + $val = $this->compileValue($args[3]); + throw $this->error("\$alpha: $val is not a number"); + } + } + + $this->assertNumber($hue, 'hue'); + $this->assertUnit($whiteness, ['%'], 'whiteness'); + $this->assertUnit($blackness, ['%'], 'blackness'); + + $this->assertRange($whiteness, 0, 100, "0% and 100%", "whiteness"); + $this->assertRange($blackness, 0, 100, "0% and 100%", "blackness"); + + $w = $whiteness->getDimension(); + $b = $blackness->getDimension(); + + $hueValue = $hue->getDimension() % 360; + + while ($hueValue < 0) { + $hueValue += 360; + } + + $color = $this->HWBtoRGB($hueValue, $w, $b); + + if (! \is_null($alpha)) { + $color[4] = $alpha; + } + + return $color; + } + + protected static $libWhiteness = ['color']; + protected function libWhiteness($args, $kwargs, $funcName = 'whiteness') { + + $color = $this->assertColor($args[0]); + $hwb = $this->RGBtoHWB($color[1], $color[2], $color[3]); + + return new Number($hwb[2], '%'); + } + + protected static $libBlackness = ['color']; + protected function libBlackness($args, $kwargs, $funcName = 'blackness') { + + $color = $this->assertColor($args[0]); + $hwb = $this->RGBtoHWB($color[1], $color[2], $color[3]); + + return new Number($hwb[3], '%'); + } + */ + + /** + * @param array $color + * @param int $idx + * @param int|float $amount + * + * @return array + */ + protected function adjustHsl($color, $idx, $amount) + { + $hsl = $this->toHSL($color[1], $color[2], $color[3]); + $hsl[$idx] += $amount; + + if ($idx !== 1) { + // Clamp the saturation and lightness + $hsl[$idx] = min(max(0, $hsl[$idx]), 100); + } + + $out = $this->toRGB($hsl[1], $hsl[2], $hsl[3]); + + if (isset($color[4])) { + $out[4] = $color[4]; + } + + return $out; + } + + protected static $libAdjustHue = ['color', 'degrees']; + protected function libAdjustHue($args) + { + $color = $this->assertColor($args[0], 'color'); + $degrees = $this->assertNumber($args[1], 'degrees')->getDimension(); + + return $this->adjustHsl($color, 1, $degrees); + } + + protected static $libLighten = ['color', 'amount']; + protected function libLighten($args) + { + $color = $this->assertColor($args[0], 'color'); + $amount = Util::checkRange('amount', new Range(0, 100), $args[1], '%'); + + return $this->adjustHsl($color, 3, $amount); + } + + protected static $libDarken = ['color', 'amount']; + protected function libDarken($args) + { + $color = $this->assertColor($args[0], 'color'); + $amount = Util::checkRange('amount', new Range(0, 100), $args[1], '%'); + + return $this->adjustHsl($color, 3, -$amount); + } + + protected static $libSaturate = [['color', 'amount'], ['amount']]; + protected function libSaturate($args) + { + $value = $args[0]; + + if (count($args) === 1) { + $this->assertNumber($args[0], 'amount'); + + return null; + } + + $color = $this->assertColor($args[0], 'color'); + $amount = $this->assertNumber($args[1], 'amount'); + + return $this->adjustHsl($color, 2, $amount->valueInRange(0, 100, 'amount')); + } + + protected static $libDesaturate = ['color', 'amount']; + protected function libDesaturate($args) + { + $color = $this->assertColor($args[0], 'color'); + $amount = $this->assertNumber($args[1], 'amount'); + + return $this->adjustHsl($color, 2, -$amount->valueInRange(0, 100, 'amount')); + } + + protected static $libGrayscale = ['color']; + protected function libGrayscale($args) + { + $value = $args[0]; + + if ($value instanceof Number) { + return null; + } + + return $this->adjustHsl($this->assertColor($value, 'color'), 2, -100); + } + + protected static $libComplement = ['color']; + protected function libComplement($args) + { + return $this->adjustHsl($this->assertColor($args[0], 'color'), 1, 180); + } + + protected static $libInvert = ['color', 'weight:100%']; + protected function libInvert($args) + { + $value = $args[0]; + + $weight = $this->assertNumber($args[1], 'weight'); + + if ($value instanceof Number) { + if ($weight->getDimension() != 100 || !$weight->hasUnit('%')) { + throw new SassScriptException('Only one argument may be passed to the plain-CSS invert() function.'); + } + + return null; + } + + $color = $this->assertColor($value, 'color'); + $inverted = $color; + $inverted[1] = 255 - $inverted[1]; + $inverted[2] = 255 - $inverted[2]; + $inverted[3] = 255 - $inverted[3]; + + return $this->libMix([$inverted, $color, $weight]); + } + + // increases opacity by amount + protected static $libOpacify = ['color', 'amount']; + protected function libOpacify($args) + { + $color = $this->assertColor($args[0], 'color'); + $amount = $this->assertNumber($args[1], 'amount'); + + $color[4] = (isset($color[4]) ? $color[4] : 1) + $amount->valueInRangeWithUnit(0, 1, 'amount', ''); + $color[4] = min(1, max(0, $color[4])); + + return $color; + } + + protected static $libFadeIn = ['color', 'amount']; + protected function libFadeIn($args) + { + return $this->libOpacify($args); + } + + // decreases opacity by amount + protected static $libTransparentize = ['color', 'amount']; + protected function libTransparentize($args) + { + $color = $this->assertColor($args[0], 'color'); + $amount = $this->assertNumber($args[1], 'amount'); + + $color[4] = (isset($color[4]) ? $color[4] : 1) - $amount->valueInRangeWithUnit(0, 1, 'amount', ''); + $color[4] = min(1, max(0, $color[4])); + + return $color; + } + + protected static $libFadeOut = ['color', 'amount']; + protected function libFadeOut($args) + { + return $this->libTransparentize($args); + } + + protected static $libUnquote = ['string']; + protected function libUnquote($args) + { + try { + $str = $this->assertString($args[0], 'string'); + } catch (SassScriptException $e) { + $value = $this->compileValue($args[0]); + $fname = $this->getPrettyPath($this->sourceNames[$this->sourceIndex]); + $line = $this->sourceLine; + + $message = "Passing $value, a non-string value, to unquote() +will be an error in future versions of Sass.\n on line $line of $fname"; + + $this->logger->warn($message, true); + + return $args[0]; + } + + $str[1] = ''; + + return $str; + } + + protected static $libQuote = ['string']; + protected function libQuote($args) + { + $value = $this->assertString($args[0], 'string'); + + $value[1] = '"'; + + return $value; + } + + protected static $libPercentage = ['number']; + protected function libPercentage($args) + { + $num = $this->assertNumber($args[0], 'number'); + $num->assertNoUnits('number'); + + return new Number($num->getDimension() * 100, '%'); + } + + protected static $libRound = ['number']; + protected function libRound($args) + { + $num = $this->assertNumber($args[0], 'number'); + + return new Number(round($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); + } + + protected static $libFloor = ['number']; + protected function libFloor($args) + { + $num = $this->assertNumber($args[0], 'number'); + + return new Number(floor($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); + } + + protected static $libCeil = ['number']; + protected function libCeil($args) + { + $num = $this->assertNumber($args[0], 'number'); + + return new Number(ceil($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); + } + + protected static $libAbs = ['number']; + protected function libAbs($args) + { + $num = $this->assertNumber($args[0], 'number'); + + return new Number(abs($num->getDimension()), $num->getNumeratorUnits(), $num->getDenominatorUnits()); + } + + protected static $libMin = ['numbers...']; + protected function libMin($args) + { + /** + * @var Number|null + */ + $min = null; + + foreach ($args[0][2] as $arg) { + $number = $this->assertNumber($arg); + + if (\is_null($min) || $min->greaterThan($number)) { + $min = $number; + } + } + + if (!\is_null($min)) { + return $min; + } + + throw $this->error('At least one argument must be passed.'); + } + + protected static $libMax = ['numbers...']; + protected function libMax($args) + { + /** + * @var Number|null + */ + $max = null; + + foreach ($args[0][2] as $arg) { + $number = $this->assertNumber($arg); + + if (\is_null($max) || $max->lessThan($number)) { + $max = $number; + } + } + + if (!\is_null($max)) { + return $max; + } + + throw $this->error('At least one argument must be passed.'); + } + + protected static $libLength = ['list']; + protected function libLength($args) + { + $list = $this->coerceList($args[0], ',', true); + + return new Number(\count($list[2]), ''); + } + + protected static $libListSeparator = ['list']; + protected function libListSeparator($args) + { + if (! \in_array($args[0][0], [Type::T_LIST, Type::T_MAP])) { + return [Type::T_KEYWORD, 'space']; + } + + $list = $this->coerceList($args[0]); + + if ($list[1] === '' && \count($list[2]) <= 1 && empty($list['enclosing'])) { + return [Type::T_KEYWORD, 'space']; + } + + if ($list[1] === ',') { + return [Type::T_KEYWORD, 'comma']; + } + + if ($list[1] === '/') { + return [Type::T_KEYWORD, 'slash']; + } + + return [Type::T_KEYWORD, 'space']; + } + + protected static $libNth = ['list', 'n']; + protected function libNth($args) + { + $list = $this->coerceList($args[0], ',', false); + $n = $this->assertInteger($args[1]); + + if ($n > 0) { + $n--; + } elseif ($n < 0) { + $n += \count($list[2]); + } + + return isset($list[2][$n]) ? $list[2][$n] : static::$defaultValue; + } + + protected static $libSetNth = ['list', 'n', 'value']; + protected function libSetNth($args) + { + $list = $this->coerceList($args[0]); + $n = $this->assertInteger($args[1]); + + if ($n > 0) { + $n--; + } elseif ($n < 0) { + $n += \count($list[2]); + } + + if (! isset($list[2][$n])) { + throw $this->error('Invalid argument for "n"'); + } + + $list[2][$n] = $args[2]; + + return $list; + } + + protected static $libMapGet = ['map', 'key', 'keys...']; + protected function libMapGet($args) + { + $map = $this->assertMap($args[0], 'map'); + if (!isset($args[2])) { + // BC layer for usages of the function from PHP code rather than from the Sass function + $args[2] = self::$emptyArgumentList; + } + $keys = array_merge([$args[1]], $args[2][2]); + $value = static::$null; + + foreach ($keys as $key) { + if (!\is_array($map) || $map[0] !== Type::T_MAP) { + return static::$null; + } + + $map = $this->mapGet($map, $key); + + if ($map === null) { + return static::$null; + } + + $value = $map; + } + + return $value; + } + + /** + * Gets the value corresponding to that key in the map + * + * @param array $map + * @param Number|array $key + * + * @return Number|array|null + */ + private function mapGet(array $map, $key) + { + $index = $this->mapGetEntryIndex($map, $key); + + if ($index !== null) { + return $map[2][$index]; + } + + return null; + } + + /** + * Gets the index corresponding to that key in the map entries + * + * @param array $map + * @param Number|array $key + * + * @return int|null + */ + private function mapGetEntryIndex(array $map, $key) + { + $key = $this->compileStringContent($this->coerceString($key)); + + for ($i = \count($map[1]) - 1; $i >= 0; $i--) { + if ($key === $this->compileStringContent($this->coerceString($map[1][$i]))) { + return $i; + } + } + + return null; + } + + protected static $libMapKeys = ['map']; + protected function libMapKeys($args) + { + $map = $this->assertMap($args[0], 'map'); + $keys = $map[1]; + + return [Type::T_LIST, ',', $keys]; + } + + protected static $libMapValues = ['map']; + protected function libMapValues($args) + { + $map = $this->assertMap($args[0], 'map'); + $values = $map[2]; + + return [Type::T_LIST, ',', $values]; + } + + protected static $libMapRemove = [ + ['map'], + ['map', 'key', 'keys...'], + ]; + protected function libMapRemove($args) + { + $map = $this->assertMap($args[0], 'map'); + + if (\count($args) === 1) { + return $map; + } + + $keys = []; + $keys[] = $this->compileStringContent($this->coerceString($args[1])); + + foreach ($args[2][2] as $key) { + $keys[] = $this->compileStringContent($this->coerceString($key)); + } + + for ($i = \count($map[1]) - 1; $i >= 0; $i--) { + if (in_array($this->compileStringContent($this->coerceString($map[1][$i])), $keys)) { + array_splice($map[1], $i, 1); + array_splice($map[2], $i, 1); + } + } + + return $map; + } + + protected static $libMapHasKey = ['map', 'key', 'keys...']; + protected function libMapHasKey($args) + { + $map = $this->assertMap($args[0], 'map'); + if (!isset($args[2])) { + // BC layer for usages of the function from PHP code rather than from the Sass function + $args[2] = self::$emptyArgumentList; + } + $keys = array_merge([$args[1]], $args[2][2]); + $lastKey = array_pop($keys); + + foreach ($keys as $key) { + $value = $this->mapGet($map, $key); + + if ($value === null || $value instanceof Number || $value[0] !== Type::T_MAP) { + return self::$false; + } + + $map = $value; + } + + return $this->toBool($this->mapHasKey($map, $lastKey)); + } + + /** + * @param array|Number $keyValue + * + * @return bool + */ + private function mapHasKey(array $map, $keyValue) + { + $key = $this->compileStringContent($this->coerceString($keyValue)); + + for ($i = \count($map[1]) - 1; $i >= 0; $i--) { + if ($key === $this->compileStringContent($this->coerceString($map[1][$i]))) { + return true; + } + } + + return false; + } + + protected static $libMapMerge = [ + ['map1', 'map2'], + ['map-1', 'map-2'], + ['map1', 'args...'] + ]; + protected function libMapMerge($args) + { + $map1 = $this->assertMap($args[0], 'map1'); + $map2 = $args[1]; + $keys = []; + if ($map2[0] === Type::T_LIST && isset($map2[3]) && \is_array($map2[3])) { + // This is an argument list for the variadic signature + if (\count($map2[2]) === 0) { + throw new SassScriptException('Expected $args to contain a key.'); + } + if (\count($map2[2]) === 1) { + throw new SassScriptException('Expected $args to contain a value.'); + } + $keys = $map2[2]; + $map2 = array_pop($keys); + } + $map2 = $this->assertMap($map2, 'map2'); + + return $this->modifyMap($map1, $keys, function ($oldValue) use ($map2) { + $nestedMap = $this->tryMap($oldValue); + + if ($nestedMap === null) { + return $map2; + } + + return $this->mergeMaps($nestedMap, $map2); + }); + } + + /** + * @param array $map + * @param array $keys + * @param callable $modify + * @param bool $addNesting + * + * @return Number|array + * + * @phpstan-param array $keys + * @phpstan-param callable(Number|array): (Number|array) $modify + */ + private function modifyMap(array $map, array $keys, callable $modify, $addNesting = true) + { + if ($keys === []) { + return $modify($map); + } + + return $this->modifyNestedMap($map, $keys, $modify, $addNesting); + } + + /** + * @param array $map + * @param array $keys + * @param callable $modify + * @param bool $addNesting + * + * @return array + * + * @phpstan-param non-empty-array $keys + * @phpstan-param callable(Number|array): (Number|array) $modify + */ + private function modifyNestedMap(array $map, array $keys, callable $modify, $addNesting) + { + $key = array_shift($keys); + + $nestedValueIndex = $this->mapGetEntryIndex($map, $key); + + if ($keys === []) { + if ($nestedValueIndex !== null) { + $map[2][$nestedValueIndex] = $modify($map[2][$nestedValueIndex]); + } else { + $map[1][] = $key; + $map[2][] = $modify(self::$null); + } + + return $map; + } + + $nestedMap = $nestedValueIndex !== null ? $this->tryMap($map[2][$nestedValueIndex]) : null; + + if ($nestedMap === null && !$addNesting) { + return $map; + } + + if ($nestedMap === null) { + $nestedMap = self::$emptyMap; + } + + $newNestedMap = $this->modifyNestedMap($nestedMap, $keys, $modify, $addNesting); + + if ($nestedValueIndex !== null) { + $map[2][$nestedValueIndex] = $newNestedMap; + } else { + $map[1][] = $key; + $map[2][] = $newNestedMap; + } + + return $map; + } + + /** + * Merges 2 Sass maps together + * + * @param array $map1 + * @param array $map2 + * + * @return array + */ + private function mergeMaps(array $map1, array $map2) + { + foreach ($map2[1] as $i2 => $key2) { + $map1EntryIndex = $this->mapGetEntryIndex($map1, $key2); + + if ($map1EntryIndex !== null) { + $map1[2][$map1EntryIndex] = $map2[2][$i2]; + continue; + } + + $map1[1][] = $key2; + $map1[2][] = $map2[2][$i2]; + } + + return $map1; + } + + protected static $libKeywords = ['args']; + protected function libKeywords($args) + { + $value = $args[0]; + + if ($value[0] !== Type::T_LIST || !isset($value[3]) || !\is_array($value[3])) { + $compiledValue = $this->compileValue($value); + + throw SassScriptException::forArgument($compiledValue . ' is not an argument list.', 'args'); + } + + $keys = []; + $values = []; + + foreach ($this->getArgumentListKeywords($value) as $name => $arg) { + $keys[] = [Type::T_KEYWORD, $name]; + $values[] = $arg; + } + + return [Type::T_MAP, $keys, $values]; + } + + protected static $libIsBracketed = ['list']; + protected function libIsBracketed($args) + { + $list = $args[0]; + $this->coerceList($list, ' '); + + if (! empty($list['enclosing']) && $list['enclosing'] === 'bracket') { + return self::$true; + } + + return self::$false; + } + + /** + * @param array $list1 + * @param array|Number|null $sep + * + * @return string + * @throws CompilerException + * + * @deprecated + */ + protected function listSeparatorForJoin($list1, $sep) + { + @trigger_error(sprintf('The "%s" method is deprecated.', __METHOD__), E_USER_DEPRECATED); + + if (! isset($sep)) { + return $list1[1]; + } + + switch ($this->compileValue($sep)) { + case 'comma': + return ','; + + case 'space': + return ' '; + + default: + return $list1[1]; + } + } + + protected static $libJoin = ['list1', 'list2', 'separator:auto', 'bracketed:auto']; + protected function libJoin($args) + { + list($list1, $list2, $sep, $bracketed) = $args; + + $list1 = $this->coerceList($list1, ' ', true); + $list2 = $this->coerceList($list2, ' ', true); + + switch ($this->compileStringContent($this->assertString($sep, 'separator'))) { + case 'comma': + $separator = ','; + break; + + case 'space': + $separator = ' '; + break; + + case 'slash': + $separator = '/'; + break; + + case 'auto': + if ($list1[1] !== '' || count($list1[2]) > 1 || !empty($list1['enclosing']) && $list1['enclosing'] !== 'parent') { + $separator = $list1[1] ?: ' '; + } elseif ($list2[1] !== '' || count($list2[2]) > 1 || !empty($list2['enclosing']) && $list2['enclosing'] !== 'parent') { + $separator = $list2[1] ?: ' '; + } else { + $separator = ' '; + } + break; + + default: + throw SassScriptException::forArgument('Must be "space", "comma", "slash", or "auto".', 'separator'); + } + + if ($bracketed === static::$true) { + $bracketed = true; + } elseif ($bracketed === static::$false) { + $bracketed = false; + } elseif ($bracketed === [Type::T_KEYWORD, 'auto']) { + $bracketed = 'auto'; + } elseif ($bracketed === static::$null) { + $bracketed = false; + } else { + $bracketed = $this->compileValue($bracketed); + $bracketed = ! ! $bracketed; + + if ($bracketed === true) { + $bracketed = true; + } + } + + if ($bracketed === 'auto') { + $bracketed = false; + + if (! empty($list1['enclosing']) && $list1['enclosing'] === 'bracket') { + $bracketed = true; + } + } + + $res = [Type::T_LIST, $separator, array_merge($list1[2], $list2[2])]; + + if ($bracketed) { + $res['enclosing'] = 'bracket'; + } + + return $res; + } + + protected static $libAppend = ['list', 'val', 'separator:auto']; + protected function libAppend($args) + { + list($list1, $value, $sep) = $args; + + $list1 = $this->coerceList($list1, ' ', true); + + switch ($this->compileStringContent($this->assertString($sep, 'separator'))) { + case 'comma': + $separator = ','; + break; + + case 'space': + $separator = ' '; + break; + + case 'slash': + $separator = '/'; + break; + + case 'auto': + $separator = $list1[1] === '' && \count($list1[2]) <= 1 && (empty($list1['enclosing']) || $list1['enclosing'] === 'parent') ? ' ' : $list1[1]; + break; + + default: + throw SassScriptException::forArgument('Must be "space", "comma", "slash", or "auto".', 'separator'); + } + + $res = [Type::T_LIST, $separator, array_merge($list1[2], [$value])]; + + if (isset($list1['enclosing'])) { + $res['enclosing'] = $list1['enclosing']; + } + + return $res; + } + + protected static $libZip = ['lists...']; + protected function libZip($args) + { + $argLists = []; + foreach ($args[0][2] as $arg) { + $argLists[] = $this->coerceList($arg); + } + + $lists = []; + $firstList = array_shift($argLists); + + $result = [Type::T_LIST, ',', $lists]; + if (! \is_null($firstList)) { + foreach ($firstList[2] as $key => $item) { + $list = [Type::T_LIST, ' ', [$item]]; + + foreach ($argLists as $arg) { + if (isset($arg[2][$key])) { + $list[2][] = $arg[2][$key]; + } else { + break 2; + } + } + + $lists[] = $list; + } + + $result[2] = $lists; + } else { + $result['enclosing'] = 'parent'; + } + + return $result; + } + + protected static $libTypeOf = ['value']; + protected function libTypeOf($args) + { + $value = $args[0]; + + return [Type::T_KEYWORD, $this->getTypeOf($value)]; + } + + /** + * @param array|Number $value + * + * @return string + */ + private function getTypeOf($value) + { + switch ($value[0]) { + case Type::T_KEYWORD: + if ($value === static::$true || $value === static::$false) { + return 'bool'; + } + + if ($this->coerceColor($value)) { + return 'color'; + } + + // fall-thru + case Type::T_FUNCTION: + return 'string'; + + case Type::T_FUNCTION_REFERENCE: + return 'function'; + + case Type::T_LIST: + if (isset($value[3]) && \is_array($value[3])) { + return 'arglist'; + } + + // fall-thru + default: + return $value[0]; + } + } + + protected static $libUnit = ['number']; + protected function libUnit($args) + { + $num = $this->assertNumber($args[0], 'number'); + + return [Type::T_STRING, '"', [$num->unitStr()]]; + } + + protected static $libUnitless = ['number']; + protected function libUnitless($args) + { + $value = $this->assertNumber($args[0], 'number'); + + return $this->toBool($value->unitless()); + } + + protected static $libComparable = [ + ['number1', 'number2'], + ['number-1', 'number-2'] + ]; + protected function libComparable($args) + { + list($number1, $number2) = $args; + + if ( + ! $number1 instanceof Number || + ! $number2 instanceof Number + ) { + throw $this->error('Invalid argument(s) for "comparable"'); + } + + return $this->toBool($number1->isComparableTo($number2)); + } + + protected static $libStrIndex = ['string', 'substring']; + protected function libStrIndex($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + $substring = $this->assertString($args[1], 'substring'); + $substringContent = $this->compileStringContent($substring); + + if (! \strlen($substringContent)) { + $result = 0; + } else { + $result = Util::mbStrpos($stringContent, $substringContent); + } + + return $result === false ? static::$null : new Number($result + 1, ''); + } + + protected static $libStrInsert = ['string', 'insert', 'index']; + protected function libStrInsert($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + $insert = $this->assertString($args[1], 'insert'); + $insertContent = $this->compileStringContent($insert); + + $index = $this->assertInteger($args[2], 'index'); + if ($index > 0) { + $index = $index - 1; + } + if ($index < 0) { + $index = max(Util::mbStrlen($stringContent) + 1 + $index, 0); + } + + $string[2] = [ + Util::mbSubstr($stringContent, 0, $index), + $insertContent, + Util::mbSubstr($stringContent, $index) + ]; + + return $string; + } + + protected static $libStrLength = ['string']; + protected function libStrLength($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + return new Number(Util::mbStrlen($stringContent), ''); + } + + protected static $libStrSlice = ['string', 'start-at', 'end-at:-1']; + protected function libStrSlice($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + $start = $this->assertNumber($args[1], 'start-at'); + $start->assertNoUnits('start-at'); + $startInt = $this->assertInteger($start, 'start-at'); + $end = $this->assertNumber($args[2], 'end-at'); + $end->assertNoUnits('end-at'); + $endInt = $this->assertInteger($end, 'end-at'); + + if ($endInt === 0) { + return [Type::T_STRING, $string[1], []]; + } + + if ($startInt > 0) { + $startInt--; + } + + if ($endInt < 0) { + $endInt = Util::mbStrlen($stringContent) + $endInt; + } else { + $endInt--; + } + + if ($endInt < $startInt) { + return [Type::T_STRING, $string[1], []]; + } + + $length = $endInt - $startInt + 1; // The end of the slice is inclusive + + $string[2] = [Util::mbSubstr($stringContent, $startInt, $length)]; + + return $string; + } + + protected static $libToLowerCase = ['string']; + protected function libToLowerCase($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + $string[2] = [$this->stringTransformAsciiOnly($stringContent, 'strtolower')]; + + return $string; + } + + protected static $libToUpperCase = ['string']; + protected function libToUpperCase($args) + { + $string = $this->assertString($args[0], 'string'); + $stringContent = $this->compileStringContent($string); + + $string[2] = [$this->stringTransformAsciiOnly($stringContent, 'strtoupper')]; + + return $string; + } + + /** + * Apply a filter on a string content, only on ascii chars + * let extended chars untouched + * + * @param string $stringContent + * @param callable $filter + * @return string + */ + protected function stringTransformAsciiOnly($stringContent, $filter) + { + $mblength = Util::mbStrlen($stringContent); + if ($mblength === strlen($stringContent)) { + return $filter($stringContent); + } + $filteredString = ""; + for ($i = 0; $i < $mblength; $i++) { + $char = Util::mbSubstr($stringContent, $i, 1); + if (strlen($char) > 1) { + $filteredString .= $char; + } else { + $filteredString .= $filter($char); + } + } + + return $filteredString; + } + + protected static $libFeatureExists = ['feature']; + protected function libFeatureExists($args) + { + $string = $this->assertString($args[0], 'feature'); + $name = $this->compileStringContent($string); + + return $this->toBool( + \array_key_exists($name, $this->registeredFeatures) ? $this->registeredFeatures[$name] : false + ); + } + + protected static $libFunctionExists = ['name']; + protected function libFunctionExists($args) + { + $string = $this->assertString($args[0], 'name'); + $name = $this->compileStringContent($string); + + // user defined functions + if ($this->has(static::$namespaces['function'] . $name)) { + return self::$true; + } + + $name = $this->normalizeName($name); + + if (isset($this->userFunctions[$name])) { + return self::$true; + } + + // built-in functions + $f = $this->getBuiltinFunction($name); + + return $this->toBool(\is_callable($f)); + } + + protected static $libGlobalVariableExists = ['name']; + protected function libGlobalVariableExists($args) + { + $string = $this->assertString($args[0], 'name'); + $name = $this->compileStringContent($string); + + return $this->toBool($this->has($name, $this->rootEnv)); + } + + protected static $libMixinExists = ['name']; + protected function libMixinExists($args) + { + $string = $this->assertString($args[0], 'name'); + $name = $this->compileStringContent($string); + + return $this->toBool($this->has(static::$namespaces['mixin'] . $name)); + } + + protected static $libVariableExists = ['name']; + protected function libVariableExists($args) + { + $string = $this->assertString($args[0], 'name'); + $name = $this->compileStringContent($string); + + return $this->toBool($this->has($name)); + } + + protected static $libCounter = ['args...']; + /** + * Workaround IE7's content counter bug. + * + * @param array $args + * + * @return array + */ + protected function libCounter($args) + { + $list = array_map([$this, 'compileValue'], $args[0][2]); + + return [Type::T_STRING, '', ['counter(' . implode(',', $list) . ')']]; + } + + protected static $libRandom = ['limit:null']; + protected function libRandom($args) + { + if (isset($args[0]) && $args[0] !== static::$null) { + $limit = $this->assertNumber($args[0], 'limit'); + + if ($limit->hasUnits()) { + $unitString = $limit->unitStr(); + $message = <<addLocationToMessage($message)); + } + + $n = $this->assertInteger($limit, 'limit'); + + if ($n < 1) { + throw new SassScriptException("\$limit: Must be greater than 0, was $n."); + } + + return new Number(mt_rand(1, $n), ''); + } + + $max = mt_getrandmax(); + return new Number(mt_rand(0, $max - 1) / $max, ''); + } + + protected static $libUniqueId = []; + protected function libUniqueId() + { + static $id; + + if (! isset($id)) { + $id = PHP_INT_SIZE === 4 + ? mt_rand(0, pow(36, 5)) . str_pad(mt_rand(0, pow(36, 5)) % 10000000, 7, '0', STR_PAD_LEFT) + : mt_rand(0, pow(36, 8)); + } + + $id += mt_rand(0, 10) + 1; + + return [Type::T_STRING, '', ['u' . str_pad(base_convert($id, 10, 36), 8, '0', STR_PAD_LEFT)]]; + } + + /** + * @param array|Number $value + * @param bool $force_enclosing_display + * + * @return array + */ + protected function inspectFormatValue($value, $force_enclosing_display = false) + { + if ($value === static::$null) { + $value = [Type::T_KEYWORD, 'null']; + } + + $stringValue = [$value]; + + if ($value instanceof Number) { + return [Type::T_STRING, '', $stringValue]; + } + + if ($value[0] === Type::T_LIST) { + if (end($value[2]) === static::$null) { + array_pop($value[2]); + $value[2][] = [Type::T_STRING, '', ['']]; + $force_enclosing_display = true; + } + + if ( + ! empty($value['enclosing']) && + ($force_enclosing_display || + ($value['enclosing'] === 'bracket') || + ! \count($value[2])) + ) { + $value['enclosing'] = 'forced_' . $value['enclosing']; + $force_enclosing_display = true; + } elseif (! \count($value[2])) { + $value['enclosing'] = 'forced_parent'; + } + + foreach ($value[2] as $k => $listelement) { + $value[2][$k] = $this->inspectFormatValue($listelement, $force_enclosing_display); + } + + $stringValue = [$value]; + } + + return [Type::T_STRING, '', $stringValue]; + } + + protected static $libInspect = ['value']; + protected function libInspect($args) + { + $value = $args[0]; + + return $this->inspectFormatValue($value); + } + + /** + * Preprocess selector args + * + * @param array $arg + * @param string|null $varname + * @param bool $allowParent + * + * @return array + */ + protected function getSelectorArg($arg, $varname = null, $allowParent = false) + { + static $parser = null; + + if (\is_null($parser)) { + $parser = $this->parserFactory(__METHOD__); + } + + if (! $this->checkSelectorArgType($arg)) { + $var_value = $this->compileValue($arg); + throw SassScriptException::forArgument("$var_value is not a valid selector: it must be a string, a list of strings, or a list of lists of strings", $varname); + } + + + if ($arg[0] === Type::T_STRING) { + $arg[1] = ''; + } + $arg = $this->compileValue($arg); + + $parsedSelector = []; + + if ($parser->parseSelector($arg, $parsedSelector, true)) { + $selector = $this->evalSelectors($parsedSelector); + $gluedSelector = $this->glueFunctionSelectors($selector); + + if (! $allowParent) { + foreach ($gluedSelector as $selector) { + foreach ($selector as $s) { + if (in_array(static::$selfSelector, $s)) { + throw SassScriptException::forArgument("Parent selectors aren't allowed here.", $varname); + } + } + } + } + + return $gluedSelector; + } + + throw SassScriptException::forArgument("expected more input, invalid selector.", $varname); + } + + /** + * Check variable type for getSelectorArg() function + * @param array $arg + * @param int $maxDepth + * @return bool + */ + protected function checkSelectorArgType($arg, $maxDepth = 2) + { + if ($arg[0] === Type::T_LIST && $maxDepth > 0) { + foreach ($arg[2] as $elt) { + if (! $this->checkSelectorArgType($elt, $maxDepth - 1)) { + return false; + } + } + return true; + } + if (!in_array($arg[0], [Type::T_STRING, Type::T_KEYWORD])) { + return false; + } + return true; + } + + /** + * Postprocess selector to output in right format + * + * @param array $selectors + * + * @return array + */ + protected function formatOutputSelector($selectors) + { + $selectors = $this->collapseSelectorsAsList($selectors); + + return $selectors; + } + + protected static $libIsSuperselector = ['super', 'sub']; + protected function libIsSuperselector($args) + { + list($super, $sub) = $args; + + $super = $this->getSelectorArg($super, 'super'); + $sub = $this->getSelectorArg($sub, 'sub'); + + return $this->toBool($this->isSuperSelector($super, $sub)); + } + + /** + * Test a $super selector again $sub + * + * @param array $super + * @param array $sub + * + * @return bool + */ + protected function isSuperSelector($super, $sub) + { + // one and only one selector for each arg + if (! $super) { + throw $this->error('Invalid super selector for isSuperSelector()'); + } + + if (! $sub) { + throw $this->error('Invalid sub selector for isSuperSelector()'); + } + + if (count($sub) > 1) { + foreach ($sub as $s) { + if (! $this->isSuperSelector($super, [$s])) { + return false; + } + } + return true; + } + + if (count($super) > 1) { + foreach ($super as $s) { + if ($this->isSuperSelector([$s], $sub)) { + return true; + } + } + return false; + } + + $super = reset($super); + $sub = reset($sub); + + $i = 0; + $nextMustMatch = false; + + foreach ($super as $node) { + $compound = ''; + + array_walk_recursive( + $node, + function ($value, $key) use (&$compound) { + $compound .= $value; + } + ); + + if ($this->isImmediateRelationshipCombinator($compound)) { + if ($node !== $sub[$i]) { + return false; + } + + $nextMustMatch = true; + $i++; + } else { + while ($i < \count($sub) && ! $this->isSuperPart($node, $sub[$i])) { + if ($nextMustMatch) { + return false; + } + + $i++; + } + + if ($i >= \count($sub)) { + return false; + } + + $nextMustMatch = false; + $i++; + } + } + + return true; + } + + /** + * Test a part of super selector again a part of sub selector + * + * @param array $superParts + * @param array $subParts + * + * @return bool + */ + protected function isSuperPart($superParts, $subParts) + { + $i = 0; + + foreach ($superParts as $superPart) { + while ($i < \count($subParts) && $subParts[$i] !== $superPart) { + $i++; + } + + if ($i >= \count($subParts)) { + return false; + } + + $i++; + } + + return true; + } + + protected static $libSelectorAppend = ['selector...']; + protected function libSelectorAppend($args) + { + // get the selector... list + $args = reset($args); + $args = $args[2]; + + if (\count($args) < 1) { + throw $this->error('selector-append() needs at least 1 argument'); + } + + $selectors = []; + foreach ($args as $arg) { + $selectors[] = $this->getSelectorArg($arg, 'selector'); + } + + return $this->formatOutputSelector($this->selectorAppend($selectors)); + } + + /** + * Append parts of the last selector in the list to the previous, recursively + * + * @param array $selectors + * + * @return array + * + * @throws \ScssPhp\ScssPhp\Exception\CompilerException + */ + protected function selectorAppend($selectors) + { + $lastSelectors = array_pop($selectors); + + if (! $lastSelectors) { + throw $this->error('Invalid selector list in selector-append()'); + } + + while (\count($selectors)) { + $previousSelectors = array_pop($selectors); + + if (! $previousSelectors) { + throw $this->error('Invalid selector list in selector-append()'); + } + + // do the trick, happening $lastSelector to $previousSelector + $appended = []; + + foreach ($previousSelectors as $previousSelector) { + foreach ($lastSelectors as $lastSelector) { + $previous = $previousSelector; + foreach ($previousSelector as $j => $previousSelectorParts) { + foreach ($lastSelector as $lastSelectorParts) { + foreach ($lastSelectorParts as $lastSelectorPart) { + $previous[$j][] = $lastSelectorPart; + } + } + } + + $appended[] = $previous; + } + } + + $lastSelectors = $appended; + } + + return $lastSelectors; + } + + protected static $libSelectorExtend = [ + ['selector', 'extendee', 'extender'], + ['selectors', 'extendee', 'extender'] + ]; + protected function libSelectorExtend($args) + { + list($selectors, $extendee, $extender) = $args; + + $selectors = $this->getSelectorArg($selectors, 'selector'); + $extendee = $this->getSelectorArg($extendee, 'extendee'); + $extender = $this->getSelectorArg($extender, 'extender'); + + if (! $selectors || ! $extendee || ! $extender) { + throw $this->error('selector-extend() invalid arguments'); + } + + $extended = $this->extendOrReplaceSelectors($selectors, $extendee, $extender); + + return $this->formatOutputSelector($extended); + } + + protected static $libSelectorReplace = [ + ['selector', 'original', 'replacement'], + ['selectors', 'original', 'replacement'] + ]; + protected function libSelectorReplace($args) + { + list($selectors, $original, $replacement) = $args; + + $selectors = $this->getSelectorArg($selectors, 'selector'); + $original = $this->getSelectorArg($original, 'original'); + $replacement = $this->getSelectorArg($replacement, 'replacement'); + + if (! $selectors || ! $original || ! $replacement) { + throw $this->error('selector-replace() invalid arguments'); + } + + $replaced = $this->extendOrReplaceSelectors($selectors, $original, $replacement, true); + + return $this->formatOutputSelector($replaced); + } + + /** + * Extend/replace in selectors + * used by selector-extend and selector-replace that use the same logic + * + * @param array $selectors + * @param array $extendee + * @param array $extender + * @param bool $replace + * + * @return array + */ + protected function extendOrReplaceSelectors($selectors, $extendee, $extender, $replace = false) + { + $saveExtends = $this->extends; + $saveExtendsMap = $this->extendsMap; + + $this->extends = []; + $this->extendsMap = []; + + foreach ($extendee as $es) { + if (\count($es) !== 1) { + throw $this->error('Can\'t extend complex selector.'); + } + + // only use the first one + $this->pushExtends(reset($es), $extender, null); + } + + $extended = []; + + foreach ($selectors as $selector) { + if (! $replace) { + $extended[] = $selector; + } + + $n = \count($extended); + + $this->matchExtends($selector, $extended); + + // if didnt match, keep the original selector if we are in a replace operation + if ($replace && \count($extended) === $n) { + $extended[] = $selector; + } + } + + $this->extends = $saveExtends; + $this->extendsMap = $saveExtendsMap; + + return $extended; + } + + protected static $libSelectorNest = ['selector...']; + protected function libSelectorNest($args) + { + // get the selector... list + $args = reset($args); + $args = $args[2]; + + if (\count($args) < 1) { + throw $this->error('selector-nest() needs at least 1 argument'); + } + + $selectorsMap = []; + foreach ($args as $arg) { + $selectorsMap[] = $this->getSelectorArg($arg, 'selector', true); + } + + assert(!empty($selectorsMap)); + + $envs = []; + + foreach ($selectorsMap as $selectors) { + $env = new Environment(); + $env->selectors = $selectors; + + $envs[] = $env; + } + + $envs = array_reverse($envs); + $env = $this->extractEnv($envs); + $outputSelectors = $this->multiplySelectors($env); + + return $this->formatOutputSelector($outputSelectors); + } + + protected static $libSelectorParse = [ + ['selector'], + ['selectors'] + ]; + protected function libSelectorParse($args) + { + $selectors = reset($args); + $selectors = $this->getSelectorArg($selectors, 'selector'); + + return $this->formatOutputSelector($selectors); + } + + protected static $libSelectorUnify = ['selectors1', 'selectors2']; + protected function libSelectorUnify($args) + { + list($selectors1, $selectors2) = $args; + + $selectors1 = $this->getSelectorArg($selectors1, 'selectors1'); + $selectors2 = $this->getSelectorArg($selectors2, 'selectors2'); + + if (! $selectors1 || ! $selectors2) { + throw $this->error('selector-unify() invalid arguments'); + } + + // only consider the first compound of each + $compound1 = reset($selectors1); + $compound2 = reset($selectors2); + + // unify them and that's it + $unified = $this->unifyCompoundSelectors($compound1, $compound2); + + return $this->formatOutputSelector($unified); + } + + /** + * The selector-unify magic as its best + * (at least works as expected on test cases) + * + * @param array $compound1 + * @param array $compound2 + * + * @return array + */ + protected function unifyCompoundSelectors($compound1, $compound2) + { + if (! \count($compound1)) { + return $compound2; + } + + if (! \count($compound2)) { + return $compound1; + } + + // check that last part are compatible + $lastPart1 = array_pop($compound1); + $lastPart2 = array_pop($compound2); + $last = $this->mergeParts($lastPart1, $lastPart2); + + if (! $last) { + return [[]]; + } + + $unifiedCompound = [$last]; + $unifiedSelectors = [$unifiedCompound]; + + // do the rest + while (\count($compound1) || \count($compound2)) { + $part1 = end($compound1); + $part2 = end($compound2); + + if ($part1 && ($match2 = $this->matchPartInCompound($part1, $compound2))) { + list($compound2, $part2, $after2) = $match2; + + if ($after2) { + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, $after2); + } + + $c = $this->mergeParts($part1, $part2); + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, [$c]); + + $part1 = $part2 = null; + + array_pop($compound1); + } + + if ($part2 && ($match1 = $this->matchPartInCompound($part2, $compound1))) { + list($compound1, $part1, $after1) = $match1; + + if ($after1) { + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, $after1); + } + + $c = $this->mergeParts($part2, $part1); + $unifiedSelectors = $this->prependSelectors($unifiedSelectors, [$c]); + + $part1 = $part2 = null; + + array_pop($compound2); + } + + $new = []; + + if ($part1 && $part2) { + array_pop($compound1); + array_pop($compound2); + + $s = $this->prependSelectors($unifiedSelectors, [$part2]); + $new = array_merge($new, $this->prependSelectors($s, [$part1])); + $s = $this->prependSelectors($unifiedSelectors, [$part1]); + $new = array_merge($new, $this->prependSelectors($s, [$part2])); + } elseif ($part1) { + array_pop($compound1); + + $new = array_merge($new, $this->prependSelectors($unifiedSelectors, [$part1])); + } elseif ($part2) { + array_pop($compound2); + + $new = array_merge($new, $this->prependSelectors($unifiedSelectors, [$part2])); + } + + if ($new) { + $unifiedSelectors = $new; + } + } + + return $unifiedSelectors; + } + + /** + * Prepend each selector from $selectors with $parts + * + * @param array $selectors + * @param array $parts + * + * @return array + */ + protected function prependSelectors($selectors, $parts) + { + $new = []; + + foreach ($selectors as $compoundSelector) { + array_unshift($compoundSelector, $parts); + + $new[] = $compoundSelector; + } + + return $new; + } + + /** + * Try to find a matching part in a compound: + * - with same html tag name + * - with some class or id or something in common + * + * @param array $part + * @param array $compound + * + * @return array|false + */ + protected function matchPartInCompound($part, $compound) + { + $partTag = $this->findTagName($part); + $before = $compound; + $after = []; + + // try to find a match by tag name first + while (\count($before)) { + $p = array_pop($before); + + if ($partTag && $partTag !== '*' && $partTag == $this->findTagName($p)) { + return [$before, $p, $after]; + } + + $after[] = $p; + } + + // try again matching a non empty intersection and a compatible tagname + $before = $compound; + $after = []; + + while (\count($before)) { + $p = array_pop($before); + + if ($this->checkCompatibleTags($partTag, $this->findTagName($p))) { + if (\count(array_intersect($part, $p))) { + return [$before, $p, $after]; + } + } + + $after[] = $p; + } + + return false; + } + + /** + * Merge two part list taking care that + * - the html tag is coming first - if any + * - the :something are coming last + * + * @param array $parts1 + * @param array $parts2 + * + * @return array + */ + protected function mergeParts($parts1, $parts2) + { + $tag1 = $this->findTagName($parts1); + $tag2 = $this->findTagName($parts2); + $tag = $this->checkCompatibleTags($tag1, $tag2); + + // not compatible tags + if ($tag === false) { + return []; + } + + if ($tag) { + if ($tag1) { + $parts1 = array_diff($parts1, [$tag1]); + } + + if ($tag2) { + $parts2 = array_diff($parts2, [$tag2]); + } + } + + $mergedParts = array_merge($parts1, $parts2); + $mergedOrderedParts = []; + + foreach ($mergedParts as $part) { + if (strpos($part, ':') === 0) { + $mergedOrderedParts[] = $part; + } + } + + $mergedParts = array_diff($mergedParts, $mergedOrderedParts); + $mergedParts = array_merge($mergedParts, $mergedOrderedParts); + + if ($tag) { + array_unshift($mergedParts, $tag); + } + + return $mergedParts; + } + + /** + * Check the compatibility between two tag names: + * if both are defined they should be identical or one has to be '*' + * + * @param string $tag1 + * @param string $tag2 + * + * @return array|false + */ + protected function checkCompatibleTags($tag1, $tag2) + { + $tags = [$tag1, $tag2]; + $tags = array_unique($tags); + $tags = array_filter($tags); + + if (\count($tags) > 1) { + $tags = array_diff($tags, ['*']); + } + + // not compatible nodes + if (\count($tags) > 1) { + return false; + } + + return $tags; + } + + /** + * Find the html tag name in a selector parts list + * + * @param string[] $parts + * + * @return string + */ + protected function findTagName($parts) + { + foreach ($parts as $part) { + if (! preg_match('/^[\[.:#%_-]/', $part)) { + return $part; + } + } + + return ''; + } + + protected static $libSimpleSelectors = ['selector']; + protected function libSimpleSelectors($args) + { + $selector = reset($args); + $selector = $this->getSelectorArg($selector, 'selector'); + + // remove selectors list layer, keeping the first one + $selector = reset($selector); + + // remove parts list layer, keeping the first part + $part = reset($selector); + + $listParts = []; + + foreach ($part as $p) { + $listParts[] = [Type::T_STRING, '', [$p]]; + } + + return [Type::T_LIST, ',', $listParts]; + } + + protected static $libScssphpGlob = ['pattern']; + protected function libScssphpGlob($args) + { + @trigger_error(sprintf('The "scssphp-glob" function is deprecated an will be removed in ScssPhp 2.0. Register your own alternative through "%s::registerFunction', __CLASS__), E_USER_DEPRECATED); + + $this->logger->warn('The "scssphp-glob" function is deprecated an will be removed in ScssPhp 2.0.', true); + + $string = $this->assertString($args[0], 'pattern'); + $pattern = $this->compileStringContent($string); + $matches = glob($pattern); + $listParts = []; + + foreach ($matches as $match) { + if (! is_file($match)) { + continue; + } + + $listParts[] = [Type::T_STRING, '"', [$match]]; + } + + return [Type::T_LIST, ',', $listParts]; + } +} diff --git a/rules/scssphp/src/Compiler/CachedResult.php b/rules/scssphp/src/Compiler/CachedResult.php new file mode 100644 index 0000000..a662919 --- /dev/null +++ b/rules/scssphp/src/Compiler/CachedResult.php @@ -0,0 +1,77 @@ + + */ + private $parsedFiles; + + /** + * @var array + * @phpstan-var list + */ + private $resolvedImports; + + /** + * @param CompilationResult $result + * @param array $parsedFiles + * @param array $resolvedImports + * + * @phpstan-param list $resolvedImports + */ + public function __construct(CompilationResult $result, array $parsedFiles, array $resolvedImports) + { + $this->result = $result; + $this->parsedFiles = $parsedFiles; + $this->resolvedImports = $resolvedImports; + } + + /** + * @return CompilationResult + */ + public function getResult() + { + return $this->result; + } + + /** + * @return array + */ + public function getParsedFiles() + { + return $this->parsedFiles; + } + + /** + * @return array + * + * @phpstan-return list + */ + public function getResolvedImports() + { + return $this->resolvedImports; + } +} diff --git a/rules/scssphp/src/Compiler/Environment.php b/rules/scssphp/src/Compiler/Environment.php new file mode 100644 index 0000000..b205a07 --- /dev/null +++ b/rules/scssphp/src/Compiler/Environment.php @@ -0,0 +1,68 @@ + + * + * @internal + */ +class Environment +{ + /** + * @var \ScssPhp\ScssPhp\Block|null + */ + public $block; + + /** + * @var \ScssPhp\ScssPhp\Compiler\Environment|null + */ + public $parent; + + /** + * @var Environment|null + */ + public $declarationScopeParent; + + /** + * @var Environment|null + */ + public $parentStore; + + /** + * @var array|null + */ + public $selectors; + + /** + * @var string|null + */ + public $marker; + + /** + * @var array + */ + public $store; + + /** + * @var array + */ + public $storeUnreduced; + + /** + * @var int + */ + public $depth; +} diff --git a/rules/scssphp/src/Exception/CompilerException.php b/rules/scssphp/src/Exception/CompilerException.php new file mode 100644 index 0000000..0b00cf5 --- /dev/null +++ b/rules/scssphp/src/Exception/CompilerException.php @@ -0,0 +1,24 @@ + + * + * @internal + */ +class CompilerException extends \Exception implements SassException +{ +} diff --git a/rules/scssphp/src/Exception/ParserException.php b/rules/scssphp/src/Exception/ParserException.php new file mode 100644 index 0000000..f072669 --- /dev/null +++ b/rules/scssphp/src/Exception/ParserException.php @@ -0,0 +1,58 @@ + + * + * @internal + */ +class ParserException extends \Exception implements SassException +{ + /** + * @var array|null + * @phpstan-var array{string, int, int}|null + */ + private $sourcePosition; + + /** + * Get source position + * + * @api + * + * @return array|null + * @phpstan-return array{string, int, int}|null + */ + public function getSourcePosition() + { + return $this->sourcePosition; + } + + /** + * Set source position + * + * @api + * + * @param array $sourcePosition + * + * @return void + * + * @phpstan-param array{string, int, int} $sourcePosition + */ + public function setSourcePosition($sourcePosition) + { + $this->sourcePosition = $sourcePosition; + } +} diff --git a/rules/scssphp/src/Exception/RangeException.php b/rules/scssphp/src/Exception/RangeException.php new file mode 100644 index 0000000..4be4dee --- /dev/null +++ b/rules/scssphp/src/Exception/RangeException.php @@ -0,0 +1,24 @@ + + * + * @internal + */ +class RangeException extends \Exception implements SassException +{ +} diff --git a/rules/scssphp/src/Exception/SassException.php b/rules/scssphp/src/Exception/SassException.php new file mode 100644 index 0000000..9f62b3c --- /dev/null +++ b/rules/scssphp/src/Exception/SassException.php @@ -0,0 +1,7 @@ + + * + * @deprecated The Scssphp server should define its own exception instead. + */ +class ServerException extends \Exception implements SassException +{ +} diff --git a/rules/scssphp/src/Formatter.php b/rules/scssphp/src/Formatter.php new file mode 100644 index 0000000..6137dc6 --- /dev/null +++ b/rules/scssphp/src/Formatter.php @@ -0,0 +1,377 @@ + + * + * @internal + */ +abstract class Formatter +{ + /** + * @var int + */ + public $indentLevel; + + /** + * @var string + */ + public $indentChar; + + /** + * @var string + */ + public $break; + + /** + * @var string + */ + public $open; + + /** + * @var string + */ + public $close; + + /** + * @var string + */ + public $tagSeparator; + + /** + * @var string + */ + public $assignSeparator; + + /** + * @var bool + */ + public $keepSemicolons; + + /** + * @var \ScssPhp\ScssPhp\Formatter\OutputBlock + */ + protected $currentBlock; + + /** + * @var int + */ + protected $currentLine; + + /** + * @var int + */ + protected $currentColumn; + + /** + * @var \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator|null + */ + protected $sourceMapGenerator; + + /** + * @var string + */ + protected $strippedSemicolon; + + /** + * Initialize formatter + * + * @api + */ + abstract public function __construct(); + + /** + * Return indentation (whitespace) + * + * @return string + */ + protected function indentStr() + { + return ''; + } + + /** + * Return property assignment + * + * @api + * + * @param string $name + * @param mixed $value + * + * @return string + */ + public function property($name, $value) + { + return rtrim($name) . $this->assignSeparator . $value . ';'; + } + + /** + * Return custom property assignment + * differs in that you have to keep spaces in the value as is + * + * @api + * + * @param string $name + * @param mixed $value + * + * @return string + */ + public function customProperty($name, $value) + { + return rtrim($name) . trim($this->assignSeparator) . $value . ';'; + } + + /** + * Output lines inside a block + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return void + */ + protected function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + $glue = $this->break . $inner; + + $this->write($inner . implode($glue, $block->lines)); + + if (! empty($block->children)) { + $this->write($this->break); + } + } + + /** + * Output block selectors + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return void + */ + protected function blockSelectors(OutputBlock $block) + { + assert(! empty($block->selectors)); + + $inner = $this->indentStr(); + + $this->write($inner + . implode($this->tagSeparator, $block->selectors) + . $this->open . $this->break); + } + + /** + * Output block children + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return void + */ + protected function blockChildren(OutputBlock $block) + { + foreach ($block->children as $child) { + $this->block($child); + } + } + + /** + * Output non-empty block + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return void + */ + protected function block(OutputBlock $block) + { + if (empty($block->lines) && empty($block->children)) { + return; + } + + $this->currentBlock = $block; + + $pre = $this->indentStr(); + + if (! empty($block->selectors)) { + $this->blockSelectors($block); + + $this->indentLevel++; + } + + if (! empty($block->lines)) { + $this->blockLines($block); + } + + if (! empty($block->children)) { + $this->blockChildren($block); + } + + if (! empty($block->selectors)) { + $this->indentLevel--; + + if (! $this->keepSemicolons) { + $this->strippedSemicolon = ''; + } + + if (empty($block->children)) { + $this->write($this->break); + } + + $this->write($pre . $this->close . $this->break); + } + } + + /** + * Test and clean safely empty children + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return bool + */ + protected function testEmptyChildren($block) + { + $isEmpty = empty($block->lines); + + if ($block->children) { + foreach ($block->children as $k => &$child) { + if (! $this->testEmptyChildren($child)) { + $isEmpty = false; + continue; + } + + if ($child->type === Type::T_MEDIA || $child->type === Type::T_DIRECTIVE) { + $child->children = []; + $child->selectors = null; + } + } + } + + return $isEmpty; + } + + /** + * Entry point to formatting a block + * + * @api + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block An abstract syntax tree + * @param \ScssPhp\ScssPhp\SourceMap\SourceMapGenerator|null $sourceMapGenerator Optional source map generator + * + * @return string + */ + public function format(OutputBlock $block, SourceMapGenerator $sourceMapGenerator = null) + { + $this->sourceMapGenerator = null; + + if ($sourceMapGenerator) { + $this->currentLine = 1; + $this->currentColumn = 0; + $this->sourceMapGenerator = $sourceMapGenerator; + } + + $this->testEmptyChildren($block); + + ob_start(); + + try { + $this->block($block); + } catch (\Exception $e) { + ob_end_clean(); + throw $e; + } catch (\Throwable $e) { + ob_end_clean(); + throw $e; + } + + $out = ob_get_clean(); + assert($out !== false); + + return $out; + } + + /** + * Output content + * + * @param string $str + * + * @return void + */ + protected function write($str) + { + if (! empty($this->strippedSemicolon)) { + echo $this->strippedSemicolon; + + $this->strippedSemicolon = ''; + } + + /* + * Maybe Strip semi-colon appended by property(); it's a separator, not a terminator + * will be striped for real before a closing, otherwise displayed unchanged starting the next write + */ + if ( + ! $this->keepSemicolons && + $str && + (strpos($str, ';') !== false) && + (substr($str, -1) === ';') + ) { + $str = substr($str, 0, -1); + + $this->strippedSemicolon = ';'; + } + + if ($this->sourceMapGenerator) { + $lines = explode("\n", $str); + $lastLine = array_pop($lines); + + foreach ($lines as $line) { + // If the written line starts is empty, adding a mapping would add it for + // a non-existent column as we are at the end of the line + if ($line !== '') { + assert($this->currentBlock->sourceLine !== null); + assert($this->currentBlock->sourceName !== null); + $this->sourceMapGenerator->addMapping( + $this->currentLine, + $this->currentColumn, + $this->currentBlock->sourceLine, + //columns from parser are off by one + $this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0, + $this->currentBlock->sourceName + ); + } + + $this->currentLine++; + $this->currentColumn = 0; + } + + if ($lastLine !== '') { + assert($this->currentBlock->sourceLine !== null); + assert($this->currentBlock->sourceName !== null); + $this->sourceMapGenerator->addMapping( + $this->currentLine, + $this->currentColumn, + $this->currentBlock->sourceLine, + //columns from parser are off by one + $this->currentBlock->sourceColumn > 0 ? $this->currentBlock->sourceColumn - 1 : 0, + $this->currentBlock->sourceName + ); + } + + $this->currentColumn += \strlen($lastLine); + } + + echo $str; + } +} diff --git a/rules/scssphp/src/Formatter/Compact.php b/rules/scssphp/src/Formatter/Compact.php new file mode 100644 index 0000000..22f2268 --- /dev/null +++ b/rules/scssphp/src/Formatter/Compact.php @@ -0,0 +1,52 @@ + + * + * @deprecated since 1.4.0. Use the Compressed formatter instead. + * + * @internal + */ +class Compact extends Formatter +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + @trigger_error('The Compact formatter is deprecated since 1.4.0. Use the Compressed formatter instead.', E_USER_DEPRECATED); + + $this->indentLevel = 0; + $this->indentChar = ''; + $this->break = ''; + $this->open = ' {'; + $this->close = "}\n\n"; + $this->tagSeparator = ','; + $this->assignSeparator = ':'; + $this->keepSemicolons = true; + } + + /** + * {@inheritdoc} + */ + public function indentStr() + { + return ' '; + } +} diff --git a/rules/scssphp/src/Formatter/Compressed.php b/rules/scssphp/src/Formatter/Compressed.php new file mode 100644 index 0000000..58ebe3f --- /dev/null +++ b/rules/scssphp/src/Formatter/Compressed.php @@ -0,0 +1,83 @@ + + * + * @internal + */ +class Compressed extends Formatter +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = ''; + $this->open = '{'; + $this->close = '}'; + $this->tagSeparator = ','; + $this->assignSeparator = ':'; + $this->keepSemicolons = false; + } + + /** + * {@inheritdoc} + */ + public function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + + $glue = $this->break . $inner; + + foreach ($block->lines as $index => $line) { + if (substr($line, 0, 2) === '/*' && substr($line, 2, 1) !== '!') { + unset($block->lines[$index]); + } + } + + $this->write($inner . implode($glue, $block->lines)); + + if (! empty($block->children)) { + $this->write($this->break); + } + } + + /** + * Output block selectors + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + */ + protected function blockSelectors(OutputBlock $block) + { + assert(! empty($block->selectors)); + + $inner = $this->indentStr(); + + $this->write( + $inner + . implode( + $this->tagSeparator, + str_replace([' > ', ' + ', ' ~ '], ['>', '+', '~'], $block->selectors) + ) + . $this->open . $this->break + ); + } +} diff --git a/rules/scssphp/src/Formatter/Crunched.php b/rules/scssphp/src/Formatter/Crunched.php new file mode 100644 index 0000000..2bc1e92 --- /dev/null +++ b/rules/scssphp/src/Formatter/Crunched.php @@ -0,0 +1,87 @@ + + * + * @deprecated since 1.4.0. Use the Compressed formatter instead. + * + * @internal + */ +class Crunched extends Formatter +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + @trigger_error('The Crunched formatter is deprecated since 1.4.0. Use the Compressed formatter instead.', E_USER_DEPRECATED); + + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = ''; + $this->open = '{'; + $this->close = '}'; + $this->tagSeparator = ','; + $this->assignSeparator = ':'; + $this->keepSemicolons = false; + } + + /** + * {@inheritdoc} + */ + public function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + + $glue = $this->break . $inner; + + foreach ($block->lines as $index => $line) { + if (substr($line, 0, 2) === '/*') { + unset($block->lines[$index]); + } + } + + $this->write($inner . implode($glue, $block->lines)); + + if (! empty($block->children)) { + $this->write($this->break); + } + } + + /** + * Output block selectors + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + */ + protected function blockSelectors(OutputBlock $block) + { + assert(! empty($block->selectors)); + + $inner = $this->indentStr(); + + $this->write( + $inner + . implode( + $this->tagSeparator, + str_replace([' > ', ' + ', ' ~ '], ['>', '+', '~'], $block->selectors) + ) + . $this->open . $this->break + ); + } +} diff --git a/rules/scssphp/src/Formatter/Debug.php b/rules/scssphp/src/Formatter/Debug.php new file mode 100644 index 0000000..b3f4422 --- /dev/null +++ b/rules/scssphp/src/Formatter/Debug.php @@ -0,0 +1,127 @@ + + * + * @deprecated since 1.4.0. + * + * @internal + */ +class Debug extends Formatter +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + @trigger_error('The Debug formatter is deprecated since 1.4.0.', E_USER_DEPRECATED); + + $this->indentLevel = 0; + $this->indentChar = ''; + $this->break = "\n"; + $this->open = ' {'; + $this->close = ' }'; + $this->tagSeparator = ', '; + $this->assignSeparator = ': '; + $this->keepSemicolons = true; + } + + /** + * {@inheritdoc} + */ + protected function indentStr() + { + return str_repeat(' ', $this->indentLevel); + } + + /** + * {@inheritdoc} + */ + protected function blockLines(OutputBlock $block) + { + $indent = $this->indentStr(); + + if (empty($block->lines)) { + $this->write("{$indent}block->lines: []\n"); + + return; + } + + foreach ($block->lines as $index => $line) { + $this->write("{$indent}block->lines[{$index}]: $line\n"); + } + } + + /** + * {@inheritdoc} + */ + protected function blockSelectors(OutputBlock $block) + { + $indent = $this->indentStr(); + + if (empty($block->selectors)) { + $this->write("{$indent}block->selectors: []\n"); + + return; + } + + foreach ($block->selectors as $index => $selector) { + $this->write("{$indent}block->selectors[{$index}]: $selector\n"); + } + } + + /** + * {@inheritdoc} + */ + protected function blockChildren(OutputBlock $block) + { + $indent = $this->indentStr(); + + if (empty($block->children)) { + $this->write("{$indent}block->children: []\n"); + + return; + } + + $this->indentLevel++; + + foreach ($block->children as $i => $child) { + $this->block($child); + } + + $this->indentLevel--; + } + + /** + * {@inheritdoc} + */ + protected function block(OutputBlock $block) + { + $indent = $this->indentStr(); + + $this->write("{$indent}block->type: {$block->type}\n" . + "{$indent}block->depth: {$block->depth}\n"); + + $this->currentBlock = $block; + + $this->blockSelectors($block); + $this->blockLines($block); + $this->blockChildren($block); + } +} diff --git a/rules/scssphp/src/Formatter/Expanded.php b/rules/scssphp/src/Formatter/Expanded.php new file mode 100644 index 0000000..6eb4a0c --- /dev/null +++ b/rules/scssphp/src/Formatter/Expanded.php @@ -0,0 +1,72 @@ + + * + * @internal + */ +class Expanded extends Formatter +{ + /** + * {@inheritdoc} + */ + public function __construct() + { + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = "\n"; + $this->open = ' {'; + $this->close = '}'; + $this->tagSeparator = ', '; + $this->assignSeparator = ': '; + $this->keepSemicolons = true; + } + + /** + * {@inheritdoc} + */ + protected function indentStr() + { + return str_repeat($this->indentChar, $this->indentLevel); + } + + /** + * {@inheritdoc} + */ + protected function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + + $glue = $this->break . $inner; + + foreach ($block->lines as $index => $line) { + if (substr($line, 0, 2) === '/*') { + $replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line); + assert($replacedLine !== null); + $block->lines[$index] = $replacedLine; + } + } + + $this->write($inner . implode($glue, $block->lines)); + + if (empty($block->selectors) || ! empty($block->children)) { + $this->write($this->break); + } + } +} diff --git a/rules/scssphp/src/Formatter/Nested.php b/rules/scssphp/src/Formatter/Nested.php new file mode 100644 index 0000000..d5ed85c --- /dev/null +++ b/rules/scssphp/src/Formatter/Nested.php @@ -0,0 +1,238 @@ + + * + * @deprecated since 1.4.0. Use the Expanded formatter instead. + * + * @internal + */ +class Nested extends Formatter +{ + /** + * @var int + */ + private $depth; + + /** + * {@inheritdoc} + */ + public function __construct() + { + @trigger_error('The Nested formatter is deprecated since 1.4.0. Use the Expanded formatter instead.', E_USER_DEPRECATED); + + $this->indentLevel = 0; + $this->indentChar = ' '; + $this->break = "\n"; + $this->open = ' {'; + $this->close = ' }'; + $this->tagSeparator = ', '; + $this->assignSeparator = ': '; + $this->keepSemicolons = true; + } + + /** + * {@inheritdoc} + */ + protected function indentStr() + { + $n = $this->depth - 1; + + return str_repeat($this->indentChar, max($this->indentLevel + $n, 0)); + } + + /** + * {@inheritdoc} + */ + protected function blockLines(OutputBlock $block) + { + $inner = $this->indentStr(); + $glue = $this->break . $inner; + + foreach ($block->lines as $index => $line) { + if (substr($line, 0, 2) === '/*') { + $replacedLine = preg_replace('/\r\n?|\n|\f/', $this->break, $line); + assert($replacedLine !== null); + $block->lines[$index] = $replacedLine; + } + } + + $this->write($inner . implode($glue, $block->lines)); + } + + /** + * {@inheritdoc} + */ + protected function block(OutputBlock $block) + { + static $depths; + static $downLevel; + static $closeBlock; + static $previousEmpty; + static $previousHasSelector; + + if ($block->type === 'root') { + $depths = [ 0 ]; + $downLevel = ''; + $closeBlock = ''; + $this->depth = 0; + $previousEmpty = false; + $previousHasSelector = false; + } + + $isMediaOrDirective = \in_array($block->type, [Type::T_DIRECTIVE, Type::T_MEDIA]); + $isSupport = ($block->type === Type::T_DIRECTIVE + && $block->selectors && strpos(implode('', $block->selectors), '@supports') !== false); + + while ($block->depth < end($depths) || ($block->depth == 1 && end($depths) == 1)) { + array_pop($depths); + $this->depth--; + + if ( + ! $this->depth && ($block->depth <= 1 || (! $this->indentLevel && $block->type === Type::T_COMMENT)) && + (($block->selectors && ! $isMediaOrDirective) || $previousHasSelector) + ) { + $downLevel = $this->break; + } + + if (empty($block->lines) && empty($block->children)) { + $previousEmpty = true; + } + } + + if (empty($block->lines) && empty($block->children)) { + return; + } + + $this->currentBlock = $block; + + if (! empty($block->lines) || (! empty($block->children) && ($this->depth < 1 || $isSupport))) { + if ($block->depth > end($depths)) { + if (! $previousEmpty || $this->depth < 1) { + $this->depth++; + + $depths[] = $block->depth; + } else { + // keep the current depth unchanged but take the block depth as a new reference for following blocks + array_pop($depths); + + $depths[] = $block->depth; + } + } + } + + $previousEmpty = ($block->type === Type::T_COMMENT); + $previousHasSelector = false; + + if (! empty($block->selectors)) { + if ($closeBlock) { + $this->write($closeBlock); + $closeBlock = ''; + } + + if ($downLevel) { + $this->write($downLevel); + $downLevel = ''; + } + + $this->blockSelectors($block); + + $this->indentLevel++; + } + + if (! empty($block->lines)) { + if ($closeBlock) { + $this->write($closeBlock); + $closeBlock = ''; + } + + if ($downLevel) { + $this->write($downLevel); + $downLevel = ''; + } + + $this->blockLines($block); + + $closeBlock = $this->break; + } + + if (! empty($block->children)) { + if ($this->depth > 0 && ($isMediaOrDirective || ! $this->hasFlatChild($block))) { + array_pop($depths); + + $this->depth--; + $this->blockChildren($block); + $this->depth++; + + $depths[] = $block->depth; + } else { + $this->blockChildren($block); + } + } + + // reclear to not be spoiled by children if T_DIRECTIVE + if ($block->type === Type::T_DIRECTIVE) { + $previousHasSelector = false; + } + + if (! empty($block->selectors)) { + $this->indentLevel--; + + if (! $this->keepSemicolons) { + $this->strippedSemicolon = ''; + } + + $this->write($this->close); + + $closeBlock = $this->break; + + if ($this->depth > 1 && ! empty($block->children)) { + array_pop($depths); + $this->depth--; + } + + if (! $isMediaOrDirective) { + $previousHasSelector = true; + } + } + + if ($block->type === 'root') { + $this->write($this->break); + } + } + + /** + * Block has flat child + * + * @param \ScssPhp\ScssPhp\Formatter\OutputBlock $block + * + * @return bool + */ + private function hasFlatChild($block) + { + foreach ($block->children as $child) { + if (empty($child->selectors)) { + return true; + } + } + + return false; + } +} diff --git a/rules/scssphp/src/Formatter/OutputBlock.php b/rules/scssphp/src/Formatter/OutputBlock.php new file mode 100644 index 0000000..2799656 --- /dev/null +++ b/rules/scssphp/src/Formatter/OutputBlock.php @@ -0,0 +1,68 @@ + + * + * @internal + */ +class OutputBlock +{ + /** + * @var string|null + */ + public $type; + + /** + * @var int + */ + public $depth; + + /** + * @var array|null + */ + public $selectors; + + /** + * @var string[] + */ + public $lines; + + /** + * @var OutputBlock[] + */ + public $children; + + /** + * @var OutputBlock|null + */ + public $parent; + + /** + * @var string|null + */ + public $sourceName; + + /** + * @var int|null + */ + public $sourceLine; + + /** + * @var int|null + */ + public $sourceColumn; +} diff --git a/rules/scssphp/src/Logger/LoggerInterface.php b/rules/scssphp/src/Logger/LoggerInterface.php new file mode 100644 index 0000000..7c0a2f7 --- /dev/null +++ b/rules/scssphp/src/Logger/LoggerInterface.php @@ -0,0 +1,48 @@ +stream = $stream; + $this->closeOnDestruct = $closeOnDestruct; + } + + /** + * @internal + */ + public function __destruct() + { + if ($this->closeOnDestruct) { + fclose($this->stream); + } + } + + /** + * @inheritDoc + */ + public function warn($message, $deprecation = false) + { + $prefix = ($deprecation ? 'DEPRECATION ' : '') . 'WARNING: '; + + fwrite($this->stream, $prefix . $message . "\n\n"); + } + + /** + * @inheritDoc + */ + public function debug($message) + { + fwrite($this->stream, $message . "\n"); + } +} diff --git a/rules/scssphp/src/Node.php b/rules/scssphp/src/Node.php new file mode 100644 index 0000000..fcaf8a9 --- /dev/null +++ b/rules/scssphp/src/Node.php @@ -0,0 +1,43 @@ + + * + * @internal + */ +abstract class Node +{ + /** + * @var string + */ + public $type; + + /** + * @var int + */ + public $sourceIndex; + + /** + * @var int|null + */ + public $sourceLine; + + /** + * @var int|null + */ + public $sourceColumn; +} diff --git a/rules/scssphp/src/Node/Number.php b/rules/scssphp/src/Node/Number.php new file mode 100644 index 0000000..6c04458 --- /dev/null +++ b/rules/scssphp/src/Node/Number.php @@ -0,0 +1,844 @@ + + * + * @template-implements \ArrayAccess + */ +class Number extends Node implements \ArrayAccess, \JsonSerializable +{ + const PRECISION = 10; + + /** + * @var int + * @deprecated use {Number::PRECISION} instead to read the precision. Configuring it is not supported anymore. + */ + public static $precision = self::PRECISION; + + /** + * @see http://www.w3.org/TR/2012/WD-css3-values-20120308/ + * + * @var array + * @phpstan-var array> + */ + protected static $unitTable = [ + 'in' => [ + 'in' => 1, + 'pc' => 6, + 'pt' => 72, + 'px' => 96, + 'cm' => 2.54, + 'mm' => 25.4, + 'q' => 101.6, + ], + 'turn' => [ + 'deg' => 360, + 'grad' => 400, + 'rad' => 6.28318530717958647692528676, // 2 * M_PI + 'turn' => 1, + ], + 's' => [ + 's' => 1, + 'ms' => 1000, + ], + 'Hz' => [ + 'Hz' => 1, + 'kHz' => 0.001, + ], + 'dpi' => [ + 'dpi' => 1, + 'dpcm' => 1 / 2.54, + 'dppx' => 1 / 96, + ], + ]; + + /** + * @var int|float + */ + private $dimension; + + /** + * @var string[] + * @phpstan-var list + */ + private $numeratorUnits; + + /** + * @var string[] + * @phpstan-var list + */ + private $denominatorUnits; + + /** + * Initialize number + * + * @param int|float $dimension + * @param string[]|string $numeratorUnits + * @param string[] $denominatorUnits + * + * @phpstan-param list|string $numeratorUnits + * @phpstan-param list $denominatorUnits + */ + public function __construct($dimension, $numeratorUnits, array $denominatorUnits = []) + { + if (is_string($numeratorUnits)) { + $numeratorUnits = $numeratorUnits ? [$numeratorUnits] : []; + } elseif (isset($numeratorUnits['numerator_units'], $numeratorUnits['denominator_units'])) { + // TODO get rid of this once `$number[2]` is not used anymore + $denominatorUnits = $numeratorUnits['denominator_units']; + $numeratorUnits = $numeratorUnits['numerator_units']; + } + + $this->dimension = $dimension; + $this->numeratorUnits = $numeratorUnits; + $this->denominatorUnits = $denominatorUnits; + } + + /** + * @return float|int + */ + public function getDimension() + { + return $this->dimension; + } + + /** + * @return list + */ + public function getNumeratorUnits() + { + return $this->numeratorUnits; + } + + /** + * @return list + */ + public function getDenominatorUnits() + { + return $this->denominatorUnits; + } + + /** + * @return mixed + */ + #[\ReturnTypeWillChange] + public function jsonSerialize() + { + // Passing a compiler instance makes the method output a Sass representation instead of a CSS one, supporting full units. + return $this->output(new Compiler()); + } + + /** + * @return bool + */ + #[\ReturnTypeWillChange] + public function offsetExists($offset) + { + if ($offset === -3) { + return ! \is_null($this->sourceColumn); + } + + if ($offset === -2) { + return ! \is_null($this->sourceLine); + } + + if ( + $offset === -1 || + $offset === 0 || + $offset === 1 || + $offset === 2 + ) { + return true; + } + + return false; + } + + /** + * @return mixed + */ + #[\ReturnTypeWillChange] + public function offsetGet($offset) + { + switch ($offset) { + case -3: + return $this->sourceColumn; + + case -2: + return $this->sourceLine; + + case -1: + return $this->sourceIndex; + + case 0: + return Type::T_NUMBER; + + case 1: + return $this->dimension; + + case 2: + return array('numerator_units' => $this->numeratorUnits, 'denominator_units' => $this->denominatorUnits); + } + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetSet($offset, $value) + { + throw new \BadMethodCallException('Number is immutable'); + } + + /** + * @return void + */ + #[\ReturnTypeWillChange] + public function offsetUnset($offset) + { + throw new \BadMethodCallException('Number is immutable'); + } + + /** + * Returns true if the number is unitless + * + * @return bool + */ + public function unitless() + { + return \count($this->numeratorUnits) === 0 && \count($this->denominatorUnits) === 0; + } + + /** + * Returns true if the number has any units + * + * @return bool + */ + public function hasUnits() + { + return !$this->unitless(); + } + + /** + * Checks whether the number has exactly this unit + * + * @param string $unit + * + * @return bool + */ + public function hasUnit($unit) + { + return \count($this->numeratorUnits) === 1 && \count($this->denominatorUnits) === 0 && $this->numeratorUnits[0] === $unit; + } + + /** + * Returns unit(s) as the product of numerator units divided by the product of denominator units + * + * @return string + */ + public function unitStr() + { + if ($this->unitless()) { + return ''; + } + + return self::getUnitString($this->numeratorUnits, $this->denominatorUnits); + } + + /** + * @param float|int $min + * @param float|int $max + * @param string|null $name + * + * @return float|int + * @throws SassScriptException + */ + public function valueInRange($min, $max, $name = null) + { + try { + return Util::checkRange('', new Range($min, $max), $this); + } catch (RangeException $e) { + throw SassScriptException::forArgument(sprintf('Expected %s to be within %s%s and %s%3$s.', $this, $min, $this->unitStr(), $max), $name); + } + } + + /** + * @param float|int $min + * @param float|int $max + * @param string $name + * @param string $unit + * + * @return float|int + * @throws SassScriptException + * + * @internal + */ + public function valueInRangeWithUnit($min, $max, $name, $unit) + { + try { + return Util::checkRange('', new Range($min, $max), $this); + } catch (RangeException $e) { + throw SassScriptException::forArgument(sprintf('Expected %s to be within %s%s and %s%3$s.', $this, $min, $unit, $max), $name); + } + } + + /** + * @param string|null $varName + * + * @return void + */ + public function assertNoUnits($varName = null) + { + if ($this->unitless()) { + return; + } + + throw SassScriptException::forArgument(sprintf('Expected %s to have no units.', $this), $varName); + } + + /** + * @param string $unit + * @param string|null $varName + * + * @return void + */ + public function assertUnit($unit, $varName = null) + { + if ($this->hasUnit($unit)) { + return; + } + + throw SassScriptException::forArgument(sprintf('Expected %s to have unit "%s".', $this, $unit), $varName); + } + + /** + * @param Number $other + * + * @return void + */ + public function assertSameUnitOrUnitless(Number $other) + { + if ($other->unitless()) { + return; + } + + if ($this->numeratorUnits === $other->numeratorUnits && $this->denominatorUnits === $other->denominatorUnits) { + return; + } + + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($other->numeratorUnits, $other->denominatorUnits) + )); + } + + /** + * Returns a copy of this number, converted to the units represented by $newNumeratorUnits and $newDenominatorUnits. + * + * This does not throw an error if this number is unitless and + * $newNumeratorUnits/$newDenominatorUnits are not empty, or vice versa. Instead, + * it treats all unitless numbers as convertible to and from all units without + * changing the value. + * + * @param string[] $newNumeratorUnits + * @param string[] $newDenominatorUnits + * + * @return Number + * + * @phpstan-param list $newNumeratorUnits + * @phpstan-param list $newDenominatorUnits + * + * @throws SassScriptException if this number's units are not compatible with $newNumeratorUnits and $newDenominatorUnits + */ + public function coerce(array $newNumeratorUnits, array $newDenominatorUnits) + { + return new Number($this->valueInUnits($newNumeratorUnits, $newDenominatorUnits), $newNumeratorUnits, $newDenominatorUnits); + } + + /** + * @param Number $other + * + * @return bool + */ + public function isComparableTo(Number $other) + { + if ($this->unitless() || $other->unitless()) { + return true; + } + + try { + $this->greaterThan($other); + return true; + } catch (SassScriptException $e) { + return false; + } + } + + /** + * @param Number $other + * + * @return bool + */ + public function lessThan(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 < $num2; + }); + } + + /** + * @param Number $other + * + * @return bool + */ + public function lessThanOrEqual(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 <= $num2; + }); + } + + /** + * @param Number $other + * + * @return bool + */ + public function greaterThan(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 > $num2; + }); + } + + /** + * @param Number $other + * + * @return bool + */ + public function greaterThanOrEqual(Number $other) + { + return $this->coerceUnits($other, function ($num1, $num2) { + return $num1 >= $num2; + }); + } + + /** + * @param Number $other + * + * @return Number + */ + public function plus(Number $other) + { + return $this->coerceNumber($other, function ($num1, $num2) { + return $num1 + $num2; + }); + } + + /** + * @param Number $other + * + * @return Number + */ + public function minus(Number $other) + { + return $this->coerceNumber($other, function ($num1, $num2) { + return $num1 - $num2; + }); + } + + /** + * @return Number + */ + public function unaryMinus() + { + return new Number(-$this->dimension, $this->numeratorUnits, $this->denominatorUnits); + } + + /** + * @param Number $other + * + * @return Number + */ + public function modulo(Number $other) + { + return $this->coerceNumber($other, function ($num1, $num2) { + if ($num2 == 0) { + return NAN; + } + + $result = fmod($num1, $num2); + + if ($result == 0) { + return 0; + } + + if ($num2 < 0 xor $num1 < 0) { + $result += $num2; + } + + return $result; + }); + } + + /** + * @param Number $other + * + * @return Number + */ + public function times(Number $other) + { + return $this->multiplyUnits($this->dimension * $other->dimension, $this->numeratorUnits, $this->denominatorUnits, $other->numeratorUnits, $other->denominatorUnits); + } + + /** + * @param Number $other + * + * @return Number + */ + public function dividedBy(Number $other) + { + if ($other->dimension == 0) { + if ($this->dimension == 0) { + $value = NAN; + } elseif ($this->dimension > 0) { + $value = INF; + } else { + $value = -INF; + } + } else { + $value = $this->dimension / $other->dimension; + } + + return $this->multiplyUnits($value, $this->numeratorUnits, $this->denominatorUnits, $other->denominatorUnits, $other->numeratorUnits); + } + + /** + * @param Number $other + * + * @return bool + */ + public function equals(Number $other) + { + // Unitless numbers are convertable to unit numbers, but not equal, so we special-case unitless here. + if ($this->unitless() !== $other->unitless()) { + return false; + } + + // In Sass, neither NaN nor Infinity are equal to themselves, while PHP defines INF==INF + if (is_nan($this->dimension) || is_nan($other->dimension) || !is_finite($this->dimension) || !is_finite($other->dimension)) { + return false; + } + + if ($this->unitless()) { + return round($this->dimension, self::PRECISION) == round($other->dimension, self::PRECISION); + } + + try { + return $this->coerceUnits($other, function ($num1, $num2) { + return round($num1, self::PRECISION) == round($num2, self::PRECISION); + }); + } catch (SassScriptException $e) { + return false; + } + } + + /** + * Output number + * + * @param \ScssPhp\ScssPhp\Compiler $compiler + * + * @return string + */ + public function output(Compiler $compiler = null) + { + $dimension = round($this->dimension, self::PRECISION); + + if (is_nan($dimension)) { + return 'NaN'; + } + + if ($dimension === INF) { + return 'Infinity'; + } + + if ($dimension === -INF) { + return '-Infinity'; + } + + if ($compiler) { + $unit = $this->unitStr(); + } elseif (isset($this->numeratorUnits[0])) { + $unit = $this->numeratorUnits[0]; + } else { + $unit = ''; + } + + $dimension = number_format($dimension, self::PRECISION, '.', ''); + + return rtrim(rtrim($dimension, '0'), '.') . $unit; + } + + /** + * {@inheritdoc} + */ + public function __toString() + { + return $this->output(); + } + + /** + * @param Number $other + * @param callable $operation + * + * @return Number + * + * @phpstan-param callable(int|float, int|float): (int|float) $operation + */ + private function coerceNumber(Number $other, $operation) + { + $result = $this->coerceUnits($other, $operation); + + if (!$this->unitless()) { + return new Number($result, $this->numeratorUnits, $this->denominatorUnits); + } + + return new Number($result, $other->numeratorUnits, $other->denominatorUnits); + } + + /** + * @param Number $other + * @param callable $operation + * + * @return mixed + * + * @phpstan-template T + * @phpstan-param callable(int|float, int|float): T $operation + * @phpstan-return T + */ + private function coerceUnits(Number $other, $operation) + { + if (!$this->unitless()) { + $num1 = $this->dimension; + $num2 = $other->valueInUnits($this->numeratorUnits, $this->denominatorUnits); + } else { + $num1 = $this->valueInUnits($other->numeratorUnits, $other->denominatorUnits); + $num2 = $other->dimension; + } + + return \call_user_func($operation, $num1, $num2); + } + + /** + * @param string[] $numeratorUnits + * @param string[] $denominatorUnits + * + * @return int|float + * + * @phpstan-param list $numeratorUnits + * @phpstan-param list $denominatorUnits + * + * @throws SassScriptException if this number's units are not compatible with $numeratorUnits and $denominatorUnits + */ + private function valueInUnits(array $numeratorUnits, array $denominatorUnits) + { + if ( + $this->unitless() + || (\count($numeratorUnits) === 0 && \count($denominatorUnits) === 0) + || ($this->numeratorUnits === $numeratorUnits && $this->denominatorUnits === $denominatorUnits) + ) { + return $this->dimension; + } + + $value = $this->dimension; + $oldNumerators = $this->numeratorUnits; + + foreach ($numeratorUnits as $newNumerator) { + foreach ($oldNumerators as $key => $oldNumerator) { + $conversionFactor = self::getConversionFactor($newNumerator, $oldNumerator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value *= $conversionFactor; + unset($oldNumerators[$key]); + continue 2; + } + + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($numeratorUnits, $denominatorUnits) + )); + } + + $oldDenominators = $this->denominatorUnits; + + foreach ($denominatorUnits as $newDenominator) { + foreach ($oldDenominators as $key => $oldDenominator) { + $conversionFactor = self::getConversionFactor($newDenominator, $oldDenominator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value /= $conversionFactor; + unset($oldDenominators[$key]); + continue 2; + } + + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($numeratorUnits, $denominatorUnits) + )); + } + + if (\count($oldNumerators) || \count($oldDenominators)) { + throw new SassScriptException(sprintf( + 'Incompatible units %s and %s.', + self::getUnitString($this->numeratorUnits, $this->denominatorUnits), + self::getUnitString($numeratorUnits, $denominatorUnits) + )); + } + + return $value; + } + + /** + * @param int|float $value + * @param string[] $numerators1 + * @param string[] $denominators1 + * @param string[] $numerators2 + * @param string[] $denominators2 + * + * @return Number + * + * @phpstan-param list $numerators1 + * @phpstan-param list $denominators1 + * @phpstan-param list $numerators2 + * @phpstan-param list $denominators2 + */ + private function multiplyUnits($value, array $numerators1, array $denominators1, array $numerators2, array $denominators2) + { + $newNumerators = array(); + + foreach ($numerators1 as $numerator) { + foreach ($denominators2 as $key => $denominator) { + $conversionFactor = self::getConversionFactor($numerator, $denominator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value /= $conversionFactor; + unset($denominators2[$key]); + continue 2; + } + + $newNumerators[] = $numerator; + } + + foreach ($numerators2 as $numerator) { + foreach ($denominators1 as $key => $denominator) { + $conversionFactor = self::getConversionFactor($numerator, $denominator); + + if (\is_null($conversionFactor)) { + continue; + } + + $value /= $conversionFactor; + unset($denominators1[$key]); + continue 2; + } + + $newNumerators[] = $numerator; + } + + $newDenominators = array_values(array_merge($denominators1, $denominators2)); + + return new Number($value, $newNumerators, $newDenominators); + } + + /** + * Returns the number of [unit1]s per [unit2]. + * + * Equivalently, `1unit1 * conversionFactor(unit1, unit2) = 1unit2`. + * + * @param string $unit1 + * @param string $unit2 + * + * @return float|int|null + */ + private static function getConversionFactor($unit1, $unit2) + { + if ($unit1 === $unit2) { + return 1; + } + + foreach (static::$unitTable as $unitVariants) { + if (isset($unitVariants[$unit1]) && isset($unitVariants[$unit2])) { + return $unitVariants[$unit1] / $unitVariants[$unit2]; + } + } + + return null; + } + + /** + * Returns unit(s) as the product of numerator units divided by the product of denominator units + * + * @param string[] $numerators + * @param string[] $denominators + * + * @phpstan-param list $numerators + * @phpstan-param list $denominators + * + * @return string + */ + private static function getUnitString(array $numerators, array $denominators) + { + if (!\count($numerators)) { + if (\count($denominators) === 0) { + return 'no units'; + } + + if (\count($denominators) === 1) { + return $denominators[0] . '^-1'; + } + + return '(' . implode('*', $denominators) . ')^-1'; + } + + return implode('*', $numerators) . (\count($denominators) ? '/' . implode('*', $denominators) : ''); + } +} diff --git a/rules/scssphp/src/OutputStyle.php b/rules/scssphp/src/OutputStyle.php new file mode 100644 index 0000000..a1d8b42 --- /dev/null +++ b/rules/scssphp/src/OutputStyle.php @@ -0,0 +1,62 @@ + + * + * @internal + */ +class Parser +{ + const SOURCE_INDEX = -1; + const SOURCE_LINE = -2; + const SOURCE_COLUMN = -3; + + /** + * @var array + */ + protected static $precedence = [ + '=' => 0, + 'or' => 1, + 'and' => 2, + '==' => 3, + '!=' => 3, + '<=' => 4, + '>=' => 4, + '<' => 4, + '>' => 4, + '+' => 5, + '-' => 5, + '*' => 6, + '/' => 6, + '%' => 6, + ]; + + /** + * @var string + */ + protected static $commentPattern; + /** + * @var string + */ + protected static $operatorPattern; + /** + * @var string + */ + protected static $whitePattern; + + /** + * @var Cache|null + */ + protected $cache; + + private $sourceName; + private $sourceIndex; + /** + * @var array + */ + private $sourcePositions; + /** + * The current offset in the buffer + * + * @var int + */ + private $count; + /** + * @var Block|null + */ + private $env; + /** + * @var bool + */ + private $inParens; + /** + * @var bool + */ + private $eatWhiteDefault; + /** + * @var bool + */ + private $discardComments; + private $allowVars; + /** + * @var string + */ + private $buffer; + private $utf8; + /** + * @var string|null + */ + private $encoding; + private $patternModifiers; + private $commentsSeen; + + private $cssOnly; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * Constructor + * + * @api + * + * @param string|null $sourceName + * @param int $sourceIndex + * @param string|null $encoding + * @param Cache|null $cache + * @param bool $cssOnly + * @param LoggerInterface|null $logger + */ + public function __construct($sourceName, $sourceIndex = 0, $encoding = 'utf-8', Cache $cache = null, $cssOnly = false, LoggerInterface $logger = null) + { + $this->sourceName = $sourceName ?: '(stdin)'; + $this->sourceIndex = $sourceIndex; + $this->utf8 = ! $encoding || strtolower($encoding) === 'utf-8'; + $this->patternModifiers = $this->utf8 ? 'Aisu' : 'Ais'; + $this->commentsSeen = []; + $this->allowVars = true; + $this->cssOnly = $cssOnly; + $this->logger = $logger ?: new QuietLogger(); + + if (empty(static::$operatorPattern)) { + static::$operatorPattern = '([*\/%+-]|[!=]\=|\>\=?|\<\=?|and|or)'; + + $commentSingle = '\/\/'; + $commentMultiLeft = '\/\*'; + $commentMultiRight = '\*\/'; + + static::$commentPattern = $commentMultiLeft . '.*?' . $commentMultiRight; + static::$whitePattern = $this->utf8 + ? '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisuS' + : '/' . $commentSingle . '[^\n]*\s*|(' . static::$commentPattern . ')\s*|\s+/AisS'; + } + + $this->cache = $cache; + } + + /** + * Get source file name + * + * @api + * + * @return string + */ + public function getSourceName() + { + return $this->sourceName; + } + + /** + * Throw parser error + * + * @api + * + * @param string $msg + * + * @phpstan-return never-return + * + * @throws ParserException + * + * @deprecated use "parseError" and throw the exception in the caller instead. + */ + public function throwParseError($msg = 'parse error') + { + @trigger_error( + 'The method "throwParseError" is deprecated. Use "parseError" and throw the exception in the caller instead', + E_USER_DEPRECATED + ); + + throw $this->parseError($msg); + } + + /** + * Creates a parser error + * + * @api + * + * @param string $msg + * + * @return ParserException + */ + public function parseError($msg = 'parse error') + { + list($line, $column) = $this->getSourcePosition($this->count); + + $loc = empty($this->sourceName) + ? "line: $line, column: $column" + : "$this->sourceName on line $line, at column $column"; + + if ($this->peek('(.*?)(\n|$)', $m, $this->count)) { + $this->restoreEncoding(); + + $e = new ParserException("$msg: failed at `$m[1]` $loc"); + $e->setSourcePosition([$this->sourceName, $line, $column]); + + return $e; + } + + $this->restoreEncoding(); + + $e = new ParserException("$msg: $loc"); + $e->setSourcePosition([$this->sourceName, $line, $column]); + + return $e; + } + + /** + * Parser buffer + * + * @api + * + * @param string $buffer + * + * @return Block + */ + public function parse($buffer) + { + if ($this->cache) { + $cacheKey = $this->sourceName . ':' . md5($buffer); + $parseOptions = [ + 'utf8' => $this->utf8, + ]; + $v = $this->cache->getCache('parse', $cacheKey, $parseOptions); + + if (! \is_null($v)) { + return $v; + } + } + + // strip BOM (byte order marker) + if (substr($buffer, 0, 3) === "\xef\xbb\xbf") { + $buffer = substr($buffer, 3); + } + + $this->buffer = rtrim($buffer, "\x00..\x1f"); + $this->count = 0; + $this->env = null; + $this->inParens = false; + $this->eatWhiteDefault = true; + + $this->saveEncoding(); + $this->extractLineNumbers($buffer); + + if ($this->utf8 && !preg_match('//u', $buffer)) { + $message = $this->sourceName ? 'Invalid UTF-8 file: ' . $this->sourceName : 'Invalid UTF-8 file'; + throw new ParserException($message); + } + + $this->pushBlock(null); // root block + $this->whitespace(); + $this->pushBlock(null); + $this->popBlock(); + + while ($this->parseChunk()) { + ; + } + + if ($this->count !== \strlen($this->buffer)) { + throw $this->parseError(); + } + + if (! empty($this->env->parent)) { + throw $this->parseError('unclosed block'); + } + + $this->restoreEncoding(); + assert($this->env !== null); + + if ($this->cache) { + $this->cache->setCache('parse', $cacheKey, $this->env, $parseOptions); + } + + return $this->env; + } + + /** + * Parse a value or value list + * + * @api + * + * @param string $buffer + * @param mixed $out + * @param-out array|Number $out + * + * @return bool + */ + public function parseValue($buffer, &$out) + { + $this->count = 0; + $this->env = null; + $this->inParens = false; + $this->eatWhiteDefault = true; + $this->buffer = (string) $buffer; + + $this->saveEncoding(); + $this->extractLineNumbers($this->buffer); + + $list = $this->valueList($out); + + if ($this->count !== \strlen($this->buffer)) { + $error = $this->parseError('Expected end of value'); + $message = 'Passing trailing content after the expression when parsing a value is deprecated since Scssphp 1.12.0 and will be an error in 2.0. ' . $error->getMessage(); + + @trigger_error($message, E_USER_DEPRECATED); + } + + $this->restoreEncoding(); + + return $list; + } + + /** + * Parse a selector or selector list + * + * @api + * + * @param string $buffer + * @param array $out + * @param bool $shouldValidate + * + * @return bool + */ + public function parseSelector($buffer, &$out, $shouldValidate = true) + { + $this->count = 0; + $this->env = null; + $this->inParens = false; + $this->eatWhiteDefault = true; + $this->buffer = (string) $buffer; + + $this->saveEncoding(); + $this->extractLineNumbers($this->buffer); + + // discard space/comments at the start + $this->discardComments = true; + $this->whitespace(); + $this->discardComments = false; + + $selector = $this->selectors($out); + + $this->restoreEncoding(); + + if ($shouldValidate && $this->count !== strlen($buffer)) { + throw $this->parseError("`" . substr($buffer, $this->count) . "` is not a valid Selector in `$buffer`"); + } + + return $selector; + } + + /** + * Parse a media Query + * + * @api + * + * @param string $buffer + * @param array $out + * + * @return bool + */ + public function parseMediaQueryList($buffer, &$out) + { + $this->count = 0; + $this->env = null; + $this->inParens = false; + $this->eatWhiteDefault = true; + $this->buffer = (string) $buffer; + $this->discardComments = true; + + $this->saveEncoding(); + $this->extractLineNumbers($this->buffer); + + $this->whitespace(); + + $isMediaQuery = $this->mediaQueryList($out); + + $this->restoreEncoding(); + + return $isMediaQuery; + } + + /** + * Parse a single chunk off the head of the buffer and append it to the + * current parse environment. + * + * Returns false when the buffer is empty, or when there is an error. + * + * This function is called repeatedly until the entire document is + * parsed. + * + * This parser is most similar to a recursive descent parser. Single + * functions represent discrete grammatical rules for the language, and + * they are able to capture the text that represents those rules. + * + * Consider the function Compiler::keyword(). (All parse functions are + * structured the same.) + * + * The function takes a single reference argument. When calling the + * function it will attempt to match a keyword on the head of the buffer. + * If it is successful, it will place the keyword in the referenced + * argument, advance the position in the buffer, and return true. If it + * fails then it won't advance the buffer and it will return false. + * + * All of these parse functions are powered by Compiler::match(), which behaves + * the same way, but takes a literal regular expression. Sometimes it is + * more convenient to use match instead of creating a new function. + * + * Because of the format of the functions, to parse an entire string of + * grammatical rules, you can chain them together using &&. + * + * But, if some of the rules in the chain succeed before one fails, then + * the buffer position will be left at an invalid state. In order to + * avoid this, Compiler::seek() is used to remember and set buffer positions. + * + * Before parsing a chain, use $s = $this->count to remember the current + * position into $s. Then if a chain fails, use $this->seek($s) to + * go back where we started. + * + * @return bool + */ + protected function parseChunk() + { + $s = $this->count; + + // the directives + if (isset($this->buffer[$this->count]) && $this->buffer[$this->count] === '@') { + if ( + $this->literal('@at-root', 8) && + ($this->selectors($selector) || true) && + ($this->map($with) || true) && + (($this->matchChar('(') && + $this->interpolation($with) && + $this->matchChar(')')) || true) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $atRoot = new AtRootBlock(); + $this->registerPushedBlock($atRoot, $s); + $atRoot->selector = $selector; + $atRoot->with = $with; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@media', 6) && + $this->mediaQueryList($mediaQueryList) && + $this->matchChar('{', false) + ) { + $media = new MediaBlock(); + $this->registerPushedBlock($media, $s); + $media->queryList = $mediaQueryList[2]; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@mixin', 6) && + $this->keyword($mixinName) && + ($this->argumentDef($args) || true) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $mixin = new CallableBlock(Type::T_MIXIN); + $this->registerPushedBlock($mixin, $s); + $mixin->name = $mixinName; + $mixin->args = $args; + + return true; + } + + $this->seek($s); + + if ( + ($this->literal('@include', 8) && + $this->keyword($mixinName) && + ($this->matchChar('(') && + ($this->argValues($argValues) || true) && + $this->matchChar(')') || true) && + ($this->end()) || + ($this->literal('using', 5) && + $this->argumentDef($argUsing) && + ($this->end() || $this->matchChar('{') && $hasBlock = true)) || + $this->matchChar('{') && $hasBlock = true) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $child = [ + Type::T_INCLUDE, + $mixinName, + isset($argValues) ? $argValues : null, + null, + isset($argUsing) ? $argUsing : null + ]; + + if (! empty($hasBlock)) { + $include = new ContentBlock(); + $this->registerPushedBlock($include, $s); + $include->child = $child; + } else { + $this->append($child, $s); + } + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@scssphp-import-once', 20) && + $this->valueList($importPath) && + $this->end() + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + list($line, $column) = $this->getSourcePosition($s); + $file = $this->sourceName; + $this->logger->warn("The \"@scssphp-import-once\" directive is deprecated and will be removed in ScssPhp 2.0, in \"$file\", line $line, column $column.", true); + + $this->append([Type::T_SCSSPHP_IMPORT_ONCE, $importPath], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@import', 7) && + $this->valueList($importPath) && + $importPath[0] !== Type::T_FUNCTION_CALL && + $this->end() + ) { + if ($this->cssOnly) { + $this->assertPlainCssValid([Type::T_IMPORT, $importPath], $s); + $this->append([Type::T_COMMENT, rtrim(substr($this->buffer, $s, $this->count - $s))]); + return true; + } + + $this->append([Type::T_IMPORT, $importPath], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@import', 7) && + $this->url($importPath) && + $this->end() + ) { + if ($this->cssOnly) { + $this->assertPlainCssValid([Type::T_IMPORT, $importPath], $s); + $this->append([Type::T_COMMENT, rtrim(substr($this->buffer, $s, $this->count - $s))]); + return true; + } + + $this->append([Type::T_IMPORT, $importPath], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@extend', 7) && + $this->selectors($selectors) && + $this->end() + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + // check for '!flag' + $optional = $this->stripOptionalFlag($selectors); + $this->append([Type::T_EXTEND, $selectors, $optional], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@function', 9) && + $this->keyword($fnName) && + $this->argumentDef($args) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $func = new CallableBlock(Type::T_FUNCTION); + $this->registerPushedBlock($func, $s); + $func->name = $fnName; + $func->args = $args; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@return', 7) && + ($this->valueList($retVal) || true) && + $this->end() + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $this->append([Type::T_RETURN, isset($retVal) ? $retVal : [Type::T_NULL]], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@each', 5) && + $this->genericList($varNames, 'variable', ',', false) && + $this->literal('in', 2) && + $this->valueList($list) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $each = new EachBlock(); + $this->registerPushedBlock($each, $s); + + foreach ($varNames[2] as $varName) { + $each->vars[] = $varName[1]; + } + + $each->list = $list; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@while', 6) && + $this->expression($cond) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + while ( + $cond[0] === Type::T_LIST && + ! empty($cond['enclosing']) && + $cond['enclosing'] === 'parent' && + \count($cond[2]) == 1 + ) { + $cond = reset($cond[2]); + } + + $while = new WhileBlock(); + $this->registerPushedBlock($while, $s); + $while->cond = $cond; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@for', 4) && + $this->variable($varName) && + $this->literal('from', 4) && + $this->expression($start) && + ($this->literal('through', 7) || + ($forUntil = true && $this->literal('to', 2))) && + $this->expression($end) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $for = new ForBlock(); + $this->registerPushedBlock($for, $s); + $for->var = $varName[1]; + $for->start = $start; + $for->end = $end; + $for->until = isset($forUntil); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@if', 3) && + $this->functionCallArgumentsList($cond, false, '{', false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $if = new IfBlock(); + $this->registerPushedBlock($if, $s); + + while ( + $cond[0] === Type::T_LIST && + ! empty($cond['enclosing']) && + $cond['enclosing'] === 'parent' && + \count($cond[2]) == 1 + ) { + $cond = reset($cond[2]); + } + + $if->cond = $cond; + $if->cases = []; + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@debug', 6) && + $this->functionCallArgumentsList($value, false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $this->append([Type::T_DEBUG, $value], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@warn', 5) && + $this->functionCallArgumentsList($value, false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $this->append([Type::T_WARN, $value], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@error', 6) && + $this->functionCallArgumentsList($value, false) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $this->append([Type::T_ERROR, $value], $s); + + return true; + } + + $this->seek($s); + + if ( + $this->literal('@content', 8) && + ($this->end() || + $this->matchChar('(') && + $this->argValues($argContent) && + $this->matchChar(')') && + $this->end()) + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + $this->append([Type::T_MIXIN_CONTENT, isset($argContent) ? $argContent : null], $s); + + return true; + } + + $this->seek($s); + + $last = $this->last(); + + if (isset($last) && $last[0] === Type::T_IF) { + list(, $if) = $last; + assert($if instanceof IfBlock); + + if ($this->literal('@else', 5)) { + if ($this->matchChar('{', false)) { + $else = new ElseBlock(); + } elseif ( + $this->literal('if', 2) && + $this->functionCallArgumentsList($cond, false, '{', false) + ) { + $else = new ElseifBlock(); + $else->cond = $cond; + } + + if (isset($else)) { + $this->registerPushedBlock($else, $s); + $if->cases[] = $else; + + return true; + } + } + + $this->seek($s); + } + + // only retain the first @charset directive encountered + if ( + $this->literal('@charset', 8) && + $this->valueList($charset) && + $this->end() + ) { + return true; + } + + $this->seek($s); + + if ( + $this->literal('@supports', 9) && + ($t1 = $this->supportsQuery($supportQuery)) && + ($t2 = $this->matchChar('{', false)) + ) { + $directive = new DirectiveBlock(); + $this->registerPushedBlock($directive, $s); + $directive->name = 'supports'; + $directive->value = $supportQuery; + + return true; + } + + $this->seek($s); + + // doesn't match built in directive, do generic one + if ( + $this->matchChar('@', false) && + $this->mixedKeyword($dirName) && + $this->directiveValue($dirValue, '{') + ) { + if (count($dirName) === 1 && is_string(reset($dirName))) { + $dirName = reset($dirName); + } else { + $dirName = [Type::T_STRING, '', $dirName]; + } + if ($dirName === 'media') { + $directive = new MediaBlock(); + } else { + $directive = new DirectiveBlock(); + $directive->name = $dirName; + } + $this->registerPushedBlock($directive, $s); + + if (isset($dirValue)) { + ! $this->cssOnly || ($dirValue = $this->assertPlainCssValid($dirValue)); + $directive->value = $dirValue; + } + + return true; + } + + $this->seek($s); + + // maybe it's a generic blockless directive + if ( + $this->matchChar('@', false) && + $this->mixedKeyword($dirName) && + ! $this->isKnownGenericDirective($dirName) && + ($this->end(false) || ($this->directiveValue($dirValue, '') && $this->end(false))) + ) { + if (\count($dirName) === 1 && \is_string(\reset($dirName))) { + $dirName = \reset($dirName); + } else { + $dirName = [Type::T_STRING, '', $dirName]; + } + if ( + ! empty($this->env->parent) && + $this->env->type && + ! \in_array($this->env->type, [Type::T_DIRECTIVE, Type::T_MEDIA]) + ) { + $plain = \trim(\substr($this->buffer, $s, $this->count - $s)); + throw $this->parseError( + "Unknown directive `{$plain}` not allowed in `" . $this->env->type . "` block" + ); + } + // blockless directives with a blank line after keeps their blank lines after + // sass-spec compliance purpose + $s = $this->count; + $hasBlankLine = false; + if ($this->match('\s*?\n\s*\n', $out, false)) { + $hasBlankLine = true; + $this->seek($s); + } + $isNotRoot = ! empty($this->env->parent); + $this->append([Type::T_DIRECTIVE, [$dirName, $dirValue, $hasBlankLine, $isNotRoot]], $s); + $this->whitespace(); + + return true; + } + + $this->seek($s); + + return false; + } + + $inCssSelector = null; + if ($this->cssOnly) { + $inCssSelector = (! empty($this->env->parent) && + ! in_array($this->env->type, [Type::T_DIRECTIVE, Type::T_MEDIA])); + } + // custom properties : right part is static + if (($this->customProperty($name) ) && $this->matchChar(':', false)) { + $start = $this->count; + + // but can be complex and finish with ; or } + foreach ([';','}'] as $ending) { + if ( + $this->openString($ending, $stringValue, '(', ')', false) && + $this->end() + ) { + $end = $this->count; + $value = $stringValue; + + // check if we have only a partial value due to nested [] or { } to take in account + $nestingPairs = [['[', ']'], ['{', '}']]; + + foreach ($nestingPairs as $nestingPair) { + $p = strpos($this->buffer, $nestingPair[0], $start); + + if ($p && $p < $end) { + $this->seek($start); + + if ( + $this->openString($ending, $stringValue, $nestingPair[0], $nestingPair[1], false) && + $this->end() && + $this->count > $end + ) { + $end = $this->count; + $value = $stringValue; + } + } + } + + $this->seek($end); + $this->append([Type::T_CUSTOM_PROPERTY, $name, $value], $s); + + return true; + } + } + + // TODO: output an error here if nothing found according to sass spec + } + + $this->seek($s); + + // property shortcut + // captures most properties before having to parse a selector + if ( + $this->keyword($name, false) && + $this->literal(': ', 2) && + $this->valueList($value) && + $this->end() + ) { + $name = [Type::T_STRING, '', [$name]]; + $this->append([Type::T_ASSIGN, $name, $value], $s); + + return true; + } + + $this->seek($s); + + // variable assigns + if ( + $this->variable($name) && + $this->matchChar(':') && + $this->valueList($value) && + $this->end() + ) { + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + + // check for '!flag' + $assignmentFlags = $this->stripAssignmentFlags($value); + $this->append([Type::T_ASSIGN, $name, $value, $assignmentFlags], $s); + + return true; + } + + $this->seek($s); + + // opening css block + if ( + $this->selectors($selectors) && + $this->matchChar('{', false) + ) { + ! $this->cssOnly || ! $inCssSelector || $this->assertPlainCssValid(false); + + $this->pushBlock($selectors, $s); + + if ($this->eatWhiteDefault) { + $this->whitespace(); + $this->append(null); // collect comments at the beginning if needed + } + + return true; + } + + $this->seek($s); + + // property assign, or nested assign + if ( + $this->propertyName($name) && + $this->matchChar(':') + ) { + $foundSomething = false; + + if ($this->valueList($value)) { + if (empty($this->env->parent)) { + throw $this->parseError('expected "{"'); + } + + $this->append([Type::T_ASSIGN, $name, $value], $s); + $foundSomething = true; + } + + if ($this->matchChar('{', false)) { + ! $this->cssOnly || $this->assertPlainCssValid(false); + + $propBlock = new NestedPropertyBlock(); + $this->registerPushedBlock($propBlock, $s); + $propBlock->prefix = $name; + $propBlock->hasValue = $foundSomething; + + $foundSomething = true; + } elseif ($foundSomething) { + $foundSomething = $this->end(); + } + + if ($foundSomething) { + return true; + } + } + + $this->seek($s); + + // closing a block + if ($this->matchChar('}', false)) { + $block = $this->popBlock(); + + if (! isset($block->type) || $block->type !== Type::T_IF) { + assert($this->env !== null); + + if ($this->env->parent) { + $this->append(null); // collect comments before next statement if needed + } + } + + if ($block instanceof ContentBlock) { + $include = $block->child; + assert(\is_array($include)); + unset($block->child); + $include[3] = $block; + $this->append($include, $s); + } elseif (!$block instanceof ElseBlock && !$block instanceof ElseifBlock) { + $type = isset($block->type) ? $block->type : Type::T_BLOCK; + $this->append([$type, $block], $s); + } + + // collect comments just after the block closing if needed + if ($this->eatWhiteDefault) { + $this->whitespace(); + assert($this->env !== null); + + if ($this->env->comments) { + $this->append(null); + } + } + + return true; + } + + // extra stuff + if ($this->matchChar(';')) { + return true; + } + + return false; + } + + /** + * Push block onto parse tree + * + * @param array|null $selectors + * @param int $pos + * + * @return Block + */ + protected function pushBlock($selectors, $pos = 0) + { + $b = new Block(); + $b->selectors = $selectors; + + $this->registerPushedBlock($b, $pos); + + return $b; + } + + /** + * @param Block $b + * @param int $pos + * + * @return void + */ + private function registerPushedBlock(Block $b, $pos) + { + list($line, $column) = $this->getSourcePosition($pos); + + $b->sourceName = $this->sourceName; + $b->sourceLine = $line; + $b->sourceColumn = $column; + $b->sourceIndex = $this->sourceIndex; + $b->comments = []; + $b->parent = $this->env; + + if (! $this->env) { + $b->children = []; + } elseif (empty($this->env->children)) { + $this->env->children = $this->env->comments; + $b->children = []; + $this->env->comments = []; + } else { + $b->children = $this->env->comments; + $this->env->comments = []; + } + + $this->env = $b; + + // collect comments at the beginning of a block if needed + if ($this->eatWhiteDefault) { + $this->whitespace(); + assert($this->env !== null); + + if ($this->env->comments) { + $this->append(null); + } + } + } + + /** + * Push special (named) block onto parse tree + * + * @deprecated + * + * @param string $type + * @param int $pos + * + * @return Block + */ + protected function pushSpecialBlock($type, $pos) + { + $block = $this->pushBlock(null, $pos); + $block->type = $type; + + return $block; + } + + /** + * Pop scope and return last block + * + * @return Block + * + * @throws \Exception + */ + protected function popBlock() + { + assert($this->env !== null); + + // collect comments ending just before of a block closing + if ($this->env->comments) { + $this->append(null); + } + + // pop the block + $block = $this->env; + + if (empty($block->parent)) { + throw $this->parseError('unexpected }'); + } + + if ($block->type == Type::T_AT_ROOT) { + // keeps the parent in case of self selector & + $block->selfParent = $block->parent; + } + + $this->env = $block->parent; + + unset($block->parent); + + return $block; + } + + /** + * Peek input stream + * + * @param string $regex + * @param array $out + * @param int $from + * + * @return int + */ + protected function peek($regex, &$out, $from = null) + { + if (! isset($from)) { + $from = $this->count; + } + + $r = '/' . $regex . '/' . $this->patternModifiers; + $result = preg_match($r, $this->buffer, $out, 0, $from); + + return $result; + } + + /** + * Seek to position in input stream (or return current position in input stream) + * + * @param int $where + * + * @return void + */ + protected function seek($where) + { + $this->count = $where; + } + + /** + * Assert a parsed part is plain CSS Valid + * + * @param array|Number|false $parsed + * @param int $startPos + * + * @return array|Number + * + * @throws ParserException + */ + protected function assertPlainCssValid($parsed, $startPos = null) + { + $type = ''; + if ($parsed) { + $type = $parsed[0]; + $parsed = $this->isPlainCssValidElement($parsed); + } + if (! $parsed) { + if (! \is_null($startPos)) { + $plain = rtrim(substr($this->buffer, $startPos, $this->count - $startPos)); + $message = "Error : `{$plain}` isn't allowed in plain CSS"; + } else { + $message = 'Error: SCSS syntax not allowed in CSS file'; + } + if ($type) { + $message .= " ($type)"; + } + throw $this->parseError($message); + } + + return $parsed; + } + + /** + * Check a parsed element is plain CSS Valid + * + * @param array|Number|string $parsed + * @param bool $allowExpression + * + * @return ($parsed is string ? string : ($parsed is Number ? Number : array|false)) + */ + protected function isPlainCssValidElement($parsed, $allowExpression = false) + { + // keep string as is + if (is_string($parsed)) { + return $parsed; + } + + if ($parsed instanceof Number) { + return $parsed; + } + + if ( + \in_array($parsed[0], [Type::T_FUNCTION, Type::T_FUNCTION_CALL]) && + !\in_array($parsed[1], [ + 'alpha', + 'attr', + 'calc', + 'cubic-bezier', + 'env', + 'grayscale', + 'hsl', + 'hsla', + 'hwb', + 'invert', + 'linear-gradient', + 'min', + 'max', + 'radial-gradient', + 'repeating-linear-gradient', + 'repeating-radial-gradient', + 'rgb', + 'rgba', + 'rotate', + 'saturate', + 'var', + ]) && + Compiler::isNativeFunction($parsed[1]) + ) { + return false; + } + + switch ($parsed[0]) { + case Type::T_BLOCK: + case Type::T_KEYWORD: + case Type::T_NULL: + case Type::T_NUMBER: + case Type::T_MEDIA: + return $parsed; + + case Type::T_COMMENT: + if (isset($parsed[2])) { + return false; + } + return $parsed; + + case Type::T_DIRECTIVE: + if (\is_array($parsed[1])) { + $parsed[1][1] = $this->isPlainCssValidElement($parsed[1][1]); + if (! $parsed[1][1]) { + return false; + } + } + + return $parsed; + + case Type::T_IMPORT: + if ($parsed[1][0] === Type::T_LIST) { + return false; + } + $parsed[1] = $this->isPlainCssValidElement($parsed[1]); + if ($parsed[1] === false) { + return false; + } + return $parsed; + + case Type::T_STRING: + foreach ($parsed[2] as $k => $substr) { + if (\is_array($substr)) { + $parsed[2][$k] = $this->isPlainCssValidElement($substr); + if (! $parsed[2][$k]) { + return false; + } + } + } + return $parsed; + + case Type::T_LIST: + if (!empty($parsed['enclosing'])) { + return false; + } + foreach ($parsed[2] as $k => $listElement) { + $parsed[2][$k] = $this->isPlainCssValidElement($listElement); + if (! $parsed[2][$k]) { + return false; + } + } + return $parsed; + + case Type::T_ASSIGN: + foreach ([1, 2, 3] as $k) { + if (! empty($parsed[$k])) { + $parsed[$k] = $this->isPlainCssValidElement($parsed[$k]); + if (! $parsed[$k]) { + return false; + } + } + } + return $parsed; + + case Type::T_EXPRESSION: + list( ,$op, $lhs, $rhs, $inParens, $whiteBefore, $whiteAfter) = $parsed; + if (! $allowExpression && ! \in_array($op, ['and', 'or', '/'])) { + return false; + } + $lhs = $this->isPlainCssValidElement($lhs, true); + if (! $lhs) { + return false; + } + $rhs = $this->isPlainCssValidElement($rhs, true); + if (! $rhs) { + return false; + } + + return [ + Type::T_STRING, + '', [ + $this->inParens ? '(' : '', + $lhs, + ($whiteBefore ? ' ' : '') . $op . ($whiteAfter ? ' ' : ''), + $rhs, + $this->inParens ? ')' : '' + ] + ]; + + case Type::T_CUSTOM_PROPERTY: + case Type::T_UNARY: + $parsed[2] = $this->isPlainCssValidElement($parsed[2]); + if (! $parsed[2]) { + return false; + } + return $parsed; + + case Type::T_FUNCTION: + $argsList = $parsed[2]; + foreach ($argsList[2] as $argElement) { + if (! $this->isPlainCssValidElement($argElement)) { + return false; + } + } + return $parsed; + + case Type::T_FUNCTION_CALL: + $parsed[0] = Type::T_FUNCTION; + $argsList = [Type::T_LIST, ',', []]; + foreach ($parsed[2] as $arg) { + if ($arg[0] || ! empty($arg[2])) { + // no named arguments possible in a css function call + // nor ... argument + return false; + } + $arg = $this->isPlainCssValidElement($arg[1], $parsed[1] === 'calc'); + if (! $arg) { + return false; + } + $argsList[2][] = $arg; + } + $parsed[2] = $argsList; + return $parsed; + } + + return false; + } + + /** + * Match string looking for either ending delim, escape, or string interpolation + * + * {@internal This is a workaround for preg_match's 250K string match limit. }} + * + * @param array $m Matches (passed by reference) + * @param string $delim Delimiter + * + * @return bool True if match; false otherwise + * + * @phpstan-impure + */ + protected function matchString(&$m, $delim) + { + $token = null; + + $end = \strlen($this->buffer); + + // look for either ending delim, escape, or string interpolation + foreach (['#{', '\\', "\r", $delim] as $lookahead) { + $pos = strpos($this->buffer, $lookahead, $this->count); + + if ($pos !== false && $pos < $end) { + $end = $pos; + $token = $lookahead; + } + } + + if (! isset($token)) { + return false; + } + + $match = substr($this->buffer, $this->count, $end - $this->count); + $m = [ + $match . $token, + $match, + $token + ]; + $this->count = $end + \strlen($token); + + return true; + } + + /** + * Try to match something on head of buffer + * + * @param string $regex + * @param array $out + * @param bool $eatWhitespace + * + * @return bool + * + * @phpstan-impure + */ + protected function match($regex, &$out, $eatWhitespace = null) + { + $r = '/' . $regex . '/' . $this->patternModifiers; + + if (! preg_match($r, $this->buffer, $out, 0, $this->count)) { + return false; + } + + $this->count += \strlen($out[0]); + + if (! isset($eatWhitespace)) { + $eatWhitespace = $this->eatWhiteDefault; + } + + if ($eatWhitespace) { + $this->whitespace(); + } + + return true; + } + + /** + * Match a single string + * + * @param string $char + * @param bool $eatWhitespace + * + * @return bool + * + * @phpstan-impure + */ + protected function matchChar($char, $eatWhitespace = null) + { + if (! isset($this->buffer[$this->count]) || $this->buffer[$this->count] !== $char) { + return false; + } + + $this->count++; + + if (! isset($eatWhitespace)) { + $eatWhitespace = $this->eatWhiteDefault; + } + + if ($eatWhitespace) { + $this->whitespace(); + } + + return true; + } + + /** + * Match literal string + * + * @param string $what + * @param int $len + * @param bool $eatWhitespace + * + * @return bool + * + * @phpstan-impure + */ + protected function literal($what, $len, $eatWhitespace = null) + { + if (strcasecmp(substr($this->buffer, $this->count, $len), $what) !== 0) { + return false; + } + + $this->count += $len; + + if (! isset($eatWhitespace)) { + $eatWhitespace = $this->eatWhiteDefault; + } + + if ($eatWhitespace) { + $this->whitespace(); + } + + return true; + } + + /** + * Match some whitespace + * + * @return bool + * + * @phpstan-impure + */ + protected function whitespace() + { + $gotWhite = false; + + while (preg_match(static::$whitePattern, $this->buffer, $m, 0, $this->count)) { + if (isset($m[1]) && empty($this->commentsSeen[$this->count])) { + // comment that are kept in the output CSS + $comment = []; + $startCommentCount = $this->count; + $endCommentCount = $this->count + \strlen($m[1]); + + // find interpolations in comment + $p = strpos($this->buffer, '#{', $this->count); + + while ($p !== false && $p < $endCommentCount) { + $c = substr($this->buffer, $this->count, $p - $this->count); + $comment[] = $c; + $this->count = $p; + $out = null; + + if ($this->interpolation($out)) { + // keep right spaces in the following string part + if ($out[3]) { + while ($this->buffer[$this->count - 1] !== '}') { + $this->count--; + } + + $out[3] = ''; + } + + $comment[] = [Type::T_COMMENT, substr($this->buffer, $p, $this->count - $p), $out]; + } else { + list($line, $column) = $this->getSourcePosition($this->count); + $file = $this->sourceName; + if (!$this->discardComments) { + $this->logger->warn("Unterminated interpolations in multiline comments are deprecated and will be removed in ScssPhp 2.0, in \"$file\", line $line, column $column.", true); + } + $comment[] = substr($this->buffer, $this->count, 2); + + $this->count += 2; + } + + $p = strpos($this->buffer, '#{', $this->count); + } + + // remaining part + $c = substr($this->buffer, $this->count, $endCommentCount - $this->count); + + if (! $comment) { + // single part static comment + $commentStatement = [Type::T_COMMENT, $c]; + } else { + $comment[] = $c; + $staticComment = substr($this->buffer, $startCommentCount, $endCommentCount - $startCommentCount); + $commentStatement = [Type::T_COMMENT, $staticComment, [Type::T_STRING, '', $comment]]; + } + + list($line, $column) = $this->getSourcePosition($startCommentCount); + $commentStatement[self::SOURCE_LINE] = $line; + $commentStatement[self::SOURCE_COLUMN] = $column; + $commentStatement[self::SOURCE_INDEX] = $this->sourceIndex; + + $this->appendComment($commentStatement); + + $this->commentsSeen[$startCommentCount] = true; + $this->count = $endCommentCount; + } else { + // comment that are ignored and not kept in the output css + $this->count += \strlen($m[0]); + // silent comments are not allowed in plain CSS files + ! $this->cssOnly + || ! \strlen(trim($m[0])) + || $this->assertPlainCssValid(false, $this->count - \strlen($m[0])); + } + + $gotWhite = true; + } + + return $gotWhite; + } + + /** + * Append comment to current block + * + * @param array $comment + * + * @return void + */ + protected function appendComment($comment) + { + if (! $this->discardComments) { + assert($this->env !== null); + + $this->env->comments[] = $comment; + } + } + + /** + * Append statement to current block + * + * @param array|null $statement + * @param int $pos + * + * @return void + */ + protected function append($statement, $pos = null) + { + assert($this->env !== null); + + if (! \is_null($statement)) { + ! $this->cssOnly || ($statement = $this->assertPlainCssValid($statement, $pos)); + + if (! \is_null($pos)) { + list($line, $column) = $this->getSourcePosition($pos); + + $statement[static::SOURCE_LINE] = $line; + $statement[static::SOURCE_COLUMN] = $column; + $statement[static::SOURCE_INDEX] = $this->sourceIndex; + } + + $this->env->children[] = $statement; + } + + $comments = $this->env->comments; + + if ($comments) { + $this->env->children = array_merge($this->env->children, $comments); + $this->env->comments = []; + } + } + + /** + * Returns last child was appended + * + * @return array|null + */ + protected function last() + { + assert($this->env !== null); + + $i = \count($this->env->children) - 1; + + if (isset($this->env->children[$i])) { + return $this->env->children[$i]; + } + + return null; + } + + /** + * Parse media query list + * + * @param array $out + * + * @return bool + */ + protected function mediaQueryList(&$out) + { + return $this->genericList($out, 'mediaQuery', ',', false); + } + + /** + * Parse media query + * + * @param array $out + * + * @return bool + */ + protected function mediaQuery(&$out) + { + $expressions = null; + $parts = []; + + if ( + ($this->literal('only', 4) && ($only = true) || + $this->literal('not', 3) && ($not = true) || true) && + $this->mixedKeyword($mediaType) + ) { + $prop = [Type::T_MEDIA_TYPE]; + + if (isset($only)) { + $prop[] = [Type::T_KEYWORD, 'only']; + } + + if (isset($not)) { + $prop[] = [Type::T_KEYWORD, 'not']; + } + + $media = [Type::T_LIST, '', []]; + + foreach ((array) $mediaType as $type) { + if (\is_array($type)) { + $media[2][] = $type; + } else { + $media[2][] = [Type::T_KEYWORD, $type]; + } + } + + $prop[] = $media; + $parts[] = $prop; + } + + if (empty($parts) || $this->literal('and', 3)) { + $this->genericList($expressions, 'mediaExpression', 'and', false); + + if (\is_array($expressions)) { + $parts = array_merge($parts, $expressions[2]); + } + } + + $out = $parts; + + return true; + } + + /** + * Parse supports query + * + * @param array $out + * + * @return bool + */ + protected function supportsQuery(&$out) + { + $expressions = null; + $parts = []; + + $s = $this->count; + + $not = false; + + if ( + ($this->literal('not', 3) && ($not = true) || true) && + $this->matchChar('(') && + ($this->expression($property)) && + $this->literal(': ', 2) && + $this->valueList($value) && + $this->matchChar(')') + ) { + $support = [Type::T_STRING, '', [[Type::T_KEYWORD, ($not ? 'not ' : '') . '(']]]; + $support[2][] = $property; + $support[2][] = [Type::T_KEYWORD, ': ']; + $support[2][] = $value; + $support[2][] = [Type::T_KEYWORD, ')']; + + $parts[] = $support; + $s = $this->count; + } else { + $this->seek($s); + } + + if ( + $this->matchChar('(') && + $this->supportsQuery($subQuery) && + $this->matchChar(')') + ) { + $parts[] = [Type::T_STRING, '', [[Type::T_KEYWORD, '('], $subQuery, [Type::T_KEYWORD, ')']]]; + $s = $this->count; + } else { + $this->seek($s); + } + + if ( + $this->literal('not', 3) && + $this->supportsQuery($subQuery) + ) { + $parts[] = [Type::T_STRING, '', [[Type::T_KEYWORD, 'not '], $subQuery]]; + $s = $this->count; + } else { + $this->seek($s); + } + + if ( + $this->literal('selector(', 9) && + $this->selector($selector) && + $this->matchChar(')') + ) { + $support = [Type::T_STRING, '', [[Type::T_KEYWORD, 'selector(']]]; + + $selectorList = [Type::T_LIST, '', []]; + + foreach ($selector as $sc) { + $compound = [Type::T_STRING, '', []]; + + foreach ($sc as $scp) { + if (\is_array($scp)) { + $compound[2][] = $scp; + } else { + $compound[2][] = [Type::T_KEYWORD, $scp]; + } + } + + $selectorList[2][] = $compound; + } + + $support[2][] = $selectorList; + $support[2][] = [Type::T_KEYWORD, ')']; + $parts[] = $support; + $s = $this->count; + } else { + $this->seek($s); + } + + if ($this->variable($var) or $this->interpolation($var)) { + $parts[] = $var; + $s = $this->count; + } else { + $this->seek($s); + } + + if ( + $this->literal('and', 3) && + $this->genericList($expressions, 'supportsQuery', ' and', false) + ) { + array_unshift($expressions[2], [Type::T_STRING, '', $parts]); + + $parts = [$expressions]; + $s = $this->count; + } else { + $this->seek($s); + } + + if ( + $this->literal('or', 2) && + $this->genericList($expressions, 'supportsQuery', ' or', false) + ) { + array_unshift($expressions[2], [Type::T_STRING, '', $parts]); + + $parts = [$expressions]; + $s = $this->count; + } else { + $this->seek($s); + } + + if (\count($parts)) { + if ($this->eatWhiteDefault) { + $this->whitespace(); + } + + $out = [Type::T_STRING, '', $parts]; + + return true; + } + + return false; + } + + + /** + * Parse media expression + * + * @param array $out + * + * @return bool + */ + protected function mediaExpression(&$out) + { + $s = $this->count; + $value = null; + + if ( + $this->matchChar('(') && + $this->expression($feature) && + ($this->matchChar(':') && + $this->expression($value) || true) && + $this->matchChar(')') + ) { + $out = [Type::T_MEDIA_EXPRESSION, $feature]; + + if ($value) { + $out[] = $value; + } + + return true; + } + + $this->seek($s); + + return false; + } + + /** + * Parse argument values + * + * @param array $out + * + * @return bool + */ + protected function argValues(&$out) + { + $discardComments = $this->discardComments; + $this->discardComments = true; + + if ($this->genericList($list, 'argValue', ',', false)) { + $out = $list[2]; + + $this->discardComments = $discardComments; + + return true; + } + + $this->discardComments = $discardComments; + + return false; + } + + /** + * Parse argument value + * + * @param array $out + * + * @return bool + */ + protected function argValue(&$out) + { + $s = $this->count; + + $keyword = null; + + if (! $this->variable($keyword) || ! $this->matchChar(':')) { + $this->seek($s); + + $keyword = null; + } + + if ($this->genericList($value, 'expression', '', true)) { + $out = [$keyword, $value, false]; + $s = $this->count; + + if ($this->literal('...', 3)) { + $out[2] = true; + } else { + $this->seek($s); + } + + return true; + } + + return false; + } + + /** + * Check if a generic directive is known to be able to allow almost any syntax or not + * @param mixed $directiveName + * @return bool + */ + protected function isKnownGenericDirective($directiveName) + { + if (\is_array($directiveName) && \is_string(reset($directiveName))) { + $directiveName = reset($directiveName); + } + if (! \is_string($directiveName)) { + return false; + } + if ( + \in_array($directiveName, [ + 'at-root', + 'media', + 'mixin', + 'include', + 'scssphp-import-once', + 'import', + 'extend', + 'function', + 'break', + 'continue', + 'return', + 'each', + 'while', + 'for', + 'if', + 'debug', + 'warn', + 'error', + 'content', + 'else', + 'charset', + 'supports', + // Todo + 'use', + 'forward', + ]) + ) { + return true; + } + return false; + } + + /** + * Parse directive value list that considers $vars as keyword + * + * @param mixed $out + * @param string|false $endChar + * @param-out array|Number $out + * + * @return bool + * + * @phpstan-impure + */ + protected function directiveValue(&$out, $endChar = false) + { + $s = $this->count; + + if ($this->variable($out)) { + if ($endChar && $this->matchChar($endChar, false)) { + return true; + } + + if (! $endChar && $this->end()) { + return true; + } + } + + $this->seek($s); + + if (\is_string($endChar) && $this->openString($endChar ? $endChar : ';', $out, null, null, true, ";}{")) { + if ($endChar && $this->matchChar($endChar, false)) { + return true; + } + $ss = $this->count; + if (!$endChar && $this->end()) { + $this->seek($ss); + return true; + } + } + + $this->seek($s); + + $allowVars = $this->allowVars; + $this->allowVars = false; + + $res = $this->genericList($out, 'spaceList', ','); + $this->allowVars = $allowVars; + + if ($res) { + if ($endChar && $this->matchChar($endChar, false)) { + return true; + } + + if (! $endChar && $this->end()) { + return true; + } + } + + $this->seek($s); + + if ($endChar && $this->matchChar($endChar, false)) { + return true; + } + + return false; + } + + /** + * Parse comma separated value list + * + * @param mixed $out + * @param-out array|Number $out + * + * @return bool + */ + protected function valueList(&$out) + { + $discardComments = $this->discardComments; + $this->discardComments = true; + $res = $this->genericList($out, 'spaceList', ','); + $this->discardComments = $discardComments; + + return $res; + } + + /** + * Parse a function call, where externals () are part of the call + * and not of the value list + * + * @param mixed $out + * @param bool $mandatoryEnclos + * @param null|string $charAfter + * @param null|bool $eatWhiteSp + * @param-out array|Number $out + * + * @return bool + */ + protected function functionCallArgumentsList(&$out, $mandatoryEnclos = true, $charAfter = null, $eatWhiteSp = null) + { + $s = $this->count; + + if ( + $this->matchChar('(') && + $this->valueList($out) && + $this->matchChar(')') && + ($charAfter ? $this->matchChar($charAfter, $eatWhiteSp) : $this->end()) + ) { + return true; + } + + if (! $mandatoryEnclos) { + $this->seek($s); + + if ( + $this->valueList($out) && + ($charAfter ? $this->matchChar($charAfter, $eatWhiteSp) : $this->end()) + ) { + return true; + } + } + + $this->seek($s); + + return false; + } + + /** + * Parse space separated value list + * + * @param mixed $out + * @param-out array|Number $out + * + * @return bool + */ + protected function spaceList(&$out) + { + return $this->genericList($out, 'expression'); + } + + /** + * Parse generic list + * + * @param mixed $out + * @param string $parseItem The name of the method used to parse items + * @param string $delim + * @param bool $flatten + * @param-out ($flatten is false ? array : array|Number) $out + * + * @return bool + */ + protected function genericList(&$out, $parseItem, $delim = '', $flatten = true) + { + $s = $this->count; + $items = []; + /** @var array|Number|null $value */ + $value = null; + + while ($this->$parseItem($value)) { + $trailing_delim = false; + $items[] = $value; + + if ($delim) { + if (! $this->literal($delim, \strlen($delim))) { + break; + } + + $trailing_delim = true; + } else { + assert(\is_array($value) || $value instanceof Number); + // if no delim watch that a keyword didn't eat the single/double quote + // from the following starting string + if ($value[0] === Type::T_KEYWORD) { + assert(\is_array($value)); + /** @var string $word */ + $word = $value[1]; + + $last_char = substr($word, -1); + + if ( + strlen($word) > 1 && + in_array($last_char, [ "'", '"']) && + substr($word, -2, 1) !== '\\' + ) { + // if there is a non escaped opening quote in the keyword, this seems unlikely a mistake + $word = str_replace('\\' . $last_char, '\\\\', $word); + if (strpos($word, $last_char) < strlen($word) - 1) { + continue; + } + + $currentCount = $this->count; + + // let's try to rewind to previous char and try a parse + $this->count--; + // in case the keyword also eat spaces + while (substr($this->buffer, $this->count, 1) !== $last_char) { + $this->count--; + } + + /** @var array|Number|null $nextValue */ + $nextValue = null; + if ($this->$parseItem($nextValue)) { + assert(\is_array($nextValue) || $nextValue instanceof Number); + if ($nextValue[0] === Type::T_KEYWORD && $nextValue[1] === $last_char) { + // bad try, forget it + $this->seek($currentCount); + continue; + } + if ($nextValue[0] !== Type::T_STRING) { + // bad try, forget it + $this->seek($currentCount); + continue; + } + + // OK it was a good idea + $value[1] = substr($value[1], 0, -1); + array_pop($items); + $items[] = $value; + $items[] = $nextValue; + } else { + // bad try, forget it + $this->seek($currentCount); + continue; + } + } + } + } + } + + if (! $items) { + $this->seek($s); + + return false; + } + + if ($trailing_delim) { + $items[] = [Type::T_NULL]; + } + + if ($flatten && \count($items) === 1) { + $out = $items[0]; + } else { + $out = [Type::T_LIST, $delim, $items]; + } + + return true; + } + + /** + * Parse expression + * + * @param mixed $out + * @param bool $listOnly + * @param bool $lookForExp + * @param-out array|Number $out + * + * @return bool + * + * @phpstan-impure + */ + protected function expression(&$out, $listOnly = false, $lookForExp = true) + { + $s = $this->count; + $discard = $this->discardComments; + $this->discardComments = true; + $allowedTypes = ($listOnly ? [Type::T_LIST] : [Type::T_LIST, Type::T_MAP]); + + if ($this->matchChar('(')) { + if ($this->enclosedExpression($lhs, $s, ')', $allowedTypes)) { + if ($lookForExp) { + $out = $this->expHelper($lhs, 0); + } else { + $out = $lhs; + } + + $this->discardComments = $discard; + + return true; + } + + $this->seek($s); + } + + if (\in_array(Type::T_LIST, $allowedTypes) && $this->matchChar('[')) { + if ($this->enclosedExpression($lhs, $s, ']', [Type::T_LIST])) { + if ($lookForExp) { + $out = $this->expHelper($lhs, 0); + } else { + $out = $lhs; + } + + $this->discardComments = $discard; + + return true; + } + + $this->seek($s); + } + + if (! $listOnly && $this->value($lhs)) { + if ($lookForExp) { + $out = $this->expHelper($lhs, 0); + } else { + $out = $lhs; + } + + $this->discardComments = $discard; + + return true; + } + + $this->discardComments = $discard; + + return false; + } + + /** + * Parse expression specifically checking for lists in parenthesis or brackets + * + * @param mixed $out + * @param int $s + * @param string $closingParen + * @param string[] $allowedTypes + * @param-out array|Number $out + * + * @return bool + * + * @phpstan-param array $allowedTypes + */ + protected function enclosedExpression(&$out, $s, $closingParen = ')', $allowedTypes = [Type::T_LIST, Type::T_MAP]) + { + if ($this->matchChar($closingParen) && \in_array(Type::T_LIST, $allowedTypes)) { + $out = [Type::T_LIST, '', []]; + + switch ($closingParen) { + case ')': + $out['enclosing'] = 'parent'; // parenthesis list + break; + + case ']': + $out['enclosing'] = 'bracket'; // bracketed list + break; + } + + return true; + } + + if ( + $this->valueList($out) && + $this->matchChar($closingParen) && ! ($closingParen === ')' && + \in_array($out[0], [Type::T_EXPRESSION, Type::T_UNARY])) && + \in_array(Type::T_LIST, $allowedTypes) + ) { + if ($out[0] !== Type::T_LIST || ! empty($out['enclosing'])) { + $out = [Type::T_LIST, '', [$out]]; + } + + switch ($closingParen) { + case ')': + $out['enclosing'] = 'parent'; // parenthesis list + break; + + case ']': + $out['enclosing'] = 'bracket'; // bracketed list + break; + } + + return true; + } + + $this->seek($s); + + if (\in_array(Type::T_MAP, $allowedTypes) && $this->map($out)) { + return true; + } + + return false; + } + + /** + * Parse left-hand side of subexpression + * + * @param array|Number $lhs + * @param int $minP + * + * @return array|Number + */ + protected function expHelper($lhs, $minP) + { + $operators = static::$operatorPattern; + + $ss = $this->count; + $whiteBefore = isset($this->buffer[$this->count - 1]) && + ctype_space($this->buffer[$this->count - 1]); + + while ($this->match($operators, $m, false) && static::$precedence[strtolower($m[1])] >= $minP) { + $whiteAfter = isset($this->buffer[$this->count]) && + ctype_space($this->buffer[$this->count]); + $varAfter = isset($this->buffer[$this->count]) && + $this->buffer[$this->count] === '$'; + + $this->whitespace(); + + $op = $m[1]; + + // don't turn negative numbers into expressions + if ($op === '-' && $whiteBefore && ! $whiteAfter && ! $varAfter) { + break; + } + + if (! $this->value($rhs) && ! $this->expression($rhs, true, false)) { + break; + } + + if ($op === '-' && ! $whiteAfter && $rhs[0] === Type::T_KEYWORD) { + break; + } + + // consume higher-precedence operators on the right-hand side + $rhs = $this->expHelper($rhs, static::$precedence[strtolower($op)] + 1); + + $lhs = [Type::T_EXPRESSION, $op, $lhs, $rhs, $this->inParens, $whiteBefore, $whiteAfter]; + + $ss = $this->count; + $whiteBefore = isset($this->buffer[$this->count - 1]) && + ctype_space($this->buffer[$this->count - 1]); + } + + $this->seek($ss); + + return $lhs; + } + + /** + * Parse value + * + * @param mixed $out + * @param-out array|Number $out + * + * @return bool + */ + protected function value(&$out) + { + if (! isset($this->buffer[$this->count])) { + return false; + } + + $s = $this->count; + $char = $this->buffer[$this->count]; + + if ( + $this->literal('url(', 4) && + $this->match('data:([a-z]+)\/([a-z0-9.+-]+);base64,', $m, false) + ) { + $len = strspn( + $this->buffer, + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwyxz0123456789+/=', + $this->count + ); + + $this->count += $len; + + if ($this->matchChar(')')) { + $content = substr($this->buffer, $s, $this->count - $s); + $out = [Type::T_KEYWORD, $content]; + + return true; + } + } + + $this->seek($s); + + if ( + $this->literal('url(', 4, false) && + $this->match('\s*(\/\/[^\s\)]+)\s*', $m) + ) { + $content = 'url(' . $m[1]; + + if ($this->matchChar(')')) { + $content .= ')'; + $out = [Type::T_KEYWORD, $content]; + + return true; + } + } + + $this->seek($s); + + // not + if ($char === 'n' && $this->literal('not', 3, false)) { + if ( + $this->whitespace() && + $this->value($inner) + ) { + $out = [Type::T_UNARY, 'not', $inner, $this->inParens]; + + return true; + } + + $this->seek($s); + + if ($this->parenValue($inner)) { + $out = [Type::T_UNARY, 'not', $inner, $this->inParens]; + + return true; + } + + $this->seek($s); + } + + // addition + if ($char === '+') { + $this->count++; + + $follow_white = $this->whitespace(); + + if ($this->value($inner)) { + $out = [Type::T_UNARY, '+', $inner, $this->inParens]; + + return true; + } + + if ($follow_white) { + $out = [Type::T_KEYWORD, $char]; + return true; + } + + $this->seek($s); + + return false; + } + + // negation + if ($char === '-') { + if ($this->customProperty($out)) { + return true; + } + + $this->count++; + + $follow_white = $this->whitespace(); + + if ($this->variable($inner) || $this->unit($inner) || $this->parenValue($inner)) { + $out = [Type::T_UNARY, '-', $inner, $this->inParens]; + + return true; + } + + if ( + $this->keyword($inner) && + ! $this->func($inner, $out) + ) { + $out = [Type::T_UNARY, '-', $inner, $this->inParens]; + + return true; + } + + if ($follow_white) { + $out = [Type::T_KEYWORD, $char]; + + return true; + } + + $this->seek($s); + } + + // paren + if ($char === '(' && $this->parenValue($out)) { + return true; + } + + if ($char === '#') { + if ($this->interpolation($out) || $this->color($out)) { + return true; + } + + $this->count++; + + if ($this->keyword($keyword)) { + $out = [Type::T_KEYWORD, '#' . $keyword]; + + return true; + } + + $this->count--; + } + + if ($this->matchChar('&', true)) { + $out = [Type::T_SELF]; + + return true; + } + + if ($char === '$' && $this->variable($out)) { + return true; + } + + if ($char === 'p' && $this->progid($out)) { + return true; + } + + if (($char === '"' || $char === "'") && $this->string($out)) { + return true; + } + + if ($this->unit($out)) { + return true; + } + + // unicode range with wildcards + if ( + $this->literal('U+', 2) && + $this->match('\?+|([0-9A-F]+(\?+|(-[0-9A-F]+))?)', $m, false) + ) { + $unicode = explode('-', $m[0]); + if (strlen(reset($unicode)) <= 6 && strlen(end($unicode)) <= 6) { + $out = [Type::T_KEYWORD, 'U+' . $m[0]]; + + return true; + } + $this->count -= strlen($m[0]) + 2; + } + + if ($this->keyword($keyword, false)) { + if ($this->func($keyword, $out)) { + return true; + } + + $this->whitespace(); + + if ($keyword === 'null') { + $out = [Type::T_NULL]; + } else { + $out = [Type::T_KEYWORD, $keyword]; + } + + return true; + } + + return false; + } + + /** + * Parse parenthesized value + * + * @param mixed $out + * @param-out array|Number $out + * + * @return bool + */ + protected function parenValue(&$out) + { + $s = $this->count; + + $inParens = $this->inParens; + + if ($this->matchChar('(')) { + if ($this->matchChar(')')) { + $out = [Type::T_LIST, '', []]; + + return true; + } + + $this->inParens = true; + + if ( + $this->expression($exp) && + $this->matchChar(')') + ) { + $out = $exp; + $this->inParens = $inParens; + + return true; + } + } + + $this->inParens = $inParens; + $this->seek($s); + + return false; + } + + /** + * Parse "progid:" + * + * @param array $out + * + * @return bool + */ + protected function progid(&$out) + { + $s = $this->count; + + if ( + $this->literal('progid:', 7, false) && + $this->openString('(', $fn) && + $this->matchChar('(') + ) { + $this->openString(')', $args, '('); + + if ($this->matchChar(')')) { + $out = [Type::T_STRING, '', [ + 'progid:', $fn, '(', $args, ')' + ]]; + + return true; + } + } + + $this->seek($s); + + return false; + } + + /** + * Parse function call + * + * @param string $name + * @param mixed $func + * @param-out array $func + * + * @return bool + */ + protected function func($name, &$func) + { + $s = $this->count; + + if ($this->matchChar('(')) { + if ($name === 'alpha' && $this->argumentList($args)) { + $func = [Type::T_FUNCTION, $name, [Type::T_STRING, '', $args]]; + + return true; + } + + if ($name !== 'expression' && ! preg_match('/^(-[a-z]+-)?calc$/', $name)) { + $ss = $this->count; + + if ( + $this->argValues($args) && + $this->matchChar(')') + ) { + if (strtolower($name) === 'var' && \count($args) === 2 && $args[1][0] === Type::T_NULL) { + $args[1] = [null, [Type::T_STRING, '', [' ']], false]; + } + + $func = [Type::T_FUNCTION_CALL, $name, $args]; + + return true; + } + + $this->seek($ss); + } + + if ( + ($this->openString(')', $str, '(') || true) && + $this->matchChar(')') + ) { + $args = []; + + if (! empty($str)) { + $args[] = [null, [Type::T_STRING, '', [$str]]]; + } + + $func = [Type::T_FUNCTION_CALL, $name, $args]; + + return true; + } + } + + $this->seek($s); + + return false; + } + + /** + * Parse function call argument list + * + * @param array $out + * + * @return bool + */ + protected function argumentList(&$out) + { + $s = $this->count; + $this->matchChar('('); + + $args = []; + + while ($this->keyword($var)) { + if ( + $this->matchChar('=') && + $this->expression($exp) + ) { + $args[] = [Type::T_STRING, '', [$var . '=']]; + $arg = $exp; + } else { + break; + } + + $args[] = $arg; + + if (! $this->matchChar(',')) { + break; + } + + $args[] = [Type::T_STRING, '', [', ']]; + } + + if (! $this->matchChar(')') || ! $args) { + $this->seek($s); + + return false; + } + + $out = $args; + + return true; + } + + /** + * Parse mixin/function definition argument list + * + * @param mixed $out + * @param-out list $out + * + * @return bool + */ + protected function argumentDef(&$out) + { + $s = $this->count; + $this->matchChar('('); + + $args = []; + + while ($this->variable($var)) { + $arg = [$var[1], null, false]; + + $ss = $this->count; + + if ( + $this->matchChar(':') && + $this->genericList($defaultVal, 'expression', '', true) + ) { + $arg[1] = $defaultVal; + } else { + $this->seek($ss); + } + + $ss = $this->count; + + if ($this->literal('...', 3)) { + $sss = $this->count; + + if (! $this->matchChar(')')) { + throw $this->parseError('... has to be after the final argument'); + } + + $arg[2] = true; + + $this->seek($sss); + } else { + $this->seek($ss); + } + + $args[] = $arg; + + if (! $this->matchChar(',')) { + break; + } + } + + if (! $this->matchChar(')')) { + $this->seek($s); + + return false; + } + + $out = $args; + + return true; + } + + /** + * Parse map + * + * @param mixed $out + * @param-out array $out + * + * @return bool + */ + protected function map(&$out) + { + $s = $this->count; + + if (! $this->matchChar('(')) { + return false; + } + + $keys = []; + $values = []; + + while ( + $this->genericList($key, 'expression', '', true) && + $this->matchChar(':') && + $this->genericList($value, 'expression', '', true) + ) { + $keys[] = $key; + $values[] = $value; + + if (! $this->matchChar(',')) { + break; + } + } + + if (! $keys || ! $this->matchChar(')')) { + $this->seek($s); + + return false; + } + + $out = [Type::T_MAP, $keys, $values]; + + return true; + } + + /** + * Parse color + * + * @param mixed $out + * @param-out array $out + * + * @return bool + */ + protected function color(&$out) + { + $s = $this->count; + + if ($this->match('(#([0-9a-f]+)\b)', $m)) { + if (\in_array(\strlen($m[2]), [3,4,6,8])) { + $out = [Type::T_KEYWORD, $m[0]]; + + return true; + } + + $this->seek($s); + + return false; + } + + return false; + } + + /** + * Parse number with unit + * + * @param mixed $unit + * @param-out Number $unit + * + * @return bool + */ + protected function unit(&$unit) + { + $s = $this->count; + + if ($this->match('([0-9]*(\.)?[0-9]+)([%a-zA-Z]+)?', $m, false)) { + if (\strlen($this->buffer) === $this->count || ! ctype_digit($this->buffer[$this->count])) { + $this->whitespace(); + + $unit = new Node\Number($m[1], empty($m[3]) ? '' : $m[3]); + + return true; + } + + $this->seek($s); + } + + return false; + } + + /** + * Parse string + * + * @param array $out + * @param bool $keepDelimWithInterpolation + * + * @return bool + */ + protected function string(&$out, $keepDelimWithInterpolation = false) + { + $s = $this->count; + + if ($this->matchChar('"', false)) { + $delim = '"'; + } elseif ($this->matchChar("'", false)) { + $delim = "'"; + } else { + return false; + } + + $content = []; + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + $hasInterpolation = false; + + while ($this->matchString($m, $delim)) { + if ($m[1] !== '') { + $content[] = $m[1]; + } + + if ($m[2] === '#{') { + $this->count -= \strlen($m[2]); + + if ($this->interpolation($inter, false)) { + $content[] = $inter; + $hasInterpolation = true; + } else { + $this->count += \strlen($m[2]); + $content[] = '#{'; // ignore it + } + } elseif ($m[2] === "\r") { + $content[] = chr(10); + // TODO : warning + # DEPRECATION WARNING on line x, column y of zzz: + # Unescaped multiline strings are deprecated and will be removed in a future version of Sass. + # To include a newline in a string, use "\a" or "\a " as in CSS. + if ($this->matchChar("\n", false)) { + $content[] = ' '; + } + } elseif ($m[2] === '\\') { + if ( + $this->literal("\r\n", 2, false) || + $this->matchChar("\r", false) || + $this->matchChar("\n", false) || + $this->matchChar("\f", false) + ) { + // this is a continuation escaping, to be ignored + } elseif ($this->matchEscapeCharacter($c)) { + $content[] = $c; + } else { + throw $this->parseError('Unterminated escape sequence'); + } + } else { + $this->count -= \strlen($delim); + break; // delim + } + } + + $this->eatWhiteDefault = $oldWhite; + + if ($this->literal($delim, \strlen($delim))) { + if ($hasInterpolation && ! $keepDelimWithInterpolation) { + $delim = '"'; + } + + $out = [Type::T_STRING, $delim, $content]; + + return true; + } + + $this->seek($s); + + return false; + } + + /** + * @param string $out + * @param bool $inKeywords + * + * @return bool + */ + protected function matchEscapeCharacter(&$out, $inKeywords = false) + { + $s = $this->count; + if ($this->match('[a-f0-9]', $m, false)) { + $hex = $m[0]; + + for ($i = 5; $i--;) { + if ($this->match('[a-f0-9]', $m, false)) { + $hex .= $m[0]; + } else { + break; + } + } + + // CSS allows Unicode escape sequences to be followed by a delimiter space + // (necessary in some cases for shorter sequences to disambiguate their end) + $this->matchChar(' ', false); + + $value = hexdec($hex); + + if (!$inKeywords && ($value == 0 || ($value >= 0xD800 && $value <= 0xDFFF) || $value >= 0x10FFFF)) { + $out = "\xEF\xBF\xBD"; // "\u{FFFD}" but with a syntax supported on PHP 5 + } elseif ($value < 0x20) { + $out = Util::mbChr($value); + } else { + $out = Util::mbChr($value); + } + + return true; + } + + if ($this->match('.', $m, false)) { + if ($inKeywords && in_array($m[0], ["'",'"','@','&',' ','\\',':','/','%'])) { + $this->seek($s); + return false; + } + $out = $m[0]; + + return true; + } + + return false; + } + + /** + * Parse keyword or interpolation + * + * @param array $out + * @param bool $restricted + * + * @return bool + */ + protected function mixedKeyword(&$out, $restricted = false) + { + $parts = []; + + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + for (;;) { + if ($restricted ? $this->restrictedKeyword($key) : $this->keyword($key)) { + $parts[] = $key; + continue; + } + + if ($this->interpolation($inter)) { + $parts[] = $inter; + continue; + } + + break; + } + + $this->eatWhiteDefault = $oldWhite; + + if (! $parts) { + return false; + } + + if ($this->eatWhiteDefault) { + $this->whitespace(); + } + + $out = $parts; + + return true; + } + + /** + * Parse an unbounded string stopped by $end + * + * @param string $end + * @param mixed $out + * @param string $nestOpen + * @param string $nestClose + * @param bool $rtrim + * @param string $disallow + * @param-out array $out + * + * @return bool + */ + protected function openString($end, &$out, $nestOpen = null, $nestClose = null, $rtrim = true, $disallow = null) + { + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + if ($nestOpen && ! $nestClose) { + $nestClose = $end; + } + + $patt = ($disallow ? '[^' . $this->pregQuote($disallow) . ']' : '.'); + $patt = '(' . $patt . '*?)([\'"]|#\{|' + . $this->pregQuote($end) . '|' + . (($nestClose && $nestClose !== $end) ? $this->pregQuote($nestClose) . '|' : '') + . static::$commentPattern . ')'; + + $nestingLevel = 0; + + $content = []; + + while ($this->match($patt, $m, false)) { + if (isset($m[1]) && $m[1] !== '') { + $content[] = $m[1]; + + if ($nestOpen) { + $nestingLevel += substr_count($m[1], $nestOpen); + } + } + + $tok = $m[2]; + + $this->count -= \strlen($tok); + + if ($tok === $end && ! $nestingLevel) { + break; + } + + if ($tok === $nestClose) { + $nestingLevel--; + } + + if (($tok === "'" || $tok === '"') && $this->string($str, true)) { + $content[] = $str; + continue; + } + + if ($tok === '#{' && $this->interpolation($inter)) { + $content[] = $inter; + continue; + } + + $content[] = $tok; + $this->count += \strlen($tok); + } + + $this->eatWhiteDefault = $oldWhite; + + if (! $content || $tok !== $end) { + return false; + } + + // trim the end + if ($rtrim && \is_string(end($content))) { + $content[\count($content) - 1] = rtrim(end($content)); + } + + $out = [Type::T_STRING, '', $content]; + + return true; + } + + /** + * Parser interpolation + * + * @param mixed $out + * @param bool $lookWhite save information about whitespace before and after + * @param-out array $out + * + * @return bool + */ + protected function interpolation(&$out, $lookWhite = true) + { + $oldWhite = $this->eatWhiteDefault; + $allowVars = $this->allowVars; + $this->allowVars = true; + $this->eatWhiteDefault = true; + + $s = $this->count; + + if ( + $this->literal('#{', 2) && + $this->valueList($value) && + $this->matchChar('}', false) + ) { + if ($value === [Type::T_SELF]) { + $out = $value; + } else { + if ($lookWhite) { + $left = ($s > 0 && preg_match('/\s/', $this->buffer[$s - 1])) ? ' ' : ''; + $right = ( + ! empty($this->buffer[$this->count]) && + preg_match('/\s/', $this->buffer[$this->count]) + ) ? ' ' : ''; + } else { + $left = $right = false; + } + + $out = [Type::T_INTERPOLATE, $value, $left, $right]; + } + + $this->eatWhiteDefault = $oldWhite; + $this->allowVars = $allowVars; + + if ($this->eatWhiteDefault) { + $this->whitespace(); + } + + return true; + } + + $this->seek($s); + + $this->eatWhiteDefault = $oldWhite; + $this->allowVars = $allowVars; + + return false; + } + + /** + * Parse property name (as an array of parts or a string) + * + * @param array $out + * + * @return bool + */ + protected function propertyName(&$out) + { + $parts = []; + + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + for (;;) { + if ($this->interpolation($inter)) { + $parts[] = $inter; + continue; + } + + if ($this->keyword($text)) { + $parts[] = $text; + continue; + } + + if (! $parts && $this->match('[:.#]', $m, false)) { + // css hacks + $parts[] = $m[0]; + continue; + } + + break; + } + + $this->eatWhiteDefault = $oldWhite; + + if (! $parts) { + return false; + } + + // match comment hack + if (preg_match(static::$whitePattern, $this->buffer, $m, 0, $this->count)) { + if (! empty($m[0])) { + $parts[] = $m[0]; + $this->count += \strlen($m[0]); + } + } + + $this->whitespace(); // get any extra whitespace + + $out = [Type::T_STRING, '', $parts]; + + return true; + } + + /** + * Parse custom property name (as an array of parts or a string) + * + * @param array $out + * + * @return bool + */ + protected function customProperty(&$out) + { + $s = $this->count; + + if (! $this->literal('--', 2, false)) { + return false; + } + + $parts = ['--']; + + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + for (;;) { + if ($this->interpolation($inter)) { + $parts[] = $inter; + continue; + } + + if ($this->matchChar('&', false)) { + $parts[] = [Type::T_SELF]; + continue; + } + + if ($this->variable($var)) { + $parts[] = $var; + continue; + } + + if ($this->keyword($text)) { + $parts[] = $text; + continue; + } + + break; + } + + $this->eatWhiteDefault = $oldWhite; + + if (\count($parts) == 1) { + $this->seek($s); + + return false; + } + + $this->whitespace(); // get any extra whitespace + + $out = [Type::T_STRING, '', $parts]; + + return true; + } + + /** + * Parse comma separated selector list + * + * @param array $out + * @param string|bool $subSelector + * + * @return bool + */ + protected function selectors(&$out, $subSelector = false) + { + $s = $this->count; + $selectors = []; + + while ($this->selector($sel, $subSelector)) { + $selectors[] = $sel; + + if (! $this->matchChar(',', true)) { + break; + } + + while ($this->matchChar(',', true)) { + ; // ignore extra + } + } + + if (! $selectors) { + $this->seek($s); + + return false; + } + + $out = $selectors; + + return true; + } + + /** + * Parse whitespace separated selector list + * + * @param array $out + * @param string|bool $subSelector + * + * @return bool + */ + protected function selector(&$out, $subSelector = false) + { + $selector = []; + + $discardComments = $this->discardComments; + $this->discardComments = true; + + for (;;) { + $s = $this->count; + + if ($this->match('[>+~]+', $m, true)) { + if ( + $subSelector && \is_string($subSelector) && strpos($subSelector, 'nth-') === 0 && + $m[0] === '+' && $this->match("(\d+|n\b)", $counter) + ) { + $this->seek($s); + } else { + $selector[] = [$m[0]]; + continue; + } + } + + if ($this->selectorSingle($part, $subSelector)) { + $selector[] = $part; + $this->whitespace(); + continue; + } + + break; + } + + $this->discardComments = $discardComments; + + if (! $selector) { + return false; + } + + $out = $selector; + + return true; + } + + /** + * parsing escaped chars in selectors: + * - escaped single chars are kept escaped in the selector but in a normalized form + * (if not in 0-9a-f range as this would be ambigous) + * - other escaped sequences (multibyte chars or 0-9a-f) are kept in their initial escaped form, + * normalized to lowercase + * + * TODO: this is a fallback solution. Ideally escaped chars in selectors should be encoded as the genuine chars, + * and escaping added when printing in the Compiler, where/if it's mandatory + * - but this require a better formal selector representation instead of the array we have now + * + * @param string $out + * @param bool $keepEscapedNumber + * + * @return bool + */ + protected function matchEscapeCharacterInSelector(&$out, $keepEscapedNumber = false) + { + $s_escape = $this->count; + if ($this->match('\\\\', $m)) { + $out = '\\' . $m[0]; + return true; + } + + if ($this->matchEscapeCharacter($escapedout, true)) { + if (strlen($escapedout) === 1) { + if (!preg_match(",\w,", $escapedout)) { + $out = '\\' . $escapedout; + return true; + } elseif (! $keepEscapedNumber || ! \is_numeric($escapedout)) { + $out = $escapedout; + return true; + } + } + $escape_sequence = rtrim(substr($this->buffer, $s_escape, $this->count - $s_escape)); + if (strlen($escape_sequence) < 6) { + $escape_sequence .= ' '; + } + $out = '\\' . strtolower($escape_sequence); + return true; + } + if ($this->match('\\S', $m)) { + $out = '\\' . $m[0]; + return true; + } + + + return false; + } + + /** + * Parse the parts that make up a selector + * + * {@internal + * div[yes=no]#something.hello.world:nth-child(-2n+1)%placeholder + * }} + * + * @param array $out + * @param string|bool $subSelector + * + * @return bool + */ + protected function selectorSingle(&$out, $subSelector = false) + { + $oldWhite = $this->eatWhiteDefault; + $this->eatWhiteDefault = false; + + $parts = []; + + if ($this->matchChar('*', false)) { + $parts[] = '*'; + } + + for (;;) { + if (! isset($this->buffer[$this->count])) { + break; + } + + $s = $this->count; + $char = $this->buffer[$this->count]; + + // see if we can stop early + if ($char === '{' || $char === ',' || $char === ';' || $char === '}' || $char === '@') { + break; + } + + // parsing a sub selector in () stop with the closing ) + if ($subSelector && $char === ')') { + break; + } + + //self + switch ($char) { + case '&': + $parts[] = Compiler::$selfSelector; + $this->count++; + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + continue 2; + + case '.': + $parts[] = '.'; + $this->count++; + continue 2; + + case '|': + $parts[] = '|'; + $this->count++; + continue 2; + } + + // handling of escaping in selectors : get the escaped char + if ($char === '\\') { + $this->count++; + if ($this->matchEscapeCharacterInSelector($escaped, true)) { + $parts[] = $escaped; + continue; + } + $this->count--; + } + + if ($char === '%') { + $this->count++; + + if ($this->placeholder($placeholder)) { + $parts[] = '%'; + $parts[] = $placeholder; + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + continue; + } + + break; + } + + if ($char === '#') { + if ($this->interpolation($inter)) { + $parts[] = $inter; + ! $this->cssOnly || $this->assertPlainCssValid(false, $s); + continue; + } + + $parts[] = '#'; + $this->count++; + continue; + } + + // a pseudo selector + if ($char === ':') { + if ($this->buffer[$this->count + 1] === ':') { + $this->count += 2; + $part = '::'; + } else { + $this->count++; + $part = ':'; + } + + if ($this->mixedKeyword($nameParts, true)) { + $parts[] = $part; + + foreach ($nameParts as $sub) { + $parts[] = $sub; + } + + $ss = $this->count; + + if ( + $nameParts === ['not'] || + $nameParts === ['is'] || + $nameParts === ['has'] || + $nameParts === ['where'] || + $nameParts === ['slotted'] || + $nameParts === ['nth-child'] || + $nameParts === ['nth-last-child'] || + $nameParts === ['nth-of-type'] || + $nameParts === ['nth-last-of-type'] + ) { + if ( + $this->matchChar('(', true) && + ($this->selectors($subs, reset($nameParts)) || true) && + $this->matchChar(')') + ) { + $parts[] = '('; + + while ($sub = array_shift($subs)) { + while ($ps = array_shift($sub)) { + foreach ($ps as &$p) { + $parts[] = $p; + } + + if (\count($sub) && reset($sub)) { + $parts[] = ' '; + } + } + + if (\count($subs) && reset($subs)) { + $parts[] = ', '; + } + } + + $parts[] = ')'; + } else { + $this->seek($ss); + } + } elseif ( + $this->matchChar('(', true) && + ($this->openString(')', $str, '(') || true) && + $this->matchChar(')') + ) { + $parts[] = '('; + + if (! empty($str)) { + $parts[] = $str; + } + + $parts[] = ')'; + } else { + $this->seek($ss); + } + + continue; + } + } + + $this->seek($s); + + // 2n+1 + if ($subSelector && \is_string($subSelector) && strpos($subSelector, 'nth-') === 0) { + if ($this->match("(\s*(\+\s*|\-\s*)?(\d+|n|\d+n))+", $counter)) { + $parts[] = $counter[0]; + //$parts[] = str_replace(' ', '', $counter[0]); + continue; + } + } + + $this->seek($s); + + // attribute selector + if ( + $char === '[' && + $this->matchChar('[') && + ($this->openString(']', $str, '[') || true) && + $this->matchChar(']') + ) { + $parts[] = '['; + + if (! empty($str)) { + $parts[] = $str; + } + + $parts[] = ']'; + continue; + } + + $this->seek($s); + + // for keyframes + if ($this->unit($unit)) { + $parts[] = $unit; + continue; + } + + if ($this->restrictedKeyword($name, false, true)) { + $parts[] = $name; + continue; + } + + break; + } + + $this->eatWhiteDefault = $oldWhite; + + if (! $parts) { + return false; + } + + $out = $parts; + + return true; + } + + /** + * Parse a variable + * + * @param mixed $out + * @param-out array{Type::*, string} $out + * + * @return bool + */ + protected function variable(&$out) + { + $s = $this->count; + + if ( + $this->matchChar('$', false) && + $this->keyword($name) + ) { + if ($this->allowVars) { + $out = [Type::T_VARIABLE, $name]; + } else { + $out = [Type::T_KEYWORD, '$' . $name]; + } + + return true; + } + + $this->seek($s); + + return false; + } + + /** + * Parse a keyword + * + * @param mixed $word + * @param bool $eatWhitespace + * @param bool $inSelector + * @param-out string $word + * + * @return bool + */ + protected function keyword(&$word, $eatWhitespace = null, $inSelector = false) + { + $s = $this->count; + $match = $this->match( + $this->utf8 + ? '(([\pL\w\x{00A0}-\x{10FFFF}_\-\*!"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)([\pL\w\x{00A0}-\x{10FFFF}\-_"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)*)' + : '(([\w_\-\*!"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)([\w\-_"\']|\\\\[a-f0-9]{6} ?|\\\\[a-f0-9]{1,5}(?![a-f0-9]) ?|[\\\\].)*)', + $m, + false + ); + + if ($match) { + $word = $m[1]; + + // handling of escaping in keyword : get the escaped char + if (strpos($word, '\\') !== false) { + $send = $this->count; + $escapedWord = []; + $this->seek($s); + $previousEscape = false; + while ($this->count < $send) { + $char = $this->buffer[$this->count]; + $this->count++; + if ( + $this->count < $send + && $char === '\\' + && !$previousEscape + && ( + $inSelector ? + $this->matchEscapeCharacterInSelector($out) + : + $this->matchEscapeCharacter($out, true) + ) + ) { + $escapedWord[] = $out; + } else { + if ($previousEscape) { + $previousEscape = false; + } elseif ($char === '\\') { + $previousEscape = true; + } + $escapedWord[] = $char; + } + } + + $word = implode('', $escapedWord); + } + + if (is_null($eatWhitespace) ? $this->eatWhiteDefault : $eatWhitespace) { + $this->whitespace(); + } + + return true; + } + + return false; + } + + /** + * Parse a keyword that should not start with a number + * + * @param string $word + * @param bool $eatWhitespace + * @param bool $inSelector + * + * @return bool + */ + protected function restrictedKeyword(&$word, $eatWhitespace = null, $inSelector = false) + { + $s = $this->count; + + if ($this->keyword($word, $eatWhitespace, $inSelector) && (\ord($word[0]) > 57 || \ord($word[0]) < 48)) { + return true; + } + + $this->seek($s); + + return false; + } + + /** + * Parse a placeholder + * + * @param string|array $placeholder + * + * @return bool + */ + protected function placeholder(&$placeholder) + { + $match = $this->match( + $this->utf8 + ? '([\pL\w\-_]+)' + : '([\w\-_]+)', + $m + ); + + if ($match) { + $placeholder = $m[1]; + + return true; + } + + if ($this->interpolation($placeholder)) { + return true; + } + + return false; + } + + /** + * Parse a url + * + * @param mixed $out + * @param-out array $out + * + * @return bool + */ + protected function url(&$out) + { + if ($this->literal('url(', 4)) { + $s = $this->count; + + if ( + ($this->string($inner) || $this->spaceList($inner)) && + $this->matchChar(')') + ) { + $out = [Type::T_STRING, '', ['url(', $inner, ')']]; + + return true; + } + + $this->seek($s); + + if ( + $this->openString(')', $out) && + $this->matchChar(')') + ) { + $out = [Type::T_STRING, '', ['url(', $out, ')']]; + + return true; + } + } + + return false; + } + + /** + * Consume an end of statement delimiter + * @param bool $eatWhitespace + * + * @return bool + */ + protected function end($eatWhitespace = null) + { + if ($this->matchChar(';', $eatWhitespace)) { + return true; + } + + if ($this->count === \strlen($this->buffer) || $this->buffer[$this->count] === '}') { + // if there is end of file or a closing block next then we don't need a ; + return true; + } + + return false; + } + + /** + * Strip assignment flag from the list + * + * @param array|Number $value + * + * @return string[] + */ + protected function stripAssignmentFlags(&$value) + { + $flags = []; + + for ($token = &$value; $token[0] === Type::T_LIST && ($s = \count($token[2])); $token = &$lastNode) { + $lastNode = &$token[2][$s - 1]; + + while ($lastNode[0] === Type::T_KEYWORD && \in_array($lastNode[1], ['!default', '!global'])) { + array_pop($token[2]); + + $node = end($token[2]); + $token = $this->flattenList($token); + $flags[] = $lastNode[1]; + $lastNode = $node; + } + } + + return $flags; + } + + /** + * Strip optional flag from selector list + * + * @param array $selectors + * + * @return bool + */ + protected function stripOptionalFlag(&$selectors) + { + $optional = false; + $selector = end($selectors); + $part = end($selector); + + if ($part === ['!optional']) { + array_pop($selectors[\count($selectors) - 1]); + + $optional = true; + } + + return $optional; + } + + /** + * Turn list of length 1 into value type + * + * @param array $value + * + * @return array + */ + protected function flattenList($value) + { + if ($value[0] === Type::T_LIST && \count($value[2]) === 1) { + return $this->flattenList($value[2][0]); + } + + return $value; + } + + /** + * Quote regular expression + * + * @param string $what + * + * @return string + */ + private function pregQuote($what) + { + return preg_quote($what, '/'); + } + + /** + * Extract line numbers from buffer + * + * @param string $buffer + * + * @return void + */ + private function extractLineNumbers($buffer) + { + $this->sourcePositions = [0 => 0]; + $prev = 0; + + while (($pos = strpos($buffer, "\n", $prev)) !== false) { + $this->sourcePositions[] = $pos; + $prev = $pos + 1; + } + + $this->sourcePositions[] = \strlen($buffer); + + if (substr($buffer, -1) !== "\n") { + $this->sourcePositions[] = \strlen($buffer) + 1; + } + } + + /** + * Get source line number and column (given character position in the buffer) + * + * @param int $pos + * + * @return array + * @phpstan-return array{int, int} + */ + private function getSourcePosition($pos) + { + $low = 0; + $high = \count($this->sourcePositions); + + while ($low < $high) { + $mid = (int) (($high + $low) / 2); + + if ($pos < $this->sourcePositions[$mid]) { + $high = $mid - 1; + continue; + } + + if ($pos >= $this->sourcePositions[$mid + 1]) { + $low = $mid + 1; + continue; + } + + return [$mid + 1, $pos - $this->sourcePositions[$mid]]; + } + + return [$low + 1, $pos - $this->sourcePositions[$low]]; + } + + /** + * Save internal encoding of mbstring + * + * When mbstring.func_overload is used to replace the standard PHP string functions, + * this method configures the internal encoding to a single-byte one so that the + * behavior matches the normal behavior of PHP string functions while using the parser. + * The existing internal encoding is saved and will be restored when calling {@see restoreEncoding}. + * + * If mbstring.func_overload is not used (or does not override string functions), this method is a no-op. + * + * @return void + */ + private function saveEncoding() + { + if (\PHP_VERSION_ID < 80000 && \extension_loaded('mbstring') && (2 & (int) ini_get('mbstring.func_overload')) > 0) { + $this->encoding = mb_internal_encoding(); + + mb_internal_encoding('iso-8859-1'); + } + } + + /** + * Restore internal encoding + * + * @return void + */ + private function restoreEncoding() + { + if (\extension_loaded('mbstring') && $this->encoding) { + mb_internal_encoding($this->encoding); + } + } +} diff --git a/rules/scssphp/src/SourceMap/Base64.php b/rules/scssphp/src/SourceMap/Base64.php new file mode 100644 index 0000000..00b6b45 --- /dev/null +++ b/rules/scssphp/src/SourceMap/Base64.php @@ -0,0 +1,187 @@ + + * + * @internal + */ +class Base64 +{ + /** + * @var array + */ + private static $encodingMap = [ + 0 => 'A', + 1 => 'B', + 2 => 'C', + 3 => 'D', + 4 => 'E', + 5 => 'F', + 6 => 'G', + 7 => 'H', + 8 => 'I', + 9 => 'J', + 10 => 'K', + 11 => 'L', + 12 => 'M', + 13 => 'N', + 14 => 'O', + 15 => 'P', + 16 => 'Q', + 17 => 'R', + 18 => 'S', + 19 => 'T', + 20 => 'U', + 21 => 'V', + 22 => 'W', + 23 => 'X', + 24 => 'Y', + 25 => 'Z', + 26 => 'a', + 27 => 'b', + 28 => 'c', + 29 => 'd', + 30 => 'e', + 31 => 'f', + 32 => 'g', + 33 => 'h', + 34 => 'i', + 35 => 'j', + 36 => 'k', + 37 => 'l', + 38 => 'm', + 39 => 'n', + 40 => 'o', + 41 => 'p', + 42 => 'q', + 43 => 'r', + 44 => 's', + 45 => 't', + 46 => 'u', + 47 => 'v', + 48 => 'w', + 49 => 'x', + 50 => 'y', + 51 => 'z', + 52 => '0', + 53 => '1', + 54 => '2', + 55 => '3', + 56 => '4', + 57 => '5', + 58 => '6', + 59 => '7', + 60 => '8', + 61 => '9', + 62 => '+', + 63 => '/', + ]; + + /** + * @var array + */ + private static $decodingMap = [ + 'A' => 0, + 'B' => 1, + 'C' => 2, + 'D' => 3, + 'E' => 4, + 'F' => 5, + 'G' => 6, + 'H' => 7, + 'I' => 8, + 'J' => 9, + 'K' => 10, + 'L' => 11, + 'M' => 12, + 'N' => 13, + 'O' => 14, + 'P' => 15, + 'Q' => 16, + 'R' => 17, + 'S' => 18, + 'T' => 19, + 'U' => 20, + 'V' => 21, + 'W' => 22, + 'X' => 23, + 'Y' => 24, + 'Z' => 25, + 'a' => 26, + 'b' => 27, + 'c' => 28, + 'd' => 29, + 'e' => 30, + 'f' => 31, + 'g' => 32, + 'h' => 33, + 'i' => 34, + 'j' => 35, + 'k' => 36, + 'l' => 37, + 'm' => 38, + 'n' => 39, + 'o' => 40, + 'p' => 41, + 'q' => 42, + 'r' => 43, + 's' => 44, + 't' => 45, + 'u' => 46, + 'v' => 47, + 'w' => 48, + 'x' => 49, + 'y' => 50, + 'z' => 51, + 0 => 52, + 1 => 53, + 2 => 54, + 3 => 55, + 4 => 56, + 5 => 57, + 6 => 58, + 7 => 59, + 8 => 60, + 9 => 61, + '+' => 62, + '/' => 63, + ]; + + /** + * Convert to base64 + * + * @param int $value + * + * @return string + */ + public static function encode($value) + { + return self::$encodingMap[$value]; + } + + /** + * Convert from base64 + * + * @param string $value + * + * @return int + */ + public static function decode($value) + { + return self::$decodingMap[$value]; + } +} diff --git a/rules/scssphp/src/SourceMap/Base64VLQ.php b/rules/scssphp/src/SourceMap/Base64VLQ.php new file mode 100644 index 0000000..2a5210c --- /dev/null +++ b/rules/scssphp/src/SourceMap/Base64VLQ.php @@ -0,0 +1,151 @@ + + * @author Anthon Pang + * + * @internal + */ +class Base64VLQ +{ + // A Base64 VLQ digit can represent 5 bits, so it is base-32. + const VLQ_BASE_SHIFT = 5; + + // A mask of bits for a VLQ digit (11111), 31 decimal. + const VLQ_BASE_MASK = 31; + + // The continuation bit is the 6th bit. + const VLQ_CONTINUATION_BIT = 32; + + /** + * Returns the VLQ encoded value. + * + * @param int $value + * + * @return string + */ + public static function encode($value) + { + $encoded = ''; + $vlq = self::toVLQSigned($value); + + do { + $digit = $vlq & self::VLQ_BASE_MASK; + + //$vlq >>>= self::VLQ_BASE_SHIFT; // unsigned right shift + $vlq = (($vlq >> 1) & PHP_INT_MAX) >> (self::VLQ_BASE_SHIFT - 1); + + if ($vlq > 0) { + $digit |= self::VLQ_CONTINUATION_BIT; + } + + $encoded .= Base64::encode($digit); + } while ($vlq > 0); + + return $encoded; + } + + /** + * Decodes VLQValue. + * + * @param string $str + * @param int $index + * + * @return int + */ + public static function decode($str, &$index) + { + $result = 0; + $shift = 0; + + do { + $c = $str[$index++]; + $digit = Base64::decode($c); + $continuation = ($digit & self::VLQ_CONTINUATION_BIT) != 0; + $digit &= self::VLQ_BASE_MASK; + $result = $result + ($digit << $shift); + $shift = $shift + self::VLQ_BASE_SHIFT; + } while ($continuation); + + return self::fromVLQSigned($result); + } + + /** + * Converts from a two-complement value to a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 1 becomes 2 (10 binary), -1 becomes 3 (11 binary) + * 2 becomes 4 (100 binary), -2 becomes 5 (101 binary) + * + * @param int $value + * + * @return int + */ + private static function toVLQSigned($value) + { + if ($value < 0) { + return ((-$value) << 1) + 1; + } + + return ($value << 1) + 0; + } + + /** + * Converts to a two-complement value from a value where the sign bit is + * is placed in the least significant bit. For example, as decimals: + * 2 (10 binary) becomes 1, 3 (11 binary) becomes -1 + * 4 (100 binary) becomes 2, 5 (101 binary) becomes -2 + * + * @param int $value + * + * @return int + */ + private static function fromVLQSigned($value) + { + $negate = ($value & 1) === 1; + + //$value >>>= 1; // unsigned right shift + $value = ($value >> 1) & PHP_INT_MAX; + + if (! $negate) { + return $value; + } + + // We need to OR 0x80000000 here to ensure the 32nd bit (the sign bit) is + // always set for negative numbers. If `value` were 1, (meaning `negate` is + // true and all other bits were zeros), `value` would now be 0. -0 is just + // 0, and doesn't flip the 32nd bit as intended. All positive numbers will + // successfully flip the 32nd bit without issue, so it's a noop for them. + return -$value | 0x80000000; + } +} diff --git a/rules/scssphp/src/SourceMap/SourceMapGenerator.php b/rules/scssphp/src/SourceMap/SourceMapGenerator.php new file mode 100644 index 0000000..ccd4f02 --- /dev/null +++ b/rules/scssphp/src/SourceMap/SourceMapGenerator.php @@ -0,0 +1,390 @@ + + * @author Nicolas FRANÇOIS + * + * @internal + */ +class SourceMapGenerator +{ + /** + * What version of source map does the generator generate? + */ + const VERSION = 3; + + /** + * Array of default options + * + * @var array + * @phpstan-var array{sourceRoot: string, sourceMapFilename: string|null, sourceMapURL: string|null, sourceMapWriteTo: string|null, outputSourceFiles: bool, sourceMapRootpath: string, sourceMapBasepath: string} + */ + protected $defaultOptions = [ + // an optional source root, useful for relocating source files + // on a server or removing repeated values in the 'sources' entry. + // This value is prepended to the individual entries in the 'source' field. + 'sourceRoot' => '', + + // an optional name of the generated code that this source map is associated with. + 'sourceMapFilename' => null, + + // url of the map + 'sourceMapURL' => null, + + // absolute path to a file to write the map to + 'sourceMapWriteTo' => null, + + // output source contents? + 'outputSourceFiles' => false, + + // base path for filename normalization + 'sourceMapRootpath' => '', + + // base path for filename normalization + 'sourceMapBasepath' => '' + ]; + + /** + * The base64 VLQ encoder + * + * @var \ScssPhp\ScssPhp\SourceMap\Base64VLQ + */ + protected $encoder; + + /** + * Array of mappings + * + * @var array + * @phpstan-var list + */ + protected $mappings = []; + + /** + * Array of contents map + * + * @var array + */ + protected $contentsMap = []; + + /** + * File to content map + * + * @var array + */ + protected $sources = []; + + /** + * @var array + */ + protected $sourceKeys = []; + + /** + * @var array + * @phpstan-var array{sourceRoot: string, sourceMapFilename: string|null, sourceMapURL: string|null, sourceMapWriteTo: string|null, outputSourceFiles: bool, sourceMapRootpath: string, sourceMapBasepath: string} + */ + private $options; + + /** + * @phpstan-param array{sourceRoot?: string, sourceMapFilename?: string|null, sourceMapURL?: string|null, sourceMapWriteTo?: string|null, outputSourceFiles?: bool, sourceMapRootpath?: string, sourceMapBasepath?: string} $options + */ + public function __construct(array $options = []) + { + $this->options = array_replace($this->defaultOptions, $options); + $this->encoder = new Base64VLQ(); + } + + /** + * Adds a mapping + * + * @param int $generatedLine The line number in generated file + * @param int $generatedColumn The column number in generated file + * @param int $originalLine The line number in original file + * @param int $originalColumn The column number in original file + * @param string $sourceFile The original source file + * + * @return void + */ + public function addMapping($generatedLine, $generatedColumn, $originalLine, $originalColumn, $sourceFile) + { + $this->mappings[] = [ + 'generated_line' => $generatedLine, + 'generated_column' => $generatedColumn, + 'original_line' => $originalLine, + 'original_column' => $originalColumn, + 'source_file' => $sourceFile + ]; + + $this->sources[$sourceFile] = $sourceFile; + } + + /** + * Saves the source map to a file + * + * @param string $content The content to write + * + * @return string|null + * + * @throws \ScssPhp\ScssPhp\Exception\CompilerException If the file could not be saved + * @deprecated + */ + public function saveMap($content) + { + $file = $this->options['sourceMapWriteTo']; + assert($file !== null); + $dir = \dirname($file); + + // directory does not exist + if (! is_dir($dir)) { + // FIXME: create the dir automatically? + throw new CompilerException( + sprintf('The directory "%s" does not exist. Cannot save the source map.', $dir) + ); + } + + // FIXME: proper saving, with dir write check! + if (file_put_contents($file, $content) === false) { + throw new CompilerException(sprintf('Cannot save the source map to "%s"', $file)); + } + + return $this->options['sourceMapURL']; + } + + /** + * Generates the JSON source map + * + * @param string $prefix A prefix added in the output file, which needs to shift mappings + * + * @return string + * + * @see https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit# + */ + public function generateJson($prefix = '') + { + $sourceMap = []; + $mappings = $this->generateMappings($prefix); + + // File version (always the first entry in the object) and must be a positive integer. + $sourceMap['version'] = self::VERSION; + + // An optional name of the generated code that this source map is associated with. + $file = $this->options['sourceMapFilename']; + + if ($file) { + $sourceMap['file'] = $file; + } + + // An optional source root, useful for relocating source files on a server or removing repeated values in the + // 'sources' entry. This value is prepended to the individual entries in the 'source' field. + $root = $this->options['sourceRoot']; + + if ($root) { + $sourceMap['sourceRoot'] = $root; + } + + // A list of original sources used by the 'mappings' entry. + $sourceMap['sources'] = []; + + foreach ($this->sources as $sourceFilename) { + $sourceMap['sources'][] = $this->normalizeFilename($sourceFilename); + } + + // A list of symbol names used by the 'mappings' entry. + $sourceMap['names'] = []; + + // A string with the encoded mapping data. + $sourceMap['mappings'] = $mappings; + + if ($this->options['outputSourceFiles']) { + // An optional list of source content, useful when the 'source' can't be hosted. + // The contents are listed in the same order as the sources above. + // 'null' may be used if some original sources should be retrieved by name. + $sourceMap['sourcesContent'] = $this->getSourcesContent(); + } + + // less.js compat fixes + if (\count($sourceMap['sources']) && empty($sourceMap['sourceRoot'])) { + unset($sourceMap['sourceRoot']); + } + + $jsonSourceMap = json_encode($sourceMap, JSON_UNESCAPED_SLASHES); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \RuntimeException(json_last_error_msg()); + } + + assert($jsonSourceMap !== false); + + return $jsonSourceMap; + } + + /** + * Returns the sources contents + * + * @return string[]|null + */ + protected function getSourcesContent() + { + if (empty($this->sources)) { + return null; + } + + $content = []; + + foreach ($this->sources as $sourceFile) { + $content[] = file_get_contents($sourceFile); + } + + return $content; + } + + /** + * Generates the mappings string + * + * @param string $prefix A prefix added in the output file, which needs to shift mappings + * + * @return string + */ + public function generateMappings($prefix = '') + { + if (! \count($this->mappings)) { + return ''; + } + + $prefixLines = substr_count($prefix, "\n"); + $lastPrefixNewLine = strrpos($prefix, "\n"); + $lastPrefixLineStart = false === $lastPrefixNewLine ? 0 : $lastPrefixNewLine + 1; + $prefixColumn = strlen($prefix) - $lastPrefixLineStart; + + $this->sourceKeys = array_flip(array_keys($this->sources)); + + // group mappings by generated line number. + $groupedMap = $groupedMapEncoded = []; + + foreach ($this->mappings as $m) { + $groupedMap[$m['generated_line']][] = $m; + } + + ksort($groupedMap); + + $lastGeneratedLine = $lastOriginalIndex = $lastOriginalLine = $lastOriginalColumn = 0; + + foreach ($groupedMap as $lineNumber => $lineMap) { + if ($lineNumber > 1) { + // The prefix only impacts the column for the first line of the original output + $prefixColumn = 0; + } + $lineNumber += $prefixLines; + + while (++$lastGeneratedLine < $lineNumber) { + $groupedMapEncoded[] = ';'; + } + + $lineMapEncoded = []; + $lastGeneratedColumn = 0; + + foreach ($lineMap as $m) { + $generatedColumn = $m['generated_column'] + $prefixColumn; + + $mapEncoded = $this->encoder->encode($generatedColumn - $lastGeneratedColumn); + $lastGeneratedColumn = $generatedColumn; + + // find the index + if ($m['source_file']) { + $index = $this->findFileIndex($m['source_file']); + + if ($index !== false) { + $mapEncoded .= $this->encoder->encode($index - $lastOriginalIndex); + $lastOriginalIndex = $index; + // lines are stored 0-based in SourceMap spec version 3 + $mapEncoded .= $this->encoder->encode($m['original_line'] - 1 - $lastOriginalLine); + $lastOriginalLine = $m['original_line'] - 1; + $mapEncoded .= $this->encoder->encode($m['original_column'] - $lastOriginalColumn); + $lastOriginalColumn = $m['original_column']; + } + } + + $lineMapEncoded[] = $mapEncoded; + } + + $groupedMapEncoded[] = implode(',', $lineMapEncoded) . ';'; + } + + return rtrim(implode($groupedMapEncoded), ';'); + } + + /** + * Finds the index for the filename + * + * @param string $filename + * + * @return int|false + */ + protected function findFileIndex($filename) + { + return $this->sourceKeys[$filename]; + } + + /** + * Normalize filename + * + * @param string $filename + * + * @return string + */ + protected function normalizeFilename($filename) + { + $filename = $this->fixWindowsPath($filename); + $rootpath = $this->options['sourceMapRootpath']; + $basePath = $this->options['sourceMapBasepath']; + + // "Trim" the 'sourceMapBasepath' from the output filename. + if (\strlen($basePath) && strpos($filename, $basePath) === 0) { + $filename = substr($filename, \strlen($basePath)); + } + + // Remove extra leading path separators. + if (strpos($filename, '\\') === 0 || strpos($filename, '/') === 0) { + $filename = substr($filename, 1); + } + + return $rootpath . $filename; + } + + /** + * Fix windows paths + * + * @param string $path + * @param bool $addEndSlash + * + * @return string + */ + public function fixWindowsPath($path, $addEndSlash = false) + { + $slash = ($addEndSlash) ? '/' : ''; + + if (! empty($path)) { + $path = str_replace('\\', '/', $path); + $path = rtrim($path, '/') . $slash; + } + + return $path; + } +} diff --git a/rules/scssphp/src/Type.php b/rules/scssphp/src/Type.php new file mode 100644 index 0000000..2f8ab65 --- /dev/null +++ b/rules/scssphp/src/Type.php @@ -0,0 +1,211 @@ + + */ +class Type +{ + /** + * @internal + */ + const T_ASSIGN = 'assign'; + /** + * @internal + */ + const T_AT_ROOT = 'at-root'; + /** + * @internal + */ + const T_BLOCK = 'block'; + /** + * @deprecated + * @internal + */ + const T_BREAK = 'break'; + /** + * @internal + */ + const T_CHARSET = 'charset'; + const T_COLOR = 'color'; + /** + * @internal + */ + const T_COMMENT = 'comment'; + /** + * @deprecated + * @internal + */ + const T_CONTINUE = 'continue'; + /** + * @deprecated + * @internal + */ + const T_CONTROL = 'control'; + /** + * @internal + */ + const T_CUSTOM_PROPERTY = 'custom'; + /** + * @internal + */ + const T_DEBUG = 'debug'; + /** + * @internal + */ + const T_DIRECTIVE = 'directive'; + /** + * @internal + */ + const T_EACH = 'each'; + /** + * @internal + */ + const T_ELSE = 'else'; + /** + * @internal + */ + const T_ELSEIF = 'elseif'; + /** + * @internal + */ + const T_ERROR = 'error'; + /** + * @internal + */ + const T_EXPRESSION = 'exp'; + /** + * @internal + */ + const T_EXTEND = 'extend'; + /** + * @internal + */ + const T_FOR = 'for'; + /** + * @internal + */ + const T_FUNCTION = 'function'; + /** + * @internal + */ + const T_FUNCTION_REFERENCE = 'function-reference'; + /** + * @internal + */ + const T_FUNCTION_CALL = 'fncall'; + /** + * @internal + */ + const T_HSL = 'hsl'; + /** + * @internal + */ + const T_HWB = 'hwb'; + /** + * @internal + */ + const T_IF = 'if'; + /** + * @internal + */ + const T_IMPORT = 'import'; + /** + * @internal + */ + const T_INCLUDE = 'include'; + /** + * @internal + */ + const T_INTERPOLATE = 'interpolate'; + /** + * @internal + */ + const T_INTERPOLATED = 'interpolated'; + /** + * @internal + */ + const T_KEYWORD = 'keyword'; + const T_LIST = 'list'; + const T_MAP = 'map'; + /** + * @internal + */ + const T_MEDIA = 'media'; + /** + * @internal + */ + const T_MEDIA_EXPRESSION = 'mediaExp'; + /** + * @internal + */ + const T_MEDIA_TYPE = 'mediaType'; + /** + * @internal + */ + const T_MEDIA_VALUE = 'mediaValue'; + /** + * @internal + */ + const T_MIXIN = 'mixin'; + /** + * @internal + */ + const T_MIXIN_CONTENT = 'mixin_content'; + /** + * @internal + */ + const T_NESTED_PROPERTY = 'nestedprop'; + /** + * @internal + */ + const T_NOT = 'not'; + const T_NULL = 'null'; + const T_NUMBER = 'number'; + /** + * @internal + */ + const T_RETURN = 'return'; + /** + * @internal + */ + const T_ROOT = 'root'; + /** + * @internal + */ + const T_SCSSPHP_IMPORT_ONCE = 'scssphp-import-once'; + /** + * @internal + */ + const T_SELF = 'self'; + const T_STRING = 'string'; + /** + * @internal + */ + const T_UNARY = 'unary'; + /** + * @internal + */ + const T_VARIABLE = 'var'; + /** + * @internal + */ + const T_WARN = 'warn'; + /** + * @internal + */ + const T_WHILE = 'while'; +} diff --git a/rules/scssphp/src/Util.php b/rules/scssphp/src/Util.php new file mode 100644 index 0000000..ad608ce --- /dev/null +++ b/rules/scssphp/src/Util.php @@ -0,0 +1,184 @@ + + * + * @internal + */ +class Util +{ + /** + * Asserts that `value` falls within `range` (inclusive), leaving + * room for slight floating-point errors. + * + * @param string $name The name of the value. Used in the error message. + * @param Range $range Range of values. + * @param array|Number $value The value to check. + * @param string $unit The unit of the value. Used in error reporting. + * + * @return mixed `value` adjusted to fall within range, if it was outside by a floating-point margin. + * + * @throws \ScssPhp\ScssPhp\Exception\RangeException + */ + public static function checkRange($name, Range $range, $value, $unit = '') + { + $val = $value[1]; + $grace = new Range(-0.00001, 0.00001); + + if (! \is_numeric($val)) { + throw new RangeException("$name {$val} is not a number."); + } + + if ($range->includes($val)) { + return $val; + } + + if ($grace->includes($val - $range->first)) { + return $range->first; + } + + if ($grace->includes($val - $range->last)) { + return $range->last; + } + + throw new RangeException("$name {$val} must be between {$range->first} and {$range->last}$unit"); + } + + /** + * Encode URI component + * + * @param string $string + * + * @return string + */ + public static function encodeURIComponent($string) + { + $revert = ['%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')']; + + return strtr(rawurlencode($string), $revert); + } + + /** + * mb_chr() wrapper + * + * @param int $code + * + * @return string + */ + public static function mbChr($code) + { + // Use the native implementation if available, but not on PHP 7.2 as mb_chr(0) is buggy there + if (\PHP_VERSION_ID > 70300 && \function_exists('mb_chr')) { + return mb_chr($code, 'UTF-8'); + } + + if (0x80 > $code %= 0x200000) { + $s = \chr($code); + } elseif (0x800 > $code) { + $s = \chr(0xC0 | $code >> 6) . \chr(0x80 | $code & 0x3F); + } elseif (0x10000 > $code) { + $s = \chr(0xE0 | $code >> 12) . \chr(0x80 | $code >> 6 & 0x3F) . \chr(0x80 | $code & 0x3F); + } else { + $s = \chr(0xF0 | $code >> 18) . \chr(0x80 | $code >> 12 & 0x3F) + . \chr(0x80 | $code >> 6 & 0x3F) . \chr(0x80 | $code & 0x3F); + } + + return $s; + } + + /** + * mb_strlen() wrapper + * + * @param string $string + * @return int + */ + public static function mbStrlen($string) + { + // Use the native implementation if available. + if (\function_exists('mb_strlen')) { + return mb_strlen($string, 'UTF-8'); + } + + if (\function_exists('iconv_strlen')) { + return (int) @iconv_strlen($string, 'UTF-8'); + } + + throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.'); + } + + /** + * mb_substr() wrapper + * @param string $string + * @param int $start + * @param null|int $length + * @return string + */ + public static function mbSubstr($string, $start, $length = null) + { + // Use the native implementation if available. + if (\function_exists('mb_substr')) { + return mb_substr($string, $start, $length, 'UTF-8'); + } + + if (\function_exists('iconv_substr')) { + if ($start < 0) { + $start = static::mbStrlen($string) + $start; + if ($start < 0) { + $start = 0; + } + } + + if (null === $length) { + $length = 2147483647; + } elseif ($length < 0) { + $length = static::mbStrlen($string) + $length - $start; + if ($length < 0) { + return ''; + } + } + + return (string)iconv_substr($string, $start, $length, 'UTF-8'); + } + + throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.'); + } + + /** + * mb_strpos wrapper + * @param string $haystack + * @param string $needle + * @param int $offset + * + * @return int|false + */ + public static function mbStrpos($haystack, $needle, $offset = 0) + { + if (\function_exists('mb_strpos')) { + return mb_strpos($haystack, $needle, $offset, 'UTF-8'); + } + + if (\function_exists('iconv_strpos')) { + return iconv_strpos($haystack, $needle, $offset, 'UTF-8'); + } + + throw new \LogicException('Either mbstring (recommended) or iconv is necessary to use Scssphp.'); + } +} diff --git a/rules/scssphp/src/Util/Path.php b/rules/scssphp/src/Util/Path.php new file mode 100644 index 0000000..f399e41 --- /dev/null +++ b/rules/scssphp/src/Util/Path.php @@ -0,0 +1,77 @@ +parseValue($source, $value)) { + throw new \InvalidArgumentException(sprintf('Invalid value source "%s".', $source)); + } + + return $value; + } + + /** + * Converts a PHP value to a Sass value + * + * The returned value is guaranteed to be supported by the + * Compiler methods for registering custom variables. No other + * guarantee about it is provided. It should be considered + * opaque values by the caller. + * + * @param mixed $value + * + * @return mixed + */ + public static function fromPhp($value) + { + if ($value instanceof Number) { + return $value; + } + + if (is_array($value) && isset($value[0]) && \in_array($value[0], [Type::T_NULL, Type::T_COLOR, Type::T_KEYWORD, Type::T_LIST, Type::T_MAP, Type::T_STRING])) { + return $value; + } + + if ($value === null) { + return Compiler::$null; + } + + if ($value === true) { + return Compiler::$true; + } + + if ($value === false) { + return Compiler::$false; + } + + if ($value === '') { + return Compiler::$emptyString; + } + + if (\is_int($value) || \is_float($value)) { + return new Number($value, ''); + } + + if (\is_string($value)) { + return [Type::T_STRING, '"', [$value]]; + } + + throw new \InvalidArgumentException(sprintf('Cannot convert the value of type "%s" to a Sass value.', gettype($value))); + } +} diff --git a/rules/scssphp/src/Version.php b/rules/scssphp/src/Version.php new file mode 100644 index 0000000..45fc983 --- /dev/null +++ b/rules/scssphp/src/Version.php @@ -0,0 +1,23 @@ + + */ +class Version +{ + const VERSION = '1.13.0'; +} diff --git a/rules/scssphp/src/Warn.php b/rules/scssphp/src/Warn.php new file mode 100644 index 0000000..592b44c --- /dev/null +++ b/rules/scssphp/src/Warn.php @@ -0,0 +1,84 @@ + - + Date: Thu, 3 Oct 2024 13:15:06 +0000 Subject: [PATCH 08/82] 2.2.0 --- rules/compiler.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/rules/compiler.php b/rules/compiler.php index b02f33f..8cc327d 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -93,11 +93,13 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input if ( htmlspecialchars($params->compress) == "1") { +// $scss->setFormatter('Leafo\ScssPhp\Formatter\Crunched'); $scss->setOutputStyle ('\ScssPhp\ScssPhp\OutputStyle::COMPRESSED'); } else -{ // voor debug netter formatteren en commentaren behouden. - $scss->setOutputStyle ('\ScssPhp\ScssPhp\OutputStyle::EXPANDED'); +{ // voor debug netter formatteren en commentaren behouden. +// $scss->setFormatter('Leafo\ScssPhp\Formatter\Expanded'); + $scss->setOutputStyle ('ScssPhp\ScssPhp\OutputStyle::EXPANDED'); // $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); } From f3a6bbd81988b5eaba672623863fd217dd7cc368 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:26:41 +0000 Subject: [PATCH 09/82] 2.2.0 --- rules/compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/compiler.php b/rules/compiler.php index 8cc327d..57538d6 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -99,7 +99,7 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input else { // voor debug netter formatteren en commentaren behouden. // $scss->setFormatter('Leafo\ScssPhp\Formatter\Expanded'); - $scss->setOutputStyle ('ScssPhp\ScssPhp\OutputStyle::EXPANDED'); + $scss->setOutputStyle ('ScssPhp\ScssPhp\Formatter\Expanded'); // $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); } From 4c10f08150bf48f35c819288c5279b62e1b3fb9a Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:33:07 +0000 Subject: [PATCH 10/82] 2.2.0 --- rules/compiler.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/rules/compiler.php b/rules/compiler.php index 57538d6..45b36fd 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -99,8 +99,9 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input else { // voor debug netter formatteren en commentaren behouden. // $scss->setFormatter('Leafo\ScssPhp\Formatter\Expanded'); - $scss->setOutputStyle ('ScssPhp\ScssPhp\Formatter\Expanded'); -// $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); + $scss->setOutputStyle ('ScssPhp\ScssPhp\OutputStyle::EXPANDED'); +// $scss->setOutputStyle ('expanded'); + // $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); } //$server = new Server($currentpath. '/../scss', null, $scss); From 3b9dde1025c7a6c00464fe9830e5cbeca65b36ed Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 3 Oct 2024 13:40:01 +0000 Subject: [PATCH 11/82] 2.2.0 --- rules/compiler.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rules/compiler.php b/rules/compiler.php index 45b36fd..fc9db2b 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -94,13 +94,14 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input if ( htmlspecialchars($params->compress) == "1") { // $scss->setFormatter('Leafo\ScssPhp\Formatter\Crunched'); - $scss->setOutputStyle ('\ScssPhp\ScssPhp\OutputStyle::COMPRESSED'); +// $scss->setOutputStyle ('\ScssPhp\ScssPhp\OutputStyle::COMPRESSED'); + $scss->setOutputStyle ('compressed'); } else { // voor debug netter formatteren en commentaren behouden. // $scss->setFormatter('Leafo\ScssPhp\Formatter\Expanded'); - $scss->setOutputStyle ('ScssPhp\ScssPhp\OutputStyle::EXPANDED'); -// $scss->setOutputStyle ('expanded'); +// $scss->setOutputStyle ('\ScssPhp\ScssPhp\OutputStyle::EXPANDED'); + $scss->setOutputStyle ('expanded'); // $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); } From b313f4f785d61fa0ff4219cac7e15dac79207d72 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 3 Oct 2024 19:21:35 +0000 Subject: [PATCH 12/82] 2.2.0 5 times calc added to resolve Incompatible units rem and px. in _variables.scss --- .../bootstrap/scss/_variables.scss | 16 +- .../bootstrap/scss/_variables.scss.4.2.1.org | 1091 +++++++++++++++++ 2 files changed, 1100 insertions(+), 7 deletions(-) create mode 100644 scss/node_modules/bootstrap/scss/_variables.scss.4.2.1.org diff --git a/scss/node_modules/bootstrap/scss/_variables.scss b/scss/node_modules/bootstrap/scss/_variables.scss index 25e2684..b666639 100644 --- a/scss/node_modules/bootstrap/scss/_variables.scss +++ b/scss/node_modules/bootstrap/scss/_variables.scss @@ -1,7 +1,8 @@ -// Variables +// Variables bs 4.2.1 // // Variables should follow the `$component-state-property-size` formula for // consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. +// /* 5 times calc added to resolve Incompatible units rem and px. */ // Color system @@ -485,14 +486,14 @@ $input-placeholder-color: $gray-600 !default; $input-plaintext-color: $body-color !default; $input-height-border: $input-border-width * 2 !default; - -$input-height-inner: ($input-btn-font-size * $input-btn-line-height) + ($input-btn-padding-y * 2) !default; +/* 3 times calc added to resolve Incompatible units rem and px. */ +$input-height-inner: calc(($input-btn-font-size * $input-btn-line-height) + ($input-btn-padding-y * 2)) !default; $input-height: calc(#{$input-height-inner} + #{$input-height-border}) !default; -$input-height-inner-sm: ($input-btn-font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2) !default; +$input-height-inner-sm: calc(($input-btn-font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2)) !default; $input-height-sm: calc(#{$input-height-inner-sm} + #{$input-height-border}) !default; -$input-height-inner-lg: ($input-btn-font-size-lg * $input-btn-line-height-lg) + ($input-btn-padding-y-lg * 2) !default; +$input-height-inner-lg: calc(($input-btn-font-size-lg * $input-btn-line-height-lg) + ($input-btn-padding-y-lg * 2)) !default; $input-height-lg: calc(#{$input-height-inner-lg} + #{$input-height-border}) !default; $input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; @@ -726,9 +727,10 @@ $navbar-nav-link-padding-x: .5rem !default; $navbar-brand-font-size: $font-size-lg !default; // Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link -$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default; +/* 2 times calc added to resolve Incompatible units rem and px. */ +$nav-link-height: calc($font-size-base * $line-height-base + $nav-link-padding-y * 2) !default; $navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; -$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) / 2 !default; +$navbar-brand-padding-y: calc(($nav-link-height - $navbar-brand-height) / 2) !default; $navbar-toggler-padding-y: .25rem !default; $navbar-toggler-padding-x: .75rem !default; diff --git a/scss/node_modules/bootstrap/scss/_variables.scss.4.2.1.org b/scss/node_modules/bootstrap/scss/_variables.scss.4.2.1.org new file mode 100644 index 0000000..25e2684 --- /dev/null +++ b/scss/node_modules/bootstrap/scss/_variables.scss.4.2.1.org @@ -0,0 +1,1091 @@ +// Variables +// +// Variables should follow the `$component-state-property-size` formula for +// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. + +// Color system + +$white: #fff !default; +$gray-100: #f8f9fa !default; +$gray-200: #e9ecef !default; +$gray-300: #dee2e6 !default; +$gray-400: #ced4da !default; +$gray-500: #adb5bd !default; +$gray-600: #6c757d !default; +$gray-700: #495057 !default; +$gray-800: #343a40 !default; +$gray-900: #212529 !default; +$black: #000 !default; + +$grays: () !default; +// stylelint-disable-next-line scss/dollar-variable-default +$grays: map-merge( + ( + "100": $gray-100, + "200": $gray-200, + "300": $gray-300, + "400": $gray-400, + "500": $gray-500, + "600": $gray-600, + "700": $gray-700, + "800": $gray-800, + "900": $gray-900 + ), + $grays +); + +$blue: #007bff !default; +$indigo: #6610f2 !default; +$purple: #6f42c1 !default; +$pink: #e83e8c !default; +$red: #dc3545 !default; +$orange: #fd7e14 !default; +$yellow: #ffc107 !default; +$green: #28a745 !default; +$teal: #20c997 !default; +$cyan: #17a2b8 !default; + +$colors: () !default; +// stylelint-disable-next-line scss/dollar-variable-default +$colors: map-merge( + ( + "blue": $blue, + "indigo": $indigo, + "purple": $purple, + "pink": $pink, + "red": $red, + "orange": $orange, + "yellow": $yellow, + "green": $green, + "teal": $teal, + "cyan": $cyan, + "white": $white, + "gray": $gray-600, + "gray-dark": $gray-800 + ), + $colors +); + +$primary: $blue !default; +$secondary: $gray-600 !default; +$success: $green !default; +$info: $cyan !default; +$warning: $yellow !default; +$danger: $red !default; +$light: $gray-100 !default; +$dark: $gray-800 !default; + +$theme-colors: () !default; +// stylelint-disable-next-line scss/dollar-variable-default +$theme-colors: map-merge( + ( + "primary": $primary, + "secondary": $secondary, + "success": $success, + "info": $info, + "warning": $warning, + "danger": $danger, + "light": $light, + "dark": $dark + ), + $theme-colors +); + +// Set a specific jump point for requesting color jumps +$theme-color-interval: 8% !default; + +// The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255. +$yiq-contrasted-threshold: 150 !default; + +// Customize the light and dark text colors for use in our YIQ color contrast function. +$yiq-text-dark: $gray-900 !default; +$yiq-text-light: $white !default; + + +// Options +// +// Quickly modify global styling by enabling or disabling optional features. + +$enable-caret: true !default; +$enable-rounded: true !default; +$enable-shadows: false !default; +$enable-gradients: false !default; +$enable-transitions: true !default; +$enable-prefers-reduced-motion-media-query: true !default; +$enable-hover-media-query: false !default; // Deprecated, no longer affects any compiled CSS +$enable-grid-classes: true !default; +$enable-print-styles: true !default; +$enable-validation-icons: true !default; + + +// Spacing +// +// Control the default styling of most Bootstrap elements by modifying these +// variables. Mostly focused on spacing. +// You can add more entries to the $spacers map, should you need more variation. + +$spacer: 1rem !default; +$spacers: () !default; +// stylelint-disable-next-line scss/dollar-variable-default +$spacers: map-merge( + ( + 0: 0, + 1: ($spacer * .25), + 2: ($spacer * .5), + 3: $spacer, + 4: ($spacer * 1.5), + 5: ($spacer * 3) + ), + $spacers +); + +// This variable affects the `.h-*` and `.w-*` classes. +$sizes: () !default; +// stylelint-disable-next-line scss/dollar-variable-default +$sizes: map-merge( + ( + 25: 25%, + 50: 50%, + 75: 75%, + 100: 100%, + auto: auto + ), + $sizes +); + + +// Body +// +// Settings for the `` element. + +$body-bg: $white !default; +$body-color: $gray-900 !default; + + +// Links +// +// Style anchor elements. + +$link-color: theme-color("primary") !default; +$link-decoration: none !default; +$link-hover-color: darken($link-color, 15%) !default; +$link-hover-decoration: underline !default; +// Darken percentage for links with `.text-*` class (e.g. `.text-success`) +$emphasized-link-hover-darken-percentage: 15% !default; + +// Paragraphs +// +// Style p element. + +$paragraph-margin-bottom: 1rem !default; + + +// Grid breakpoints +// +// Define the minimum dimensions at which your layout will change, +// adapting to different screen sizes, for use in media queries. + +$grid-breakpoints: () !default; +// stylelint-disable-next-line scss/dollar-variable-default +$grid-breakpoints: map-merge( + ( + xs: 0, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px + ), + $grid-breakpoints +); + +@include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); +@include _assert-starts-at-zero($grid-breakpoints); + + +// Grid containers +// +// Define the maximum width of `.container` for different screen sizes. + +$container-max-widths: () !default; +// stylelint-disable-next-line scss/dollar-variable-default +$container-max-widths: map-merge( + ( + sm: 540px, + md: 720px, + lg: 960px, + xl: 1140px + ), + $container-max-widths +); + +@include _assert-ascending($container-max-widths, "$container-max-widths"); + + +// Grid columns +// +// Set the number of columns and specify the width of the gutters. + +$grid-columns: 12 !default; +$grid-gutter-width: 30px !default; + + +// Components +// +// Define common padding and border radius sizes and more. + +$line-height-lg: 1.5 !default; +$line-height-sm: 1.5 !default; + +$border-width: 1px !default; +$border-color: $gray-300 !default; + +$border-radius: .25rem !default; +$border-radius-lg: .3rem !default; +$border-radius-sm: .2rem !default; + +$rounded-pill: 50rem !default; + +$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default; +$box-shadow: 0 .5rem 1rem rgba($black, .15) !default; +$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default; + +$component-active-color: $white !default; +$component-active-bg: theme-color("primary") !default; + +$caret-width: .3em !default; + +$transition-base: all .2s ease-in-out !default; +$transition-fade: opacity .15s linear !default; +$transition-collapse: height .35s ease !default; + +$embed-responsive-aspect-ratios: () !default; +// stylelint-disable-next-line scss/dollar-variable-default +$embed-responsive-aspect-ratios: join( + ( + (21 9), + (16 9), + (3 4), + (1 1), + ), + $embed-responsive-aspect-ratios +); + +// Fonts +// +// Font, line-height, and color for body text, headings, and more. + +// stylelint-disable value-keyword-case +$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; +$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; +$font-family-base: $font-family-sans-serif !default; +// stylelint-enable value-keyword-case + +$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` +$font-size-lg: ($font-size-base * 1.25) !default; +$font-size-sm: ($font-size-base * .875) !default; + +$font-weight-lighter: lighter !default; +$font-weight-light: 300 !default; +$font-weight-normal: 400 !default; +$font-weight-bold: 700 !default; +$font-weight-bolder: bolder !default; + +$font-weight-base: $font-weight-normal !default; +$line-height-base: 1.5 !default; + +$h1-font-size: $font-size-base * 2.5 !default; +$h2-font-size: $font-size-base * 2 !default; +$h3-font-size: $font-size-base * 1.75 !default; +$h4-font-size: $font-size-base * 1.5 !default; +$h5-font-size: $font-size-base * 1.25 !default; +$h6-font-size: $font-size-base !default; + +$headings-margin-bottom: $spacer / 2 !default; +$headings-font-family: inherit !default; +$headings-font-weight: 500 !default; +$headings-line-height: 1.2 !default; +$headings-color: inherit !default; + +$display1-size: 6rem !default; +$display2-size: 5.5rem !default; +$display3-size: 4.5rem !default; +$display4-size: 3.5rem !default; + +$display1-weight: 300 !default; +$display2-weight: 300 !default; +$display3-weight: 300 !default; +$display4-weight: 300 !default; +$display-line-height: $headings-line-height !default; + +$lead-font-size: ($font-size-base * 1.25) !default; +$lead-font-weight: 300 !default; + +$small-font-size: 80% !default; + +$text-muted: $gray-600 !default; + +$blockquote-small-color: $gray-600 !default; +$blockquote-small-font-size: $small-font-size !default; +$blockquote-font-size: ($font-size-base * 1.25) !default; + +$hr-border-color: rgba($black, .1) !default; +$hr-border-width: $border-width !default; + +$mark-padding: .2em !default; + +$dt-font-weight: $font-weight-bold !default; + +$kbd-box-shadow: inset 0 -.1rem 0 rgba($black, .25) !default; +$nested-kbd-font-weight: $font-weight-bold !default; + +$list-inline-padding: .5rem !default; + +$mark-bg: #fcf8e3 !default; + +$hr-margin-y: $spacer !default; + + +// Tables +// +// Customizes the `.table` component with basic values, each used across all table variations. + +$table-cell-padding: .75rem !default; +$table-cell-padding-sm: .3rem !default; + +$table-bg: transparent !default; +$table-accent-bg: rgba($black, .05) !default; +$table-hover-bg: rgba($black, .075) !default; +$table-active-bg: $table-hover-bg !default; + +$table-border-width: $border-width !default; +$table-border-color: $gray-300 !default; + +$table-head-bg: $gray-200 !default; +$table-head-color: $gray-700 !default; + +$table-dark-bg: $gray-900 !default; +$table-dark-accent-bg: rgba($white, .05) !default; +$table-dark-hover-bg: rgba($white, .075) !default; +$table-dark-border-color: lighten($gray-900, 7.5%) !default; +$table-dark-color: $white !default; + +$table-striped-order: odd !default; + +$table-caption-color: $text-muted !default; + +$table-bg-level: -9 !default; +$table-border-level: -6 !default; + + +// Buttons + Forms +// +// Shared variables that are reassigned to `$input-` and `$btn-` specific variables. + +$input-btn-padding-y: .375rem !default; +$input-btn-padding-x: .75rem !default; +$input-btn-font-size: $font-size-base !default; +$input-btn-line-height: $line-height-base !default; + +$input-btn-focus-width: .2rem !default; +$input-btn-focus-color: rgba($component-active-bg, .25) !default; +$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default; + +$input-btn-padding-y-sm: .25rem !default; +$input-btn-padding-x-sm: .5rem !default; +$input-btn-font-size-sm: $font-size-sm !default; +$input-btn-line-height-sm: $line-height-sm !default; + +$input-btn-padding-y-lg: .5rem !default; +$input-btn-padding-x-lg: 1rem !default; +$input-btn-font-size-lg: $font-size-lg !default; +$input-btn-line-height-lg: $line-height-lg !default; + +$input-btn-border-width: $border-width !default; + + +// Buttons +// +// For each of Bootstrap's buttons, define text, background, and border color. + +$btn-padding-y: $input-btn-padding-y !default; +$btn-padding-x: $input-btn-padding-x !default; +$btn-font-size: $input-btn-font-size !default; +$btn-line-height: $input-btn-line-height !default; + +$btn-padding-y-sm: $input-btn-padding-y-sm !default; +$btn-padding-x-sm: $input-btn-padding-x-sm !default; +$btn-font-size-sm: $input-btn-font-size-sm !default; +$btn-line-height-sm: $input-btn-line-height-sm !default; + +$btn-padding-y-lg: $input-btn-padding-y-lg !default; +$btn-padding-x-lg: $input-btn-padding-x-lg !default; +$btn-font-size-lg: $input-btn-font-size-lg !default; +$btn-line-height-lg: $input-btn-line-height-lg !default; + +$btn-border-width: $input-btn-border-width !default; + +$btn-font-weight: $font-weight-normal !default; +$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default; +$btn-focus-width: $input-btn-focus-width !default; +$btn-focus-box-shadow: $input-btn-focus-box-shadow !default; +$btn-disabled-opacity: .65 !default; +$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default; + +$btn-link-disabled-color: $gray-600 !default; + +$btn-block-spacing-y: .5rem !default; + +// Allows for customizing button radius independently from global border radius +$btn-border-radius: $border-radius !default; +$btn-border-radius-lg: $border-radius-lg !default; +$btn-border-radius-sm: $border-radius-sm !default; + +$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + + +// Forms + +$label-margin-bottom: .5rem !default; + +$input-padding-y: $input-btn-padding-y !default; +$input-padding-x: $input-btn-padding-x !default; +$input-font-size: $input-btn-font-size !default; +$input-font-weight: $font-weight-base !default; +$input-line-height: $input-btn-line-height !default; + +$input-padding-y-sm: $input-btn-padding-y-sm !default; +$input-padding-x-sm: $input-btn-padding-x-sm !default; +$input-font-size-sm: $input-btn-font-size-sm !default; +$input-line-height-sm: $input-btn-line-height-sm !default; + +$input-padding-y-lg: $input-btn-padding-y-lg !default; +$input-padding-x-lg: $input-btn-padding-x-lg !default; +$input-font-size-lg: $input-btn-font-size-lg !default; +$input-line-height-lg: $input-btn-line-height-lg !default; + +$input-bg: $white !default; +$input-disabled-bg: $gray-200 !default; + +$input-color: $gray-700 !default; +$input-border-color: $gray-400 !default; +$input-border-width: $input-btn-border-width !default; +$input-box-shadow: inset 0 1px 1px rgba($black, .075) !default; + +$input-border-radius: $border-radius !default; +$input-border-radius-lg: $border-radius-lg !default; +$input-border-radius-sm: $border-radius-sm !default; + +$input-focus-bg: $input-bg !default; +$input-focus-border-color: lighten($component-active-bg, 25%) !default; +$input-focus-color: $input-color !default; +$input-focus-width: $input-btn-focus-width !default; +$input-focus-box-shadow: $input-btn-focus-box-shadow !default; + +$input-placeholder-color: $gray-600 !default; +$input-plaintext-color: $body-color !default; + +$input-height-border: $input-border-width * 2 !default; + +$input-height-inner: ($input-btn-font-size * $input-btn-line-height) + ($input-btn-padding-y * 2) !default; +$input-height: calc(#{$input-height-inner} + #{$input-height-border}) !default; + +$input-height-inner-sm: ($input-btn-font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2) !default; +$input-height-sm: calc(#{$input-height-inner-sm} + #{$input-height-border}) !default; + +$input-height-inner-lg: ($input-btn-font-size-lg * $input-btn-line-height-lg) + ($input-btn-padding-y-lg * 2) !default; +$input-height-lg: calc(#{$input-height-inner-lg} + #{$input-height-border}) !default; + +$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$form-text-margin-top: .25rem !default; + +$form-check-input-gutter: 1.25rem !default; +$form-check-input-margin-y: .3rem !default; +$form-check-input-margin-x: .25rem !default; + +$form-check-inline-margin-x: .75rem !default; +$form-check-inline-input-margin-x: .3125rem !default; + +$form-grid-gutter-width: 10px !default; +$form-group-margin-bottom: 1rem !default; + +$input-group-addon-color: $input-color !default; +$input-group-addon-bg: $gray-200 !default; +$input-group-addon-border-color: $input-border-color !default; + +$custom-forms-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$custom-control-gutter: .5rem !default; +$custom-control-spacer-x: 1rem !default; + +$custom-control-indicator-size: 1rem !default; +$custom-control-indicator-bg: $input-bg !default; + +$custom-control-indicator-bg-size: 50% 50% !default; +$custom-control-indicator-box-shadow: $input-box-shadow !default; +$custom-control-indicator-border-color: $gray-500 !default; +$custom-control-indicator-border-width: $input-border-width !default; + +$custom-control-indicator-disabled-bg: $input-disabled-bg !default; +$custom-control-label-disabled-color: $gray-600 !default; + +$custom-control-indicator-checked-color: $component-active-color !default; +$custom-control-indicator-checked-bg: $component-active-bg !default; +$custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), .5) !default; +$custom-control-indicator-checked-box-shadow: none !default; +$custom-control-indicator-checked-border-color: $custom-control-indicator-checked-bg !default; + +$custom-control-indicator-focus-box-shadow: $input-btn-focus-box-shadow !default; +$custom-control-indicator-focus-border-color: $input-focus-border-color !default; + +$custom-control-indicator-active-color: $component-active-color !default; +$custom-control-indicator-active-bg: lighten($component-active-bg, 35%) !default; +$custom-control-indicator-active-box-shadow: none !default; +$custom-control-indicator-active-border-color: $custom-control-indicator-active-bg !default; + +$custom-checkbox-indicator-border-radius: $border-radius !default; +$custom-checkbox-indicator-icon-checked: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='#{$custom-control-indicator-checked-color}' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e"), "#", "%23") !default; + +$custom-checkbox-indicator-indeterminate-bg: $component-active-bg !default; +$custom-checkbox-indicator-indeterminate-color: $custom-control-indicator-checked-color !default; +$custom-checkbox-indicator-icon-indeterminate: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='#{$custom-checkbox-indicator-indeterminate-color}' d='M0 2h4'/%3e%3c/svg%3e"), "#", "%23") !default; +$custom-checkbox-indicator-indeterminate-box-shadow: none !default; +$custom-checkbox-indicator-indeterminate-border-color: $custom-checkbox-indicator-indeterminate-bg !default; + +$custom-radio-indicator-border-radius: 50% !default; +$custom-radio-indicator-icon-checked: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$custom-control-indicator-checked-color}'/%3e%3c/svg%3e"), "#", "%23") !default; + +$custom-switch-width: $custom-control-indicator-size * 1.75 !default; +$custom-switch-indicator-border-radius: $custom-control-indicator-size / 2 !default; +$custom-switch-indicator-size: calc(#{$custom-control-indicator-size} - #{$custom-control-indicator-border-width * 4}) !default; + +$custom-select-padding-y: $input-btn-padding-y !default; +$custom-select-padding-x: $input-btn-padding-x !default; +$custom-select-height: $input-height !default; +$custom-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator +$custom-select-font-weight: $input-font-weight !default; +$custom-select-line-height: $input-line-height !default; +$custom-select-color: $input-color !default; +$custom-select-disabled-color: $gray-600 !default; +$custom-select-bg: $input-bg !default; +$custom-select-disabled-bg: $gray-200 !default; +$custom-select-bg-size: 8px 10px !default; // In pixels because image dimensions +$custom-select-indicator-color: $gray-800 !default; +$custom-select-indicator: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e"), "#", "%23") !default; +$custom-select-background: $custom-select-indicator no-repeat right $custom-select-padding-x center / $custom-select-bg-size !default; // Used so we can have multiple background elements (e.g., arrow and feedback icon) + +$custom-select-feedback-icon-padding-right: $input-height-inner * 3 / 4 + $custom-select-padding-x + $custom-select-indicator-padding !default; +$custom-select-feedback-icon-position: center right ($custom-select-padding-x + $custom-select-indicator-padding) !default; +$custom-select-feedback-icon-size: ($input-height-inner / 2) ($input-height-inner / 2) !default; + +$custom-select-border-width: $input-border-width !default; +$custom-select-border-color: $input-border-color !default; +$custom-select-border-radius: $border-radius !default; +$custom-select-box-shadow: inset 0 1px 2px rgba($black, .075) !default; + +$custom-select-focus-border-color: $input-focus-border-color !default; +$custom-select-focus-width: $input-focus-width !default; +$custom-select-focus-box-shadow: 0 0 0 $custom-select-focus-width rgba($custom-select-focus-border-color, .5) !default; + +$custom-select-padding-y-sm: $input-padding-y-sm !default; +$custom-select-padding-x-sm: $input-padding-x-sm !default; +$custom-select-font-size-sm: $input-btn-font-size-sm !default; +$custom-select-height-sm: $input-height-sm !default; + +$custom-select-padding-y-lg: $input-padding-y-lg !default; +$custom-select-padding-x-lg: $input-padding-x-lg !default; +$custom-select-font-size-lg: $input-btn-font-size-lg !default; +$custom-select-height-lg: $input-height-lg !default; + +$custom-range-track-width: 100% !default; +$custom-range-track-height: .5rem !default; +$custom-range-track-cursor: pointer !default; +$custom-range-track-bg: $gray-300 !default; +$custom-range-track-border-radius: 1rem !default; +$custom-range-track-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default; + +$custom-range-thumb-width: 1rem !default; +$custom-range-thumb-height: $custom-range-thumb-width !default; +$custom-range-thumb-bg: $component-active-bg !default; +$custom-range-thumb-border: 0 !default; +$custom-range-thumb-border-radius: 1rem !default; +$custom-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default; +$custom-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default; +$custom-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in IE/Edge +$custom-range-thumb-active-bg: lighten($component-active-bg, 35%) !default; +$custom-range-thumb-disabled-bg: $gray-500 !default; + +$custom-file-height: $input-height !default; +$custom-file-height-inner: $input-height-inner !default; +$custom-file-focus-border-color: $input-focus-border-color !default; +$custom-file-focus-box-shadow: $input-focus-box-shadow !default; +$custom-file-disabled-bg: $input-disabled-bg !default; + +$custom-file-padding-y: $input-padding-y !default; +$custom-file-padding-x: $input-padding-x !default; +$custom-file-line-height: $input-line-height !default; +$custom-file-font-weight: $input-font-weight !default; +$custom-file-color: $input-color !default; +$custom-file-bg: $input-bg !default; +$custom-file-border-width: $input-border-width !default; +$custom-file-border-color: $input-border-color !default; +$custom-file-border-radius: $input-border-radius !default; +$custom-file-box-shadow: $input-box-shadow !default; +$custom-file-button-color: $custom-file-color !default; +$custom-file-button-bg: $input-group-addon-bg !default; +$custom-file-text: ( + en: "Browse" +) !default; + + +// Form validation + +$form-feedback-margin-top: $form-text-margin-top !default; +$form-feedback-font-size: $small-font-size !default; +$form-feedback-valid-color: theme-color("success") !default; +$form-feedback-invalid-color: theme-color("danger") !default; + +$form-feedback-icon-valid-color: $form-feedback-valid-color !default; +$form-feedback-icon-valid: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"), "#", "%23") !default; +$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default; +$form-feedback-icon-invalid: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$form-feedback-icon-invalid-color}' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E"), "#", "%23") !default; + + +// Dropdowns +// +// Dropdown menu container and contents. + +$dropdown-min-width: 10rem !default; +$dropdown-padding-y: .5rem !default; +$dropdown-spacer: .125rem !default; +$dropdown-bg: $white !default; +$dropdown-border-color: rgba($black, .15) !default; +$dropdown-border-radius: $border-radius !default; +$dropdown-border-width: $border-width !default; +$dropdown-inner-border-radius: calc(#{$dropdown-border-radius} - #{$dropdown-border-width}) !default; +$dropdown-divider-bg: $gray-200 !default; +$dropdown-box-shadow: 0 .5rem 1rem rgba($black, .175) !default; + +$dropdown-link-color: $gray-900 !default; +$dropdown-link-hover-color: darken($gray-900, 5%) !default; +$dropdown-link-hover-bg: $gray-100 !default; + +$dropdown-link-active-color: $component-active-color !default; +$dropdown-link-active-bg: $component-active-bg !default; + +$dropdown-link-disabled-color: $gray-600 !default; + +$dropdown-item-padding-y: .25rem !default; +$dropdown-item-padding-x: 1.5rem !default; + +$dropdown-header-color: $gray-600 !default; + + +// Z-index master list +// +// Warning: Avoid customizing these values. They're used for a bird's eye view +// of components dependent on the z-axis and are designed to all work together. + +$zindex-dropdown: 1000 !default; +$zindex-sticky: 1020 !default; +$zindex-fixed: 1030 !default; +$zindex-modal-backdrop: 1040 !default; +$zindex-modal: 1050 !default; +$zindex-popover: 1060 !default; +$zindex-tooltip: 1070 !default; + + +// Navs + +$nav-link-padding-y: .5rem !default; +$nav-link-padding-x: 1rem !default; +$nav-link-disabled-color: $gray-600 !default; + +$nav-tabs-border-color: $gray-300 !default; +$nav-tabs-border-width: $border-width !default; +$nav-tabs-border-radius: $border-radius !default; +$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default; +$nav-tabs-link-active-color: $gray-700 !default; +$nav-tabs-link-active-bg: $body-bg !default; +$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default; + +$nav-pills-border-radius: $border-radius !default; +$nav-pills-link-active-color: $component-active-color !default; +$nav-pills-link-active-bg: $component-active-bg !default; + +$nav-divider-color: $gray-200 !default; +$nav-divider-margin-y: $spacer / 2 !default; + + +// Navbar + +$navbar-padding-y: $spacer / 2 !default; +$navbar-padding-x: $spacer !default; + +$navbar-nav-link-padding-x: .5rem !default; + +$navbar-brand-font-size: $font-size-lg !default; +// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link +$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default; +$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; +$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) / 2 !default; + +$navbar-toggler-padding-y: .25rem !default; +$navbar-toggler-padding-x: .75rem !default; +$navbar-toggler-font-size: $font-size-lg !default; +$navbar-toggler-border-radius: $btn-border-radius !default; + +$navbar-dark-color: rgba($white, .5) !default; +$navbar-dark-hover-color: rgba($white, .75) !default; +$navbar-dark-active-color: $white !default; +$navbar-dark-disabled-color: rgba($white, .25) !default; +$navbar-dark-toggler-icon-bg: str-replace(url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"), "#", "%23") !default; +$navbar-dark-toggler-border-color: rgba($white, .1) !default; + +$navbar-light-color: rgba($black, .5) !default; +$navbar-light-hover-color: rgba($black, .7) !default; +$navbar-light-active-color: rgba($black, .9) !default; +$navbar-light-disabled-color: rgba($black, .3) !default; +$navbar-light-toggler-icon-bg: str-replace(url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"), "#", "%23") !default; +$navbar-light-toggler-border-color: rgba($black, .1) !default; + +$navbar-light-brand-color: $navbar-light-active-color !default; +$navbar-light-brand-hover-color: $navbar-light-active-color !default; +$navbar-dark-brand-color: $navbar-dark-active-color !default; +$navbar-dark-brand-hover-color: $navbar-dark-active-color !default; + + +// Pagination + +$pagination-padding-y: .5rem !default; +$pagination-padding-x: .75rem !default; +$pagination-padding-y-sm: .25rem !default; +$pagination-padding-x-sm: .5rem !default; +$pagination-padding-y-lg: .75rem !default; +$pagination-padding-x-lg: 1.5rem !default; +$pagination-line-height: 1.25 !default; + +$pagination-color: $link-color !default; +$pagination-bg: $white !default; +$pagination-border-width: $border-width !default; +$pagination-border-color: $gray-300 !default; + +$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default; +$pagination-focus-outline: 0 !default; + +$pagination-hover-color: $link-hover-color !default; +$pagination-hover-bg: $gray-200 !default; +$pagination-hover-border-color: $gray-300 !default; + +$pagination-active-color: $component-active-color !default; +$pagination-active-bg: $component-active-bg !default; +$pagination-active-border-color: $pagination-active-bg !default; + +$pagination-disabled-color: $gray-600 !default; +$pagination-disabled-bg: $white !default; +$pagination-disabled-border-color: $gray-300 !default; + + +// Jumbotron + +$jumbotron-padding: 2rem !default; +$jumbotron-bg: $gray-200 !default; + + +// Cards + +$card-spacer-y: .75rem !default; +$card-spacer-x: 1.25rem !default; +$card-border-width: $border-width !default; +$card-border-radius: $border-radius !default; +$card-border-color: rgba($black, .125) !default; +$card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}) !default; +$card-cap-bg: rgba($black, .03) !default; +$card-cap-color: inherit !default; +$card-bg: $white !default; + +$card-img-overlay-padding: 1.25rem !default; + +$card-group-margin: $grid-gutter-width / 2 !default; +$card-deck-margin: $card-group-margin !default; + +$card-columns-count: 3 !default; +$card-columns-gap: 1.25rem !default; +$card-columns-margin: $card-spacer-y !default; + + +// Tooltips + +$tooltip-font-size: $font-size-sm !default; +$tooltip-max-width: 200px !default; +$tooltip-color: $white !default; +$tooltip-bg: $black !default; +$tooltip-border-radius: $border-radius !default; +$tooltip-opacity: .9 !default; +$tooltip-padding-y: .25rem !default; +$tooltip-padding-x: .5rem !default; +$tooltip-margin: 0 !default; + +$tooltip-arrow-width: .8rem !default; +$tooltip-arrow-height: .4rem !default; +$tooltip-arrow-color: $tooltip-bg !default; + +// Form tooltips must come after regular tooltips +$form-feedback-tooltip-padding-y: $tooltip-padding-y !default; +$form-feedback-tooltip-padding-x: $tooltip-padding-x !default; +$form-feedback-tooltip-font-size: $tooltip-font-size !default; +$form-feedback-tooltip-line-height: $line-height-base !default; +$form-feedback-tooltip-opacity: $tooltip-opacity !default; +$form-feedback-tooltip-border-radius: $tooltip-border-radius !default; + + +// Popovers + +$popover-font-size: $font-size-sm !default; +$popover-bg: $white !default; +$popover-max-width: 276px !default; +$popover-border-width: $border-width !default; +$popover-border-color: rgba($black, .2) !default; +$popover-border-radius: $border-radius-lg !default; +$popover-box-shadow: 0 .25rem .5rem rgba($black, .2) !default; + +$popover-header-bg: darken($popover-bg, 3%) !default; +$popover-header-color: $headings-color !default; +$popover-header-padding-y: .5rem !default; +$popover-header-padding-x: .75rem !default; + +$popover-body-color: $body-color !default; +$popover-body-padding-y: $popover-header-padding-y !default; +$popover-body-padding-x: $popover-header-padding-x !default; + +$popover-arrow-width: 1rem !default; +$popover-arrow-height: .5rem !default; +$popover-arrow-color: $popover-bg !default; + +$popover-arrow-outer-color: fade-in($popover-border-color, .05) !default; + + +// Toasts +$toast-max-width: 350px !default; +$toast-padding-x: .75rem !default; +$toast-padding-y: .25rem !default; +$toast-font-size: .875rem !default; +$toast-background-color: rgba($white, .85) !default; +$toast-border-width: 1px !default; +$toast-border-color: rgba(0, 0, 0, .1) !default; +$toast-border-radius: .25rem !default; +$toast-box-shadow: 0 .25rem .75rem rgba($black, .1) !default; + +$toast-header-color: $gray-600 !default; +$toast-header-background-color: rgba($white, .85) !default; +$toast-header-border-color: rgba(0, 0, 0, .05) !default; + + +// Badges + +$badge-font-size: 75% !default; +$badge-font-weight: $font-weight-bold !default; +$badge-padding-y: .25em !default; +$badge-padding-x: .4em !default; +$badge-border-radius: $border-radius !default; + +$badge-pill-padding-x: .6em !default; +// Use a higher than normal value to ensure completely rounded edges when +// customizing padding or font-size on labels. +$badge-pill-border-radius: 10rem !default; + + +// Modals + +// Padding applied to the modal body +$modal-inner-padding: 1rem !default; + +$modal-dialog-margin: .5rem !default; +$modal-dialog-margin-y-sm-up: 1.75rem !default; + +$modal-title-line-height: $line-height-base !default; + +$modal-content-bg: $white !default; +$modal-content-border-color: rgba($black, .2) !default; +$modal-content-border-width: $border-width !default; +$modal-content-border-radius: $border-radius-lg !default; +$modal-content-box-shadow-xs: 0 .25rem .5rem rgba($black, .5) !default; +$modal-content-box-shadow-sm-up: 0 .5rem 1rem rgba($black, .5) !default; + +$modal-backdrop-bg: $black !default; +$modal-backdrop-opacity: .5 !default; +$modal-header-border-color: $gray-200 !default; +$modal-footer-border-color: $modal-header-border-color !default; +$modal-header-border-width: $modal-content-border-width !default; +$modal-footer-border-width: $modal-header-border-width !default; +$modal-header-padding-y: 1rem !default; +$modal-header-padding-x: 1rem !default; +$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility + +$modal-xl: 1140px !default; +$modal-lg: 800px !default; +$modal-md: 500px !default; +$modal-sm: 300px !default; + +$modal-fade-transform: translate(0, -50px) !default; +$modal-show-transform: none !default; +$modal-transition: transform .3s ease-out !default; + + +// Alerts +// +// Define alert colors, border radius, and padding. + +$alert-padding-y: .75rem !default; +$alert-padding-x: 1.25rem !default; +$alert-margin-bottom: 1rem !default; +$alert-border-radius: $border-radius !default; +$alert-link-font-weight: $font-weight-bold !default; +$alert-border-width: $border-width !default; + +$alert-bg-level: -10 !default; +$alert-border-level: -9 !default; +$alert-color-level: 6 !default; + + +// Progress bars + +$progress-height: 1rem !default; +$progress-font-size: ($font-size-base * .75) !default; +$progress-bg: $gray-200 !default; +$progress-border-radius: $border-radius !default; +$progress-box-shadow: inset 0 .1rem .1rem rgba($black, .1) !default; +$progress-bar-color: $white !default; +$progress-bar-bg: theme-color("primary") !default; +$progress-bar-animation-timing: 1s linear infinite !default; +$progress-bar-transition: width .6s ease !default; + + +// List group + +$list-group-bg: $white !default; +$list-group-border-color: rgba($black, .125) !default; +$list-group-border-width: $border-width !default; +$list-group-border-radius: $border-radius !default; + +$list-group-item-padding-y: .75rem !default; +$list-group-item-padding-x: 1.25rem !default; + +$list-group-hover-bg: $gray-100 !default; +$list-group-active-color: $component-active-color !default; +$list-group-active-bg: $component-active-bg !default; +$list-group-active-border-color: $list-group-active-bg !default; + +$list-group-disabled-color: $gray-600 !default; +$list-group-disabled-bg: $list-group-bg !default; + +$list-group-action-color: $gray-700 !default; +$list-group-action-hover-color: $list-group-action-color !default; + +$list-group-action-active-color: $body-color !default; +$list-group-action-active-bg: $gray-200 !default; + + +// Image thumbnails + +$thumbnail-padding: .25rem !default; +$thumbnail-bg: $body-bg !default; +$thumbnail-border-width: $border-width !default; +$thumbnail-border-color: $gray-300 !default; +$thumbnail-border-radius: $border-radius !default; +$thumbnail-box-shadow: 0 1px 2px rgba($black, .075) !default; + + +// Figures + +$figure-caption-font-size: 90% !default; +$figure-caption-color: $gray-600 !default; + + +// Breadcrumbs + +$breadcrumb-padding-y: .75rem !default; +$breadcrumb-padding-x: 1rem !default; +$breadcrumb-item-padding: .5rem !default; + +$breadcrumb-margin-bottom: 1rem !default; + +$breadcrumb-bg: $gray-200 !default; +$breadcrumb-divider-color: $gray-600 !default; +$breadcrumb-active-color: $gray-600 !default; +$breadcrumb-divider: quote("/") !default; + +$breadcrumb-border-radius: $border-radius !default; + + +// Carousel + +$carousel-control-color: $white !default; +$carousel-control-width: 15% !default; +$carousel-control-opacity: .5 !default; +$carousel-control-hover-opacity: .9 !default; +$carousel-control-transition: opacity .15s ease !default; + +$carousel-indicator-width: 30px !default; +$carousel-indicator-height: 3px !default; +$carousel-indicator-hit-area-height: 10px !default; +$carousel-indicator-spacer: 3px !default; +$carousel-indicator-active-bg: $white !default; +$carousel-indicator-transition: opacity .6s ease !default; + +$carousel-caption-width: 70% !default; +$carousel-caption-color: $white !default; + +$carousel-control-icon-width: 20px !default; + +$carousel-control-prev-icon-bg: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e"), "#", "%23") !default; +$carousel-control-next-icon-bg: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e"), "#", "%23") !default; + +$carousel-transition-duration: .6s !default; +$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`) + + +// Spinners + +$spinner-width: 2rem !default; +$spinner-height: $spinner-width !default; +$spinner-border-width: .25em !default; + +$spinner-width-sm: 1rem !default; +$spinner-height-sm: $spinner-width-sm !default; +$spinner-border-width-sm: .2em !default; + + +// Close + +$close-font-size: $font-size-base * 1.5 !default; +$close-font-weight: $font-weight-bold !default; +$close-color: $black !default; +$close-text-shadow: 0 1px 0 $white !default; + + +// Code + +$code-font-size: 87.5% !default; +$code-color: $pink !default; + +$kbd-padding-y: .2rem !default; +$kbd-padding-x: .4rem !default; +$kbd-font-size: $code-font-size !default; +$kbd-color: $white !default; +$kbd-bg: $gray-900 !default; + +$pre-color: $gray-900 !default; +$pre-scrollable-max-height: 340px !default; + + +// Utilities + +$overflows: auto, hidden !default; +$positions: static, relative, absolute, fixed, sticky !default; + + +// Printing + +$print-page-size: a3 !default; +$print-body-min-width: map-get($grid-breakpoints, "lg") !default; From 0a1f35a36efb0b24ac1859f69842bbacdcab8f12 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Fri, 4 Oct 2024 08:51:16 +0000 Subject: [PATCH 13/82] 2.2.0 add scssphp/server --- README.md | 2 +- rules/compiler.php | 16 +- rules/server/.gitignore | 1 + rules/server/README.md | 70 + rules/server/composer.json | 19 + rules/server/composer.lock | 1949 +++++++++++++++++ rules/server/phpunit.xml.dist | 27 + rules/server/src/Server.php | 550 +++++ rules/server/src/ServerException.php | 24 + rules/server/tests/ServerTest.php | 40 + rules/server/tests/inputs/import.scss | 23 + .../server/tests/inputs/imports/_partial.scss | 10 + rules/server/tests/inputs/imports/simple.scss | 4 + 13 files changed, 2727 insertions(+), 8 deletions(-) create mode 100644 rules/server/.gitignore create mode 100644 rules/server/README.md create mode 100644 rules/server/composer.json create mode 100644 rules/server/composer.lock create mode 100644 rules/server/phpunit.xml.dist create mode 100644 rules/server/src/Server.php create mode 100644 rules/server/src/ServerException.php create mode 100644 rules/server/tests/ServerTest.php create mode 100644 rules/server/tests/inputs/import.scss create mode 100644 rules/server/tests/inputs/imports/_partial.scss create mode 100644 rules/server/tests/inputs/imports/simple.scss diff --git a/README.md b/README.md index fd31de8..bbe3191 100644 --- a/README.md +++ b/README.md @@ -12,5 +12,5 @@ This project is licensed under the [GNU GPL], version 3 or later. ## Changelog * 2.2.0.dev improvements rssfoto newsfeeds for J4,J5, remove suport BS3, use latest versions BS4 and BS5, remove some redundant code. original scss files of BS4 and BS5 in folders scss bs4 and bs5. - New scss compiler scssphp/scssphp 1.13.0 as continuation of leafo/scssphp + New scss compiler scssphp/scssphp 1.13.0 and server scssphp/server 1.1.0 as continuation of leafo/scssphp * 2.1.2 removed hard returns from documentation field because j4.4 + doesn't accept that. diff --git a/rules/compiler.php b/rules/compiler.php index fc9db2b..a02766d 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -23,13 +23,13 @@ v 20-3-2019 border en active link colors nav-bar v 26-12-2021 added Joomla version info to use J4 specific code. 2023-12-07 resolved Unknown constant path_parts (is var $path_parts). -2024-10-03 v2.2.0 New scss compiler scssphp/scssphp 1.13.0 as continuation of leafo/scssphp. remove Bootstrap 3, use latest versions 5.3.3 and 4.6.2 - of BS 5 and 4. +2024-10-03 v2.2.0 New scss compiler scssphp/scssphp 1.13.0 and server scssphp/server 1.1.0 as continuation of leafo/scssphp. + Remove Bootstrap 3, use latest versions 5.3.3 and 4.6.2 of BS 5 and 4. */ defined('_JEXEC') or die('caught by _JEXEC'); use ScssPhp\ScssPhp\Compiler; -//use Leafo\ScssPhp\Server; +use ScssPhp\Server\Server; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormRule; @@ -87,6 +87,8 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input // require_once "leafo/src/Server.php"; // scss compiler van scssphp https://scssphp.github.io/scssphp/ require_once "scssphp/scss.inc.php"; + require_once "server/src/Server.php"; + require_once "server/src/ServerException.php"; $scss = new Compiler(); @@ -94,14 +96,14 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input if ( htmlspecialchars($params->compress) == "1") { // $scss->setFormatter('Leafo\ScssPhp\Formatter\Crunched'); -// $scss->setOutputStyle ('\ScssPhp\ScssPhp\OutputStyle::COMPRESSED'); - $scss->setOutputStyle ('compressed'); + $scss->setOutputStyle (\ScssPhp\ScssPhp\OutputStyle::COMPRESSED); +// $scss->setOutputStyle ('compressed'); } else { // voor debug netter formatteren en commentaren behouden. // $scss->setFormatter('Leafo\ScssPhp\Formatter\Expanded'); -// $scss->setOutputStyle ('\ScssPhp\ScssPhp\OutputStyle::EXPANDED'); - $scss->setOutputStyle ('expanded'); + $scss->setOutputStyle (\ScssPhp\ScssPhp\OutputStyle::EXPANDED); +// $scss->setOutputStyle ('expanded'); // $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); } diff --git a/rules/server/.gitignore b/rules/server/.gitignore new file mode 100644 index 0000000..57872d0 --- /dev/null +++ b/rules/server/.gitignore @@ -0,0 +1 @@ +/vendor/ diff --git a/rules/server/README.md b/rules/server/README.md new file mode 100644 index 0000000..e9045cd --- /dev/null +++ b/rules/server/README.md @@ -0,0 +1,70 @@ +## Server Example + +If you just want to start serving compiled `scss` files as quick as possible +then start here. The **scssphp/server** project provides an easy-to-use example +that demonstrates how to automatically compile `scss` files and serve them from +a directory that you specify. + +Create a file, like `style.php`: + +``` +use ScssPhp\Server\Server; + +$directory = "stylesheets"; + +$server = new Server($directory); +$server->serve(); +``` + +Create the directory set in the script alongside the script, then add your +`scss` files to it. + +By default, **scssphp** expects a `scss_cache` directory to exist inside the +stylesheets directory where it will cache the compiled output. This way it can +quickly serve the files if no modifications have been made. Your PHP script +must have permission to write in `scss_cache`. + +Going to the URL `example.com/style.php/style.scss` will attempt to compile +`style.scss` from the `stylesheets` directory, and serve it as CSS. + +If it can not find the file it will return an HTTP 404 page: + +``` +/* INPUT NOT FOUND scss v0.0.1 */ +``` + +If the file can't be compiled due to an error, then an HTTP 500 page is +returned. Similar to the following: + +``` +Parse error: failed at 'height: ;' stylesheets/test.scss on line 8 +``` + +Also, because SCSS server writes headers, make sure no output is written before +it runs. + +### Constructor + +Use the `Server` constructor to specify the cache directory and even the +instance of the `Compiler` that is used to compile SCSS. + +* `new Server($sourceDir, $cacheDir, $scss)` creates a new server that + serves files from `$sourceDir`. The cache dir is where the cached compiled + files are placed. When `null`, `$sourceDir . '/scss_cache'` is used. `$scss` + is the instance of `scss` that is used to compile. + +Just call the `serve` method to let it render its output. + +Here's an example of creating a SCSS server that outputs compressed CSS: + +``` +use ScssPhp\ScssPhp\Compiler; +use ScssPhp\Server\Server; + +$scss = new Compiler(); +$scss->setOutputStyle(\ScssPhp\ScssPhp\OutputStyle::COMPRESSED); + +$server = new Server('stylesheets', null, $scss); + +$server->serve(); +``` diff --git a/rules/server/composer.json b/rules/server/composer.json new file mode 100644 index 0000000..64eefa8 --- /dev/null +++ b/rules/server/composer.json @@ -0,0 +1,19 @@ +{ + "name": "scssphp/server", + "description": "Server for on-the-fly .scss compilation", + "type": "library", + "autoload": { + "psr-4": { "ScssPhp\\Server\\": "src/" } + }, + "autoload-dev": { + "psr-4": { "ScssPhp\\Server\\Tests\\": "tests/" } + }, + "require": { + "scssphp/scssphp": "^1.10" + }, + "require-dev": { + "squizlabs/php_codesniffer": "~2.5", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3" + }, + "license": "MIT" +} diff --git a/rules/server/composer.lock b/rules/server/composer.lock new file mode 100644 index 0000000..9bd7fc7 --- /dev/null +++ b/rules/server/composer.lock @@ -0,0 +1,1949 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "d871c081aea1f136a1df580e3359edbc", + "packages": [ + { + "name": "scssphp/scssphp", + "version": "v1.6.0", + "source": { + "type": "git", + "url": "https://github.com/scssphp/scssphp.git", + "reference": "b83594e2323c5d6e80785df3f91b9d1d32aad530" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/scssphp/scssphp/zipball/b83594e2323c5d6e80785df3f91b9d1d32aad530", + "reference": "b83594e2323c5d6e80785df3f91b9d1d32aad530", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "php": ">=5.6.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4", + "phpunit/phpunit": "^5.7 || ^6.5 || ^7.5 || ^8.3 || ^9.4", + "sass/sass-spec": "*", + "squizlabs/php_codesniffer": "~3.5", + "symfony/phpunit-bridge": "^5.1", + "twbs/bootstrap": "~5.0", + "twbs/bootstrap4": "4.6.0", + "zurb/foundation": "~6.5" + }, + "suggest": { + "ext-iconv": "Can be used as fallback when ext-mbstring is not available", + "ext-mbstring": "For best performance, mbstring should be installed as it is faster than ext-iconv" + }, + "bin": [ + "bin/pscss" + ], + "type": "library", + "autoload": { + "psr-4": { + "ScssPhp\\ScssPhp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Anthon Pang", + "email": "apang@softwaredevelopment.ca", + "homepage": "https://github.com/robocoder" + }, + { + "name": "Cédric Morin", + "email": "cedric@yterium.com", + "homepage": "https://github.com/Cerdic" + } + ], + "description": "scssphp is a compiler for SCSS written in PHP.", + "homepage": "http://scssphp.github.io/scssphp/", + "keywords": [ + "css", + "less", + "sass", + "scss", + "stylesheet" + ], + "support": { + "issues": "https://github.com/scssphp/scssphp/issues", + "source": "https://github.com/scssphp/scssphp/tree/v1.6.0" + }, + "time": "2021-07-02T16:28:10+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/d56bf6102915de5702778fe20f2de3b2fe570b5b", + "reference": "d56bf6102915de5702778fe20f2de3b2fe570b5b", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^8.0", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.13 || 1.0.0-alpha2", + "phpstan/phpstan": "^0.12", + "phpstan/phpstan-phpunit": "^0.12", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.4.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" + } + ], + "time": "2020-11-10T18:47:58+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.10.2", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/776f831124e9c62e1a2c601ecc52e776d8bb7220", + "reference": "776f831124e9c62e1a2c601ecc52e776d8bb7220", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "replace": { + "myclabs/deep-copy": "self.version" + }, + "require-dev": { + "doctrine/collections": "^1.0", + "doctrine/common": "^2.6", + "phpunit/phpunit": "^7.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + }, + "files": [ + "src/DeepCopy/deep_copy.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.10.2" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2020-11-13T09:40:50+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "reference": "85265efd3af7ba3ca4b2a2c34dbfc5788dd29133", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/master" + }, + "time": "2020-06-27T14:33:11+00:00" + }, + { + "name": "phar-io/version", + "version": "3.1.0", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "bae7c545bef187884426f042434e561ab1ddb182" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/bae7c545bef187884426f042434e561ab1ddb182", + "reference": "bae7c545bef187884426f042434e561ab1ddb182", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.1.0" + }, + "time": "2021-02-23T14:00:09+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", + "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" + }, + "time": "2020-06-27T09:03:43+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "5.2.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/069a785b2141f5bcf49f3e353548dc1cce6df556", + "reference": "069a785b2141f5bcf49f3e353548dc1cce6df556", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.2", + "phpdocumentor/type-resolver": "^1.3", + "webmozart/assert": "^1.9.1" + }, + "require-dev": { + "mockery/mockery": "~1.3.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + }, + { + "name": "Jaap van Otterdijk", + "email": "account@ijaap.nl" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "support": { + "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/master" + }, + "time": "2020-09-03T19:13:55+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "1.4.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "reference": "6a467b8989322d92aa1c8bf2bebcc6e5c2ba55c0", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "phpdocumentor/reflection-common": "^2.0" + }, + "require-dev": { + "ext-tokenizer": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-1.x": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", + "support": { + "issues": "https://github.com/phpDocumentor/TypeResolver/issues", + "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.4.0" + }, + "time": "2020-09-17T18:55:26+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "1.13.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/be1996ed8adc35c3fd795488a653f4b518be70ea", + "reference": "be1996ed8adc35c3fd795488a653f4b518be70ea", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.2", + "php": "^7.2 || ~8.0, <8.1", + "phpdocumentor/reflection-docblock": "^5.2", + "sebastian/comparator": "^3.0 || ^4.0", + "sebastian/recursion-context": "^3.0 || ^4.0" + }, + "require-dev": { + "phpspec/phpspec": "^6.0", + "phpunit/phpunit": "^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.11.x-dev" + } + }, + "autoload": { + "psr-4": { + "Prophecy\\": "src/Prophecy" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "support": { + "issues": "https://github.com/phpspec/prophecy/issues", + "source": "https://github.com/phpspec/prophecy/tree/1.13.0" + }, + "time": "2021-03-17T13:42:18+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "7.0.14", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "bb7c9a210c72e4709cdde67f8b7362f672f2225c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/bb7c9a210c72e4709cdde67f8b7362f672f2225c", + "reference": "bb7c9a210c72e4709cdde67f8b7362f672f2225c", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-xmlwriter": "*", + "php": ">=7.2", + "phpunit/php-file-iterator": "^2.0.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-token-stream": "^3.1.1 || ^4.0", + "sebastian/code-unit-reverse-lookup": "^1.0.1", + "sebastian/environment": "^4.2.2", + "sebastian/version": "^2.0.1", + "theseer/tokenizer": "^1.1.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.2.2" + }, + "suggest": { + "ext-xdebug": "^2.7.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/7.0.14" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-12-02T13:39:03+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/4b49fb70f067272b659ef0174ff9ca40fdaa6357", + "reference": "4b49fb70f067272b659ef0174ff9ca40fdaa6357", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:25:21+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1" + }, + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "2.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/2454ae1765516d20c4ffe103d85a58a9a3bd5662", + "reference": "2454ae1765516d20c4ffe103d85a58a9a3bd5662", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/2.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:20:02+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "reference": "a853a0e183b9db7eed023d7933a858fa1c8d25a3", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.3 || ^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-token-stream/issues", + "source": "https://github.com/sebastianbergmann/php-token-stream/tree/master" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "abandoned": true, + "time": "2020-08-04T08:28:15+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "8.5.17", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "79067856d85421c56d413bd238d4e2cd6b0e54da" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/79067856d85421c56d413bd238d4e2cd6b0e54da", + "reference": "79067856d85421c56d413bd238d4e2cd6b0e54da", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.3.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.0", + "phar-io/manifest": "^2.0.1", + "phar-io/version": "^3.0.2", + "php": ">=7.2", + "phpspec/prophecy": "^1.10.3", + "phpunit/php-code-coverage": "^7.0.12", + "phpunit/php-file-iterator": "^2.0.2", + "phpunit/php-text-template": "^1.2.1", + "phpunit/php-timer": "^2.1.2", + "sebastian/comparator": "^3.0.2", + "sebastian/diff": "^3.0.2", + "sebastian/environment": "^4.2.3", + "sebastian/exporter": "^3.1.2", + "sebastian/global-state": "^3.0.0", + "sebastian/object-enumerator": "^3.0.3", + "sebastian/resource-operations": "^2.0.1", + "sebastian/type": "^1.1.3", + "sebastian/version": "^2.0.1" + }, + "require-dev": { + "ext-pdo": "*" + }, + "suggest": { + "ext-soap": "*", + "ext-xdebug": "*", + "phpunit/php-invoker": "^2.0.0" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "8.5-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "source": "https://github.com/sebastianbergmann/phpunit/tree/8.5.17" + }, + "funding": [ + { + "url": "https://phpunit.de/donate.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-06-23T05:12:43+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "reference": "1de8cd5c010cb153fcd68b8d0f64606f523f7619", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:15:22+00:00" + }, + { + "name": "sebastian/comparator", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "1071dfcef776a57013124ff35e1fc41ccd294758" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/1071dfcef776a57013124ff35e1fc41ccd294758", + "reference": "1071dfcef776a57013124ff35e1fc41ccd294758", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "sebastian/diff": "^3.0", + "sebastian/exporter": "^3.1" + }, + "require-dev": { + "phpunit/phpunit": "^8.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T08:04:30+00:00" + }, + { + "name": "sebastian/diff", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/14f72dd46eaf2f2293cbe79c93cc0bc43161a211", + "reference": "14f72dd46eaf2f2293cbe79c93cc0bc43161a211", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5 || ^8.0", + "symfony/process": "^2 || ^3.3 || ^4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:59:04+00:00" + }, + { + "name": "sebastian/environment", + "version": "4.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", + "reference": "d47bbbad83711771f167c72d4e3f25f7fcc1f8b0", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "require-dev": { + "phpunit/phpunit": "^7.5" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/4.2.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:53:42+00:00" + }, + { + "name": "sebastian/exporter", + "version": "3.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/6b853149eab67d4da22291d36f5b0631c0fd856e", + "reference": "6b853149eab67d4da22291d36f5b0631c0fd856e", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/3.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:47:53+00:00" + }, + { + "name": "sebastian/global-state", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "474fb9edb7ab891665d3bfc6317f42a0a150454b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/474fb9edb7ab891665d3bfc6317f42a0a150454b", + "reference": "474fb9edb7ab891665d3bfc6317f42a0a150454b", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^8.0" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:43:24+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "3.0.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "reference": "e67f6d32ebd0c749cf9d1dbd9f226c727043cdf2", + "shasum": "" + }, + "require": { + "php": ">=7.0", + "sebastian/object-reflector": "^1.1.1", + "sebastian/recursion-context": "^3.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:40:27+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "reference": "9b8772b9cbd456ab45d4a598d2dd1a1bced6363d", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:37:18+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/367dcba38d6e1977be014dc4b22f47a484dac7fb", + "reference": "367dcba38d6e1977be014dc4b22f47a484dac7fb", + "shasum": "" + }, + "require": { + "php": ">=7.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:34:24+00:00" + }, + { + "name": "sebastian/resource-operations", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/31d35ca87926450c44eae7e2611d45a7a65ea8b3", + "reference": "31d35ca87926450c44eae7e2611d45a7a65ea8b3", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:30:19+00:00" + }, + { + "name": "sebastian/type", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/0150cfbc4495ed2df3872fb31b26781e4e077eb4", + "reference": "0150cfbc4495ed2df3872fb31b26781e4e077eb4", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/1.1.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-30T07:25:11+00:00" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/master" + }, + "time": "2016-10-03T07:35:21+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + "version": "2.9.2", + "source": { + "type": "git", + "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", + "reference": "2acf168de78487db620ab4bc524135a13cfe6745" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/2acf168de78487db620ab4bc524135a13cfe6745", + "reference": "2acf168de78487db620ab4bc524135a13cfe6745", + "shasum": "" + }, + "require": { + "ext-simplexml": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": ">=5.1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.0" + }, + "bin": [ + "scripts/phpcs", + "scripts/phpcbf" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "classmap": [ + "CodeSniffer.php", + "CodeSniffer/CLI.php", + "CodeSniffer/Exception.php", + "CodeSniffer/File.php", + "CodeSniffer/Fixer.php", + "CodeSniffer/Report.php", + "CodeSniffer/Reporting.php", + "CodeSniffer/Sniff.php", + "CodeSniffer/Tokens.php", + "CodeSniffer/Reports/", + "CodeSniffer/Tokenizers/", + "CodeSniffer/DocGenerators/", + "CodeSniffer/Standards/AbstractPatternSniff.php", + "CodeSniffer/Standards/AbstractScopeSniff.php", + "CodeSniffer/Standards/AbstractVariableSniff.php", + "CodeSniffer/Standards/IncorrectPatternException.php", + "CodeSniffer/Standards/Generic/Sniffs/", + "CodeSniffer/Standards/MySource/Sniffs/", + "CodeSniffer/Standards/PEAR/Sniffs/", + "CodeSniffer/Standards/PSR1/Sniffs/", + "CodeSniffer/Standards/PSR2/Sniffs/", + "CodeSniffer/Standards/Squiz/Sniffs/", + "CodeSniffer/Standards/Zend/Sniffs/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Greg Sherwood", + "role": "lead" + } + ], + "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", + "homepage": "http://www.squizlabs.com/php-codesniffer", + "keywords": [ + "phpcs", + "standards" + ], + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2018-11-07T22:31:41+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.23.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "reference": "46cd95797e9df938fdd2b03693b5fca5e64b01ce", + "shasum": "" + }, + "require": { + "php": ">=7.1" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.23-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2021-02-19T12:13:01+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "75a63c33a8577608444246075ea0af0d052e452a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/75a63c33a8577608444246075ea0af0d052e452a", + "reference": "75a63c33a8577608444246075ea0af0d052e452a", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/master" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2020-07-12T23:59:07+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.10.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/6964c76c7804814a842473e0c8fd15bab0f18e25", + "reference": "6964c76c7804814a842473e0c8fd15bab0f18e25", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.10.0" + }, + "time": "2021-03-09T10:59:23+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.1.0" +} diff --git a/rules/server/phpunit.xml.dist b/rules/server/phpunit.xml.dist new file mode 100644 index 0000000..81e4bc3 --- /dev/null +++ b/rules/server/phpunit.xml.dist @@ -0,0 +1,27 @@ + + + + + + + + tests + + + + + + src + + + + diff --git a/rules/server/src/Server.php b/rules/server/src/Server.php new file mode 100644 index 0000000..9f4bfb2 --- /dev/null +++ b/rules/server/src/Server.php @@ -0,0 +1,550 @@ + + */ +class Server +{ + /** + * @var boolean + */ + private $showErrorsAsCSS; + + /** + * @var string + */ + private $dir; + + /** + * @var string + */ + private $cacheDir; + + /** + * @var \ScssPhp\ScssPhp\Compiler + */ + private $scss; + + /** + * Join path components + * + * @param string $left Path component, left of the directory separator + * @param string $right Path component, right of the directory separator + * + * @return string + */ + protected function join($left, $right) + { + return rtrim($left, '/\\') . DIRECTORY_SEPARATOR . ltrim($right, '/\\'); + } + + /** + * Get name of requested .scss file + * + * @return string|null + */ + protected function inputName() + { + if (isset($_GET['p'])) { + return $_GET['p']; + } + + if (isset($_SERVER['PATH_INFO'])) { + return $_SERVER['PATH_INFO']; + } + + if (isset($_SERVER['DOCUMENT_URI'])) { + return substr($_SERVER['DOCUMENT_URI'], strlen($_SERVER['SCRIPT_NAME'])); + } + } + + /** + * Get path to requested .scss file + * + * @return string + */ + protected function findInput() + { + if (($input = $this->inputName()) + && strpos($input, '..') === false + && substr($input, -5) === '.scss' + ) { + $name = $this->join($this->dir, $input); + + if (is_file($name) && is_readable($name)) { + return $name; + } + } + + return false; + } + + /** + * Get path to cached .css file + * + * @param string $fname + * + * @return string + */ + protected function cacheName($fname) + { + return $this->join($this->cacheDir, md5($fname) . '.css'); + } + + /** + * Get path to meta data + * + * @param string $out + * + * @return string + */ + protected function metadataName($out) + { + return $out . '.meta'; + } + + /** + * Determine whether .scss file needs to be re-compiled. + * + * @param string $out Output path + * @param string $etag ETag + * + * @return boolean True if compile required. + */ + protected function needsCompile($out, &$etag) + { + if (!is_file($out)) { + return true; + } + + $mtime = filemtime($out); + + $metadataName = $this->metadataName($out); + + if (is_readable($metadataName)) { + $metadata = unserialize(file_get_contents($metadataName)); + + foreach ($metadata['imports'] as $import => $originalMtime) { + $currentMtime = filemtime($import); + + if ($currentMtime !== $originalMtime || $currentMtime > $mtime) { + return true; + } + } + + $metaVars = crc32(serialize($this->scss->getVariables())); + + if ($metaVars !== $metadata['vars']) { + return true; + } + + $etag = $metadata['etag']; + + return false; + } + + return true; + } + + /** + * Get If-Modified-Since header from client request + * + * @return string + */ + protected function getIfModifiedSinceHeader() + { + $modifiedSince = ''; + + if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { + $modifiedSince = $_SERVER['HTTP_IF_MODIFIED_SINCE']; + + if (false !== ($semicolonPos = strpos($modifiedSince, ';'))) { + $modifiedSince = substr($modifiedSince, 0, $semicolonPos); + } + } + + return $modifiedSince; + } + + /** + * Get If-None-Match header from client request + * + * @return string + */ + protected function getIfNoneMatchHeader() + { + $noneMatch = ''; + + if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) { + $noneMatch = $_SERVER['HTTP_IF_NONE_MATCH']; + } + + return $noneMatch; + } + + /** + * Compile .scss file + * + * @param string $in Input path (.scss) + * @param string $out Output path (.css) + * + * @return array + */ + protected function compile($in, $out) + { + $start = microtime(true); + $result = $this->scss->compileString(file_get_contents($in), $in); + + $css = $result->getCss(); + + $elapsed = round((microtime(true) - $start), 4); + + $v = Version::VERSION; + $t = gmdate('r'); + $css = "/* compiled by scssphp $v on $t (${elapsed}s) */\n\n" . $css; + $etag = md5($css); + + file_put_contents($out, $css); + file_put_contents( + $this->metadataName($out), + serialize([ + 'etag' => $etag, + 'imports' => $this->makeParsedFilesFromIncludeFiles(array_merge([$in], $result->getIncludedFiles())), + 'vars' => crc32(serialize($this->scss->getVariables())), + ]) + ); + + return [$css, $etag]; + } + + + /** + * Adds to list of parsed files + * + * @internal + * + * @param array|null $paths + * + * @return array + */ + protected function makeParsedFilesFromIncludeFiles($paths) + { + $parsedFiles = array(); + if (!\is_null($paths) && !empty($paths)) { + foreach ($paths as $path) { + if (!\is_null($path) && is_file($path)) { + $parsedFiles[realpath($path)] = filemtime($path); + } + } + } + return $parsedFiles; + } + + + /** + * Format error as a pseudo-element in CSS + * + * @param \Exception $error + * + * @return string + */ + protected function createErrorCSS(\Exception $error) + { + $message = str_replace( + ["'", "\n"], + ["\\'", "\\A"], + $error->getfile() . ":\n\n" . $error->getMessage() + ); + + return "body { display: none !important; } + html:after { + background: white; + color: black; + content: '$message'; + display: block !important; + font-family: mono; + padding: 1em; + white-space: pre; + }"; + } + + /** + * Render errors as a pseudo-element within valid CSS, displaying the errors on any + * page that includes this CSS. + * + * @param boolean $show + */ + public function showErrorsAsCSS($show = true) + { + $this->showErrorsAsCSS = $show; + } + + /** + * Compile .scss file + * + * @param string $in Input file (.scss) + * @param string $out Output file (.css) optional + * + * @return array|bool + * + * @throws \ScssPhp\Server\ServerException + */ + public function compileFile($in, $out = null) + { + if (!is_readable($in)) { + throw new ServerException('load error: failed to find ' . $in); + } + + $pi = pathinfo($in); + + $this->scss->addImportPath($pi['dirname'] . '/'); + + $result = $this->scss->compileString(file_get_contents($in), $in); + + $compiled = $result->getCss(); + + if (is_null($out)) { + return array('compiled' => $compiled, 'files' => $this->makeParsedFilesFromIncludeFiles(array_merge([$in], $result->getIncludedFiles())),); + } + + return file_put_contents($out, $compiled); + } + + /** + * Check if file need compiling + * + * @param string $in Input file (.scss) + * @param string $out Output file (.css) + * + * @return bool + */ + public function checkedCompile($in, $out) + { + if (!is_file($out) || filemtime($in) > filemtime($out)) { + $this->compileFile($in, $out); + + return true; + } + + return false; + } + + /** + * Compile requested scss and serve css. Outputs HTTP response. + * + * @param string $salt Prefix a string to the filename for creating the cache name hash + */ + public function serve($salt = '') + { + $protocol = isset($_SERVER['SERVER_PROTOCOL']) + ? $_SERVER['SERVER_PROTOCOL'] + : 'HTTP/1.0'; + + if ($input = $this->findInput()) { + $output = $this->cacheName($salt . $input); + $etag = $noneMatch = trim($this->getIfNoneMatchHeader(), '"'); + + if ($this->needsCompile($output, $etag)) { + try { + list($css, $etag) = $this->compile($input, $output); + + $lastModified = gmdate('r', filemtime($output)); + + header('Last-Modified: ' . $lastModified); + header('Content-type: text/css'); + header('ETag: "' . $etag . '"'); + + echo $css; + } catch (\Exception $e) { + if ($this->showErrorsAsCSS) { + header('Content-type: text/css'); + + echo $this->createErrorCSS($e); + } else { + header($protocol . ' 500 Internal Server Error'); + header('Content-type: text/plain'); + + echo 'Parse error: ' . $e->getMessage() . "\n"; + } + } + + return; + } + + header('X-SCSS-Cache: true'); + header('Content-type: text/css'); + header('ETag: "' . $etag . '"'); + + if ($etag === $noneMatch) { + header($protocol . ' 304 Not Modified'); + + return; + } + + $modifiedSince = $this->getIfModifiedSinceHeader(); + $mtime = filemtime($output); + + if (strtotime($modifiedSince) === $mtime) { + header($protocol . ' 304 Not Modified'); + + return; + } + + $lastModified = gmdate('r', $mtime); + header('Last-Modified: ' . $lastModified); + + echo file_get_contents($output); + + return; + } + + header($protocol . ' 404 Not Found'); + header('Content-type: text/plain'); + + $v = Version::VERSION; + echo "/* INPUT NOT FOUND scss $v */\n"; + } + + /** + * Based on explicit input/output files does a full change check on cache before compiling. + * + * @param string $in + * @param string $out + * @param boolean $force + * + * @return string Compiled CSS results + * + * @throws \ScssPhp\ScssPhp\Exception\ServerException + */ + public function checkedCachedCompile($in, $out, $force = false) + { + if (!is_file($in) || !is_readable($in)) { + throw new ServerException('Invalid or unreadable input file specified.'); + } + + if (is_dir($out) || !is_writable(file_exists($out) ? $out : dirname($out))) { + throw new ServerException('Invalid or unwritable output file specified.'); + } + + if ($force || $this->needsCompile($out, $etag)) { + list($css, $etag) = $this->compile($in, $out); + } else { + $css = file_get_contents($out); + } + + return $css; + } + + /** + * Execute scssphp on a .scss file or a scssphp cache structure + * + * The scssphp cache structure contains information about a specific + * scss file having been parsed. It can be used as a hint for future + * calls to determine whether or not a rebuild is required. + * + * The cache structure contains two important keys that may be used + * externally: + * + * compiled: The final compiled CSS + * updated: The time (in seconds) the CSS was last compiled + * + * The cache structure is a plain-ol' PHP associative array and can + * be serialized and unserialized without a hitch. + * + * @param mixed $in Input + * @param boolean $force Force rebuild? + * + * @return array scssphp cache structure + */ + public function cachedCompile($in, $force = false) + { + // assume no root + $root = null; + + if (is_string($in)) { + $root = $in; + } elseif (is_array($in) and isset($in['root'])) { + if ($force or !isset($in['files'])) { + // If we are forcing a recompile or if for some reason the + // structure does not contain any file information we should + // specify the root to trigger a rebuild. + $root = $in['root']; + } elseif (isset($in['files']) and is_array($in['files'])) { + foreach ($in['files'] as $fname => $ftime) { + if (!file_exists($fname) or filemtime($fname) > $ftime) { + // One of the files we knew about previously has changed + // so we should look at our incoming root again. + $root = $in['root']; + break; + } + } + } + } else { + // TODO: Throw an exception? We got neither a string nor something + // that looks like a compatible lessphp cache structure. + return null; + } + + if (is_null($root)) { + // No changes, pass back the structure + // we were given initially. + return $in; + } + + // If we have a root value which means we should rebuild. + $out = $this->compileFile($root); + $out['root'] = $root; + $out['updated'] = time(); + + return $out; + } + + /** + * Constructor + * + * @param string $dir Root directory to .scss files + * @param string $cacheDir Cache directory + * @param \ScssPhp\ScssPhp\Compiler|null $scss SCSS compiler instance + */ + public function __construct($dir, $cacheDir = null, $scss = null) + { + $this->dir = $dir; + + if (!isset($cacheDir)) { + $cacheDir = $this->join($dir, 'scss_cache'); + } + + $this->cacheDir = $cacheDir; + + if (!is_dir($this->cacheDir)) { + throw new ServerException('Cache directory doesn\'t exist: ' . $cacheDir); + } + + if (!isset($scss)) { + $scss = new Compiler(); + $scss->setImportPaths($this->dir); + } + + $this->scss = $scss; + $this->showErrorsAsCSS = false; + + date_default_timezone_set('UTC'); + } +} diff --git a/rules/server/src/ServerException.php b/rules/server/src/ServerException.php new file mode 100644 index 0000000..a586dd9 --- /dev/null +++ b/rules/server/src/ServerException.php @@ -0,0 +1,24 @@ + + */ +class ServerException extends \Exception implements SassException +{ +} diff --git a/rules/server/tests/ServerTest.php b/rules/server/tests/ServerTest.php new file mode 100644 index 0000000..f966417 --- /dev/null +++ b/rules/server/tests/ServerTest.php @@ -0,0 +1,40 @@ + + */ +class ServerTest extends TestCase +{ + public function testCheckedCachedCompile() + { + require_once __DIR__ . '/../src/Server.php'; + + if (! file_exists(__DIR__ . '/inputs/scss_cache')) { + mkdir(__DIR__ . '/inputs/scss_cache', 0755, true); + } + + $server = new Server(__DIR__ . '/inputs/'); + $css = $server->checkedCachedCompile(__DIR__ . '/inputs/import.scss', '/tmp/scss.css'); + + $this->assertFileExists('/tmp/scss.css'); + $this->assertFileExists('/tmp/scss.css.meta'); + $this->assertEquals($css, file_get_contents('/tmp/scss.css')); + $this->assertNotNull(unserialize(file_get_contents('/tmp/scss.css.meta'))); + } +} diff --git a/rules/server/tests/inputs/import.scss b/rules/server/tests/inputs/import.scss new file mode 100644 index 0000000..61625cd --- /dev/null +++ b/rules/server/tests/inputs/import.scss @@ -0,0 +1,23 @@ + +@import "foo.css"; +@import "foo" screen; +@import "http://foo.com/bar"; +@import url(foo); + +@import "imports/simple"; + +pre { + color: red; + @import "imports/simple.scss"; +} + +code { + @import "imports/simple", "imports/simple"; +} + +@import "imports/partial"; + +body { + color: $variable; + @include partial-mixin(); +} diff --git a/rules/server/tests/inputs/imports/_partial.scss b/rules/server/tests/inputs/imports/_partial.scss new file mode 100644 index 0000000..010c3c4 --- /dev/null +++ b/rules/server/tests/inputs/imports/_partial.scss @@ -0,0 +1,10 @@ + +#partial { + color: blue; +} + +$variable: #7C2; + +@mixin partial-mixin() { + background: gray; +} diff --git a/rules/server/tests/inputs/imports/simple.scss b/rules/server/tests/inputs/imports/simple.scss new file mode 100644 index 0000000..4b3e1f9 --- /dev/null +++ b/rules/server/tests/inputs/imports/simple.scss @@ -0,0 +1,4 @@ +div { + height: 200px; + color: red; +} From 9c3688ff26f99d9ca0a3aa2137be33bfbc991eb1 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:25:47 +0000 Subject: [PATCH 14/82] 2.2.0 use scss Server almost same as leafo Server --- rules/compiler.php | 18 +++++++----------- rules/server/server.inc.php | 22 ++++++++++++++++++++++ 2 files changed, 29 insertions(+), 11 deletions(-) create mode 100644 rules/server/server.inc.php diff --git a/rules/compiler.php b/rules/compiler.php index a02766d..da97c86 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -81,14 +81,10 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input if (htmlspecialchars($value) == '1') { /* creeren en compileren */ - -// scss compiler van leafo http://leafo.github.io/scssphp/ -// require_once "leafo/scss.inc.php"; -// require_once "leafo/src/Server.php"; -// scss compiler van scssphp https://scssphp.github.io/scssphp/ + // scss compiler and server by scssphp https://scssphp.github.io/scssphp/ require_once "scssphp/scss.inc.php"; - require_once "server/src/Server.php"; - require_once "server/src/ServerException.php"; + require_once "server/server.inc.php"; + $scss = new Compiler(); @@ -107,7 +103,7 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input // $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); } -//$server = new Server($currentpath. '/../scss', null, $scss); +$server = new Server($currentpath. '/../scss', null, $scss); //$server->serve(); @@ -513,14 +509,14 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input /* einde opslaam style parameters in style.scss bestanden */ /* scss files compileren naar .css */ -$scss->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/' . $wsaCssFilename); +$server->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/' . $wsaCssFilename); if ($home == 1 ) {/* niet kunnen vinden van templatestyleid bij root (lijkt inmiddels opgelost te zijn)*/ - $scss->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/template.min.' . '.css'); + $server->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/template.min.' . '.css'); /* ivm &tmpl=component */ - $scss->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/template' . '.css'); + $server->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/template' . '.css'); } /* einde les files compileren naar .css */ diff --git a/rules/server/server.inc.php b/rules/server/server.inc.php new file mode 100644 index 0000000..0185575 --- /dev/null +++ b/rules/server/server.inc.php @@ -0,0 +1,22 @@ + Date: Fri, 4 Oct 2024 10:29:34 +0000 Subject: [PATCH 15/82] 2.2.0 --- scss/_variables.scss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scss/_variables.scss b/scss/_variables.scss index 68b0de9..9f4733d 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -557,9 +557,9 @@ $popover-arrow-color: $popover-bg; //** Popover outer arrow width $popover-arrow-outer-width: ($popover-arrow-width + 1); //** Popover outer arrow color -$popover-arrow-outer-color: fadein($popover-border-color, 5%); +$popover-arrow-outer-color: fadein($popover-border-color, 0.05); //** Popover outer arrow fallback color -$popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 20%); +$popover-arrow-outer-fallback-color: darken($popover-fallback-border-color, 0.20); //== Labels From d5ee86778e42f2598d2dc66c6855811ec0298158 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Fri, 4 Oct 2024 10:47:58 +0000 Subject: [PATCH 16/82] 2.2.0 update scss compiler/server succeeded --- language/en-GB/en-GB.tpl_wsa_bootstrap.sys.ini | 4 ++-- language/nl-NL/nl-NL.tpl_wsa_bootstrap.sys.ini | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/language/en-GB/en-GB.tpl_wsa_bootstrap.sys.ini b/language/en-GB/en-GB.tpl_wsa_bootstrap.sys.ini index 9b0599f..2b83d58 100644 --- a/language/en-GB/en-GB.tpl_wsa_bootstrap.sys.ini +++ b/language/en-GB/en-GB.tpl_wsa_bootstrap.sys.ini @@ -1,8 +1,8 @@ ; Author A.H.C. Waasdorp -; Copyright (C) 2015-2022 A.H.C. Waasdorp. All rights reserved. +; Copyright (C) 2015-2024 A.H.C. Waasdorp. All rights reserved. ; license GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php ; Note : All ini files need to be saved as UTF-8 -TPL_WSA_BOOTSTRAP_DESCRIPTION="Basic Template with bootstrap Joomla 5(3 or 4)" +TPL_WSA_BOOTSTRAP_DESCRIPTION="Basic Template with bootstrap 5 or 4 Joomla 5 or 4" TPL_WSA_BOOTSTRAP_POSITION_POSITION-0="Search" TPL_WSA_BOOTSTRAP_POSITION_POSITION-1="Navigation" TPL_WSA_BOOTSTRAP_POSITION_POSITION-2="Top center left" diff --git a/language/nl-NL/nl-NL.tpl_wsa_bootstrap.sys.ini b/language/nl-NL/nl-NL.tpl_wsa_bootstrap.sys.ini index ce2796a..cec7af1 100644 --- a/language/nl-NL/nl-NL.tpl_wsa_bootstrap.sys.ini +++ b/language/nl-NL/nl-NL.tpl_wsa_bootstrap.sys.ini @@ -2,7 +2,7 @@ ; Copyright (C) 2015 A.H.C. Waasdorp. All rights reserved. ; license GNU General Public License version 2 or later; see LICENSE.txt, see LICENSE.php ; Note : All ini files need to be saved as UTF-8 -TPL_WSA_BOOTSTRAP_DESCRIPTION="Basis Template met bootstrap 5, 3 of 4 Joomla 3 of 4" +TPL_WSA_BOOTSTRAP_DESCRIPTION="Basis template met Bootstrap 5 of 4 Joomla 5 of 4" TPL_WSA_BOOTSTRAP_POSITION_POSITION-0="Zoek" TPL_WSA_BOOTSTRAP_POSITION_POSITION-1="Navigatie" TPL_WSA_BOOTSTRAP_POSITION_POSITION-2="Kop midden links" From 22f89b6eb11c18040eadf9ab35cc3ac7917aedcd Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:34:45 +0000 Subject: [PATCH 17/82] 2.2.0 using new versions BS5, BS4 instead of BS3 and BS4.2.1 --- rules/compiler.php | 54 +- scss/bs4/README.md | 210 +++ scss/bs4/_functions.scss | 190 +++ scss/bs4/_grid.scss | 73 + scss/bs4/_images.scss | 42 + scss/bs4/_mixins.scss | 47 + scss/bs4/_variables.scss | 1149 ++++++++++++++ scss/bs4/mixins/_alert.scss | 13 + scss/bs4/mixins/_background-variant.scss | 23 + scss/bs4/mixins/_badge.scss | 17 + scss/bs4/mixins/_border-radius.scss | 76 + scss/bs4/mixins/_box-shadow.scss | 20 + scss/bs4/mixins/_breakpoints.scss | 123 ++ scss/bs4/mixins/_buttons.scss | 110 ++ scss/bs4/mixins/_caret.scss | 62 + scss/bs4/mixins/_clearfix.scss | 7 + scss/bs4/mixins/_deprecate.scss | 10 + scss/bs4/mixins/_float.scss | 14 + scss/bs4/mixins/_forms.scss | 195 +++ scss/bs4/mixins/_gradients.scss | 45 + scss/bs4/mixins/_grid-framework.scss | 80 + scss/bs4/mixins/_grid.scss | 69 + scss/bs4/mixins/_hover.scss | 37 + scss/bs4/mixins/_image.scss | 36 + scss/bs4/mixins/_list-group.scss | 21 + scss/bs4/mixins/_lists.scss | 7 + scss/bs4/mixins/_nav-divider.scss | 11 + scss/bs4/mixins/_pagination.scss | 22 + scss/bs4/mixins/_reset-text.scss | 17 + scss/bs4/mixins/_resize.scss | 6 + scss/bs4/mixins/_screen-reader.scss | 34 + scss/bs4/mixins/_size.scss | 7 + scss/bs4/mixins/_table-row.scss | 39 + scss/bs4/mixins/_text-emphasis.scss | 17 + scss/bs4/mixins/_text-hide.scss | 11 + scss/bs4/mixins/_text-truncate.scss | 8 + scss/bs4/mixins/_transition.scss | 26 + scss/bs4/mixins/_visibility.scss | 8 + scss/bs4/utilities/_align.scss | 8 + scss/bs4/utilities/_background.scss | 19 + scss/bs4/utilities/_borders.scss | 75 + scss/bs4/utilities/_clearfix.scss | 3 + scss/bs4/utilities/_display.scss | 26 + scss/bs4/utilities/_embed.scss | 39 + scss/bs4/utilities/_flex.scss | 51 + scss/bs4/utilities/_float.scss | 11 + scss/bs4/utilities/_interactions.scss | 5 + scss/bs4/utilities/_overflow.scss | 5 + scss/bs4/utilities/_position.scss | 32 + scss/bs4/utilities/_screenreaders.scss | 11 + scss/bs4/utilities/_shadows.scss | 6 + scss/bs4/utilities/_sizing.scss | 20 + scss/bs4/utilities/_spacing.scss | 73 + scss/bs4/utilities/_stretched-link.scss | 19 + scss/bs4/utilities/_text.scss | 72 + scss/bs4/utilities/_visibility.scss | 13 + scss/bs5/README.md | 246 +++ scss/bs5/_functions.scss | 302 ++++ scss/bs5/_grid.scss | 39 + scss/bs5/_images.scss | 42 + scss/bs5/_mixins.scss | 42 + scss/bs5/_variables-dark.scss | 87 ++ scss/bs5/_variables.scss | 1751 ++++++++++++++++++++++ scss/bs5/mixins/_alert.scss | 18 + scss/bs5/mixins/_backdrop.scss | 14 + scss/bs5/mixins/_banner.scss | 7 + scss/bs5/mixins/_border-radius.scss | 78 + scss/bs5/mixins/_box-shadow.scss | 18 + scss/bs5/mixins/_breakpoints.scss | 127 ++ scss/bs5/mixins/_buttons.scss | 70 + scss/bs5/mixins/_caret.scss | 69 + scss/bs5/mixins/_clearfix.scss | 9 + scss/bs5/mixins/_color-mode.scss | 21 + scss/bs5/mixins/_color-scheme.scss | 7 + scss/bs5/mixins/_container.scss | 11 + scss/bs5/mixins/_deprecate.scss | 10 + scss/bs5/mixins/_forms.scss | 163 ++ scss/bs5/mixins/_gradients.scss | 47 + scss/bs5/mixins/_grid.scss | 151 ++ scss/bs5/mixins/_image.scss | 16 + scss/bs5/mixins/_list-group.scss | 26 + scss/bs5/mixins/_lists.scss | 7 + scss/bs5/mixins/_pagination.scss | 10 + scss/bs5/mixins/_reset-text.scss | 17 + scss/bs5/mixins/_resize.scss | 6 + scss/bs5/mixins/_table-variants.scss | 24 + scss/bs5/mixins/_text-truncate.scss | 8 + scss/bs5/mixins/_transition.scss | 26 + scss/bs5/mixins/_utilities.scss | 97 ++ scss/bs5/mixins/_visually-hidden.scss | 33 + scss/bs5/utilities/_api.scss | 47 + 91 files changed, 7037 insertions(+), 33 deletions(-) create mode 100644 scss/bs4/README.md create mode 100644 scss/bs4/_functions.scss create mode 100644 scss/bs4/_grid.scss create mode 100644 scss/bs4/_images.scss create mode 100644 scss/bs4/_mixins.scss create mode 100644 scss/bs4/_variables.scss create mode 100644 scss/bs4/mixins/_alert.scss create mode 100644 scss/bs4/mixins/_background-variant.scss create mode 100644 scss/bs4/mixins/_badge.scss create mode 100644 scss/bs4/mixins/_border-radius.scss create mode 100644 scss/bs4/mixins/_box-shadow.scss create mode 100644 scss/bs4/mixins/_breakpoints.scss create mode 100644 scss/bs4/mixins/_buttons.scss create mode 100644 scss/bs4/mixins/_caret.scss create mode 100644 scss/bs4/mixins/_clearfix.scss create mode 100644 scss/bs4/mixins/_deprecate.scss create mode 100644 scss/bs4/mixins/_float.scss create mode 100644 scss/bs4/mixins/_forms.scss create mode 100644 scss/bs4/mixins/_gradients.scss create mode 100644 scss/bs4/mixins/_grid-framework.scss create mode 100644 scss/bs4/mixins/_grid.scss create mode 100644 scss/bs4/mixins/_hover.scss create mode 100644 scss/bs4/mixins/_image.scss create mode 100644 scss/bs4/mixins/_list-group.scss create mode 100644 scss/bs4/mixins/_lists.scss create mode 100644 scss/bs4/mixins/_nav-divider.scss create mode 100644 scss/bs4/mixins/_pagination.scss create mode 100644 scss/bs4/mixins/_reset-text.scss create mode 100644 scss/bs4/mixins/_resize.scss create mode 100644 scss/bs4/mixins/_screen-reader.scss create mode 100644 scss/bs4/mixins/_size.scss create mode 100644 scss/bs4/mixins/_table-row.scss create mode 100644 scss/bs4/mixins/_text-emphasis.scss create mode 100644 scss/bs4/mixins/_text-hide.scss create mode 100644 scss/bs4/mixins/_text-truncate.scss create mode 100644 scss/bs4/mixins/_transition.scss create mode 100644 scss/bs4/mixins/_visibility.scss create mode 100644 scss/bs4/utilities/_align.scss create mode 100644 scss/bs4/utilities/_background.scss create mode 100644 scss/bs4/utilities/_borders.scss create mode 100644 scss/bs4/utilities/_clearfix.scss create mode 100644 scss/bs4/utilities/_display.scss create mode 100644 scss/bs4/utilities/_embed.scss create mode 100644 scss/bs4/utilities/_flex.scss create mode 100644 scss/bs4/utilities/_float.scss create mode 100644 scss/bs4/utilities/_interactions.scss create mode 100644 scss/bs4/utilities/_overflow.scss create mode 100644 scss/bs4/utilities/_position.scss create mode 100644 scss/bs4/utilities/_screenreaders.scss create mode 100644 scss/bs4/utilities/_shadows.scss create mode 100644 scss/bs4/utilities/_sizing.scss create mode 100644 scss/bs4/utilities/_spacing.scss create mode 100644 scss/bs4/utilities/_stretched-link.scss create mode 100644 scss/bs4/utilities/_text.scss create mode 100644 scss/bs4/utilities/_visibility.scss create mode 100644 scss/bs5/README.md create mode 100644 scss/bs5/_functions.scss create mode 100644 scss/bs5/_grid.scss create mode 100644 scss/bs5/_images.scss create mode 100644 scss/bs5/_mixins.scss create mode 100644 scss/bs5/_variables-dark.scss create mode 100644 scss/bs5/_variables.scss create mode 100644 scss/bs5/mixins/_alert.scss create mode 100644 scss/bs5/mixins/_backdrop.scss create mode 100644 scss/bs5/mixins/_banner.scss create mode 100644 scss/bs5/mixins/_border-radius.scss create mode 100644 scss/bs5/mixins/_box-shadow.scss create mode 100644 scss/bs5/mixins/_breakpoints.scss create mode 100644 scss/bs5/mixins/_buttons.scss create mode 100644 scss/bs5/mixins/_caret.scss create mode 100644 scss/bs5/mixins/_clearfix.scss create mode 100644 scss/bs5/mixins/_color-mode.scss create mode 100644 scss/bs5/mixins/_color-scheme.scss create mode 100644 scss/bs5/mixins/_container.scss create mode 100644 scss/bs5/mixins/_deprecate.scss create mode 100644 scss/bs5/mixins/_forms.scss create mode 100644 scss/bs5/mixins/_gradients.scss create mode 100644 scss/bs5/mixins/_grid.scss create mode 100644 scss/bs5/mixins/_image.scss create mode 100644 scss/bs5/mixins/_list-group.scss create mode 100644 scss/bs5/mixins/_lists.scss create mode 100644 scss/bs5/mixins/_pagination.scss create mode 100644 scss/bs5/mixins/_reset-text.scss create mode 100644 scss/bs5/mixins/_resize.scss create mode 100644 scss/bs5/mixins/_table-variants.scss create mode 100644 scss/bs5/mixins/_text-truncate.scss create mode 100644 scss/bs5/mixins/_transition.scss create mode 100644 scss/bs5/mixins/_utilities.scss create mode 100644 scss/bs5/mixins/_visually-hidden.scss create mode 100644 scss/bs5/utilities/_api.scss diff --git a/rules/compiler.php b/rules/compiler.php index da97c86..dc9818a 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -77,44 +77,32 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input $home = $input->get('home'); $params = $input->get('params'); // stdobject params are properties. - if (htmlspecialchars($value) == '1') { /* creeren en compileren */ // scss compiler and server by scssphp https://scssphp.github.io/scssphp/ require_once "scssphp/scss.inc.php"; require_once "server/server.inc.php"; - - $scss = new Compiler(); if ( htmlspecialchars($params->compress) == "1") { -// $scss->setFormatter('Leafo\ScssPhp\Formatter\Crunched'); $scss->setOutputStyle (\ScssPhp\ScssPhp\OutputStyle::COMPRESSED); -// $scss->setOutputStyle ('compressed'); } else { // voor debug netter formatteren en commentaren behouden. -// $scss->setFormatter('Leafo\ScssPhp\Formatter\Expanded'); $scss->setOutputStyle (\ScssPhp\ScssPhp\OutputStyle::EXPANDED); -// $scss->setOutputStyle ('expanded'); - // $scss->setLineNumberStyle(Compiler::LINE_COMMENTS); $scss->setSourceMap(Compiler::SOURCE_MAP_INLINE); } $server = new Server($currentpath. '/../scss', null, $scss); -//$server->serve(); - - // einde initialisatie compiler - // get params $gplusProfile = htmlspecialchars($params->gplusProfile); -$twbs_version = htmlspecialchars($params->twbs_version); +$twbs_version = htmlspecialchars($params->get(twbs_version, '5')); $itemVideoHeight= htmlspecialchars($params->itemVideoHeight); @@ -340,8 +328,8 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input }; /* overgenomen uit asha-s werkt mogelijk (nog) niet */ -if ($showTitle > ' ' ) fwrite($tv_file, '$showTitle: ' . $showTitle . ";\n"); -if ($tagItemTitleDisplay > ' ' ) fwrite($tv_file, '$tagItemTitleDisplay: ' . $tagItemTitleDisplay . ";\n"); +if (! empty($showTitle)) fwrite($tv_file, '$showTitle: ' . $showTitle . ";\n"); +if (! empty($tagItemTitleDisplay)) fwrite($tv_file, '$tagItemTitleDisplay: ' . $tagItemTitleDisplay . ";\n"); if ($marginLeftRight > ' ' ) { fwrite($tv_file, '$asMarginStd: ' . $marginLeftRight . "%;\n"); fwrite($tv_file, '$marginArea: ' . ($marginLeftRight / 2) . "%;\n"); @@ -365,24 +353,25 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input fwrite($st_file, "// css " . $wsaCssFilename . "\n//\n"); // standaard bootstrap variables mixins etc. -fwrite($st_file, "//\n// standard bootstrap includes v" . $twbs_version . "\n//\n"); -if($twbs_version == '3') { -fwrite($st_file, '@import "variables.scss";' . "\n"); -fwrite($st_file, '@import "mixins/reset-filter.scss";' . "\n"); -fwrite($st_file, '@import "mixins/vendor-prefixes.scss";' . "\n"); -fwrite($st_file, '@import "mixins/gradients.scss";' . "\n"); -fwrite($st_file, '@import "mixins/grid.scss";' . "\n"); -} else { /* verion 4 */ -fwrite($st_file, '@import "variables.scss";' . " // nog even uit 3\n"); // nog even uit 3 -fwrite($st_file, '@import "mixins/reset-filter.scss";' . " // nog even uit 3\n"); // nog even uit 3 -fwrite($st_file, '@import "mixins/gradients.scss";' . " // nog even uit 3\n"); // nog even uit 3 + fwrite($st_file, "//\n// standard bootstrap includes v" . $twbs_version . "\n//\n"); +// if($twbs_version == '3') { +// fwrite($st_file, '@import "variables.scss";' . "\n"); +// fwrite($st_file, '@import "mixins/reset-filter.scss";' . "\n"); +// fwrite($st_file, '@import "mixins/vendor-prefixes.scss";' . "\n"); +// fwrite($st_file, '@import "mixins/gradients.scss";' . "\n"); +// fwrite($st_file, '@import "mixins/grid.scss";' . "\n"); +// } else +// { /* verion 4 + */ +// fwrite($st_file, '@import bs"' . $twbs_version . 'variables.scss";' . "\n"); +//fwrite($st_file, '@import "mixins/reset-filter.scss";' . " // nog even uit 3\n"); // nog even uit 3 +//fwrite($st_file, '@import "mixins/gradients.scss";' . " // nog even uit 3\n"); // nog even uit 3 // Custom.scss // Option B: Include parts of Bootstrap // Required -fwrite($st_file, '@import "node_modules/bootstrap/scss/functions";' . "\n"); -fwrite($st_file, '@import "node_modules/bootstrap/scss/variables";' . "\n"); -fwrite($st_file, '@import "node_modules/bootstrap/scss/mixins";' . "\n"); +fwrite($st_file, '@import bs"' . $twbs_version . 'functions";' . "\n"); +fwrite($st_file, '@import bs"' . $twbs_version . 'variables";' . "\n"); +fwrite($st_file, '@import bs"' . $twbs_version . 'mixins";' . "\n"); // Optional fwrite($st_file, "//\n// optional bootstrap includes and override v" . $twbs_version . "\n//\n"); @@ -457,9 +446,9 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input //fwrite($st_file, '@import "node_modules/bootstrap/scss/type";' . "\n"); //fwrite($st_file, '@import "node_modules/bootstrap/scss/images";' . "\n"); //fwrite($st_file, '@import "node_modules/bootstrap/scss/code";' . "\n"); -fwrite($st_file, '@import "node_modules/bootstrap/scss/grid";' . "\n"); -} +fwrite($st_file, '@import bs"' . $twbs_version . '/grid";' . "\n"); } + // standaard bootstrap variables mixins etc. einde //fwrite($st_file, '@import "system.scss";' . "\n"); //fwrite($st_file, '@import "general.scss";' . "\n"); @@ -470,7 +459,7 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input //fwrite($st_file, '@import "joomla_update_icons.scss";' . "\n"); fwrite($st_file, "//\n// css\n//\n"); -if ($background > ' ' ) +if (! empty($background)) { $pos1 = stripos($background, ".css"); if ($pos1 > 0) { @@ -511,7 +500,6 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input $server->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/' . $wsaCssFilename); - if ($home == 1 ) {/* niet kunnen vinden van templatestyleid bij root (lijkt inmiddels opgelost te zijn)*/ $server->compileFile($currentpath. '/../scss/style' . $templatestyleid . '.scss', $currentpath.'/../css/template.min.' . '.css'); diff --git a/scss/bs4/README.md b/scss/bs4/README.md new file mode 100644 index 0000000..d7b707f --- /dev/null +++ b/scss/bs4/README.md @@ -0,0 +1,210 @@ +

+ + Bootstrap logo + +

+ +

Bootstrap

+ +

+ Sleek, intuitive, and powerful front-end framework for faster and easier web development. +
+ Explore Bootstrap docs » +
+
+ Report bug + · + Request feature + · + Themes + · + Blog +

+ + +## Table of contents + +- [Quick start](#quick-start) +- [Status](#status) +- [What's included](#whats-included) +- [Bugs and feature requests](#bugs-and-feature-requests) +- [Documentation](#documentation) +- [Contributing](#contributing) +- [Community](#community) +- [Versioning](#versioning) +- [Creators](#creators) +- [Thanks](#thanks) +- [Copyright and license](#copyright-and-license) + + +## Quick start + +Several quick start options are available: + +- [Download the latest release.](https://github.com/twbs/bootstrap/archive/v4.6.2.zip) +- Clone the repo: `git clone https://github.com/twbs/bootstrap.git` +- Install with [npm](https://www.npmjs.com/): `npm install bootstrap` +- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@4.6.2` +- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:4.6.2` +- Install with [NuGet](https://www.nuget.org/): CSS: `Install-Package bootstrap` Sass: `Install-Package bootstrap.sass` + +Read the [Getting started page](https://getbootstrap.com/docs/4.6/getting-started/introduction/) for information on the framework contents, templates and examples, and more. + + +## Status + +[![Slack](https://bootstrap-slack.herokuapp.com/badge.svg)](https://bootstrap-slack.herokuapp.com/) +[![Build Status](https://img.shields.io/github/workflow/status/twbs/bootstrap/JS%20Tests/v4-dev?label=JS%20Tests&logo=github)](https://github.com/twbs/bootstrap/actions?query=workflow%3AJS+Tests+branch%3Av4-dev) +[![npm version](https://img.shields.io/npm/v/bootstrap)](https://www.npmjs.com/package/bootstrap) +[![Gem version](https://img.shields.io/gem/v/bootstrap)](https://rubygems.org/gems/bootstrap) +[![Meteor Atmosphere](https://img.shields.io/badge/meteor-twbs%3Abootstrap-blue)](https://atmospherejs.com/twbs/bootstrap) +[![Packagist Prerelease](https://img.shields.io/packagist/vpre/twbs/bootstrap)](https://packagist.org/packages/twbs/bootstrap) +[![NuGet](https://img.shields.io/nuget/vpre/bootstrap)](https://www.nuget.org/packages/bootstrap/absoluteLatest) +[![Coverage Status](https://img.shields.io/coveralls/github/twbs/bootstrap/v4-dev)](https://coveralls.io/github/twbs/bootstrap?branch=v4-dev) +[![CSS gzip size](https://img.badgesize.io/twbs/bootstrap/v4-dev/dist/css/bootstrap.min.css?compression=gzip&label=CSS%20gzip%20size)](https://github.com/twbs/bootstrap/blob/v4-dev/dist/css/bootstrap.min.css) +[![JS gzip size](https://img.badgesize.io/twbs/bootstrap/v4-dev/dist/js/bootstrap.min.js?compression=gzip&label=JS%20gzip%20size)](https://github.com/twbs/bootstrap/blob/v4-dev/dist/js/bootstrap.min.js) +[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=SkxZcStBeExEdVJqQ2hWYnlWckpkNmNEY213SFp6WHFETWk2bGFuY3pCbz0tLXhqbHJsVlZhQnRBdEpod3NLSDMzaHc9PQ==--3d0b75245708616eb93113221beece33e680b229)](https://www.browserstack.com/automate/public-build/SkxZcStBeExEdVJqQ2hWYnlWckpkNmNEY213SFp6WHFETWk2bGFuY3pCbz0tLXhqbHJsVlZhQnRBdEpod3NLSDMzaHc9PQ==--3d0b75245708616eb93113221beece33e680b229) +[![Backers on Open Collective](https://img.shields.io/opencollective/backers/bootstrap)](#backers) +[![Sponsors on Open Collective](https://img.shields.io/opencollective/sponsors/bootstrap)](#sponsors) + + +## What's included + +Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. + +
Download contents + +```text +bootstrap/ +└── dist/ + ├── css/ + │ ├── bootstrap-grid.css + │ ├── bootstrap-grid.css.map + │ ├── bootstrap-grid.min.css + │ ├── bootstrap-grid.min.css.map + │ ├── bootstrap-reboot.css + │ ├── bootstrap-reboot.css.map + │ ├── bootstrap-reboot.min.css + │ ├── bootstrap-reboot.min.css.map + │ ├── bootstrap.css + │ ├── bootstrap.css.map + │ ├── bootstrap.min.css + │ └── bootstrap.min.css.map + └── js/ + ├── bootstrap.bundle.js + ├── bootstrap.bundle.js.map + ├── bootstrap.bundle.min.js + ├── bootstrap.bundle.min.js.map + ├── bootstrap.js + ├── bootstrap.js.map + ├── bootstrap.min.js + └── bootstrap.min.js.map +``` +
+ +We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). [Source maps](https://developers.google.com/web/tools/chrome-devtools/javascript/source-maps) (`bootstrap.*.map`) are available for use with certain browsers' developer tools. Bundled JS files (`bootstrap.bundle.js` and minified `bootstrap.bundle.min.js`) include [Popper](https://popper.js.org/), but not [jQuery](https://jquery.com/). + + +## Bugs and feature requests + +Have a bug or a feature request? Please first read the [issue guidelines](https://github.com/twbs/bootstrap/blob/v4-dev/.github/CONTRIBUTING.md#using-the-issue-tracker) and search for existing and closed issues. If your problem or idea is not addressed yet, [please open a new issue](https://github.com/twbs/bootstrap/issues/new). + + +## Documentation + +Bootstrap's documentation, included in this repo in the root directory, is built with [Hugo](https://gohugo.io/) and publicly hosted on GitHub Pages at . The docs may also be run locally. + +Documentation search is powered by [Algolia's DocSearch](https://community.algolia.com/docsearch/). Working on our search? Be sure to set `debug: true` in `site/assets/js/search.js`. + +### Running documentation locally + +1. Run `npm install` to install the Node.js dependencies, including Hugo (the site builder). +2. Run `npm run test` (or a specific npm script) to rebuild distributed CSS and JavaScript files, as well as our docs assets. +3. Run `npm start` to compile CSS and JavaScript files, generate our docs, and watch for changes. +4. Open `http://localhost:9001/` in your browser, and voilà. + +Learn more about using Hugo by reading its [documentation](https://gohugo.io/documentation/). + +### Documentation for previous releases + +You can find all our previous releases docs on . + +[Previous releases](https://github.com/twbs/bootstrap/releases) and their documentation are also available for download. + + +## Contributing + +Please read through our [contributing guidelines](https://github.com/twbs/bootstrap/blob/v4-dev/.github/CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development. + +Moreover, if your pull request contains JavaScript patches or features, you must include [relevant unit tests](https://github.com/twbs/bootstrap/tree/v4-dev/js/tests). All HTML and CSS should conform to the [Code Guide](https://github.com/mdo/code-guide), maintained by [Mark Otto](https://github.com/mdo). + +Editor preferences are available in the [editor config](https://github.com/twbs/bootstrap/blob/v4-dev/.editorconfig) for easy use in common text editors. Read more and download plugins at . + + +## Community + +Get updates on Bootstrap's development and chat with the project maintainers and community members. + +- Follow [@getbootstrap on Twitter](https://twitter.com/getbootstrap). +- Read and subscribe to [The Official Bootstrap Blog](https://blog.getbootstrap.com/). +- Join [the official Slack room](https://bootstrap-slack.herokuapp.com/). +- Chat with fellow Bootstrappers in IRC. On the `irc.libera.chat` server, in the `#bootstrap` channel. +- Implementation help may be found at Stack Overflow (tagged [`bootstrap-4`](https://stackoverflow.com/questions/tagged/bootstrap-4)). +- Developers should use the keyword `bootstrap` on packages which modify or add to the functionality of Bootstrap when distributing through [npm](https://www.npmjs.com/browse/keyword/bootstrap) or similar delivery mechanisms for maximum discoverability. + + +## Versioning + +For transparency into our release cycle and in striving to maintain backward compatibility, Bootstrap is maintained under [the Semantic Versioning guidelines](https://semver.org/). Sometimes we screw up, but we adhere to those rules whenever possible. + +See [the Releases section of our GitHub project](https://github.com/twbs/bootstrap/releases) for changelogs for each release version of Bootstrap. Release announcement posts on [the official Bootstrap blog](https://blog.getbootstrap.com/) contain summaries of the most noteworthy changes made in each release. + + +## Creators + +**Mark Otto** + +- +- + +**Jacob Thornton** + +- +- + + +## Thanks + + + BrowserStack Logo + + +Thanks to [BrowserStack](https://www.browserstack.com/) for providing the infrastructure that allows us to test in real browsers! + + +## Sponsors + +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/bootstrap#sponsor)] + +[![](https://opencollective.com/bootstrap/sponsor/0/avatar.svg)](https://opencollective.com/bootstrap/sponsor/0/website) +[![](https://opencollective.com/bootstrap/sponsor/1/avatar.svg)](https://opencollective.com/bootstrap/sponsor/1/website) +[![](https://opencollective.com/bootstrap/sponsor/2/avatar.svg)](https://opencollective.com/bootstrap/sponsor/2/website) +[![](https://opencollective.com/bootstrap/sponsor/3/avatar.svg)](https://opencollective.com/bootstrap/sponsor/3/website) +[![](https://opencollective.com/bootstrap/sponsor/4/avatar.svg)](https://opencollective.com/bootstrap/sponsor/4/website) +[![](https://opencollective.com/bootstrap/sponsor/5/avatar.svg)](https://opencollective.com/bootstrap/sponsor/5/website) +[![](https://opencollective.com/bootstrap/sponsor/6/avatar.svg)](https://opencollective.com/bootstrap/sponsor/6/website) +[![](https://opencollective.com/bootstrap/sponsor/7/avatar.svg)](https://opencollective.com/bootstrap/sponsor/7/website) +[![](https://opencollective.com/bootstrap/sponsor/8/avatar.svg)](https://opencollective.com/bootstrap/sponsor/8/website) +[![](https://opencollective.com/bootstrap/sponsor/9/avatar.svg)](https://opencollective.com/bootstrap/sponsor/9/website) + + +## Backers + +Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/bootstrap#backer)] + +[![Backers](https://opencollective.com/bootstrap/backers.svg?width=890)](https://opencollective.com/bootstrap#backers) + + +## Copyright and license + +Code and documentation copyright 2011-2022 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors) and [Twitter, Inc.](https://twitter.com) Code released under the [MIT License](https://github.com/twbs/bootstrap/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). diff --git a/scss/bs4/_functions.scss b/scss/bs4/_functions.scss new file mode 100644 index 0000000..13d9de0 --- /dev/null +++ b/scss/bs4/_functions.scss @@ -0,0 +1,190 @@ +// Bootstrap functions +// +// Utility mixins and functions for evaluating source code across our variables, maps, and mixins. + +// Ascending +// Used to evaluate Sass maps like our grid breakpoints. +@mixin _assert-ascending($map, $map-name) { + $prev-key: null; + $prev-num: null; + @each $key, $num in $map { + @if $prev-num == null or unit($num) == "%" or unit($prev-num) == "%" { + // Do nothing + } @else if not comparable($prev-num, $num) { + @warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !"; + } @else if $prev-num >= $num { + @warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !"; + } + $prev-key: $key; + $prev-num: $num; + } +} + +// Starts at zero +// Used to ensure the min-width of the lowest breakpoint starts at 0. +@mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") { + @if length($map) > 0 { + $values: map-values($map); + $first-value: nth($values, 1); + @if $first-value != 0 { + @warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}."; + } + } +} + +// Replace `$search` with `$replace` in `$string` +// Used on our SVG icon backgrounds for custom forms. +// +// @author Hugo Giraudel +// @param {String} $string - Initial string +// @param {String} $search - Substring to replace +// @param {String} $replace ('') - New value +// @return {String} - Updated string +@function str-replace($string, $search, $replace: "") { + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); + } + + @return $string; +} + +// See https://codepen.io/kevinweber/pen/dXWoRw +// +// Requires the use of quotes around data URIs. + +@function escape-svg($string) { + @if str-index($string, "data:image/svg+xml") { + @each $char, $encoded in $escaped-characters { + // Do not escape the url brackets + @if str-index($string, "url(") == 1 { + $string: url("#{str-replace(str-slice($string, 6, -3), $char, $encoded)}"); + } @else { + $string: str-replace($string, $char, $encoded); + } + } + } + + @return $string; +} + +// Color contrast +@function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) { + $r: red($color); + $g: green($color); + $b: blue($color); + + $yiq: (($r * 299) + ($g * 587) + ($b * 114)) * .001; + + @if ($yiq >= $yiq-contrasted-threshold) { + @return $dark; + } @else { + @return $light; + } +} + +// Retrieve color Sass maps +@function color($key: "blue") { + @return map-get($colors, $key); +} + +@function theme-color($key: "primary") { + @return map-get($theme-colors, $key); +} + +@function gray($key: "100") { + @return map-get($grays, $key); +} + +// Request a theme color level +@function theme-color-level($color-name: "primary", $level: 0) { + $color: theme-color($color-name); + $color-base: if($level > 0, $black, $white); + $level: abs($level); + + @return mix($color-base, $color, $level * $theme-color-interval); +} + +// Return valid calc +@function add($value1, $value2, $return-calc: true) { + @if $value1 == null { + @return $value2; + } + + @if $value2 == null { + @return $value1; + } + + @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { + @return $value1 + $value2; + } + + @return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2); +} + +@function subtract($value1, $value2, $return-calc: true) { + @if $value1 == null and $value2 == null { + @return null; + } + + @if $value1 == null { + @return -$value2; + } + + @if $value2 == null { + @return $value1; + } + + @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { + @return $value1 - $value2; + } + + @if type-of($value2) != number { + $value2: unquote("(") + $value2 + unquote(")"); + } + + @return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2); +} + +@function divide($dividend, $divisor, $precision: 10) { + $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1); + $dividend: abs($dividend); + $divisor: abs($divisor); + @if $dividend == 0 { + @return 0; + } + @if $divisor == 0 { + @error "Cannot divide by 0"; + } + $remainder: $dividend; + $result: 0; + $factor: 10; + @while ($remainder > 0 and $precision >= 0) { + $quotient: 0; + @while ($remainder >= $divisor) { + $remainder: $remainder - $divisor; + $quotient: $quotient + 1; + } + $result: $result * 10 + $quotient; + $factor: $factor * .1; + $remainder: $remainder * 10; + $precision: $precision - 1; + @if ($precision < 0 and $remainder >= $divisor * 5) { + $result: $result + 1; + } + } + $result: $result * $factor * $sign; + $dividend-unit: unit($dividend); + $divisor-unit: unit($divisor); + $unit-map: ( + "px": 1px, + "rem": 1rem, + "em": 1em, + "%": 1% + ); + @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) { + $result: $result * map-get($unit-map, $dividend-unit); + } + @return $result; +} diff --git a/scss/bs4/_grid.scss b/scss/bs4/_grid.scss new file mode 100644 index 0000000..0bfe530 --- /dev/null +++ b/scss/bs4/_grid.scss @@ -0,0 +1,73 @@ +// Container widths +// +// Set the container width, and override it for fixed navbars in media queries. + +@if $enable-grid-classes { + // Single container class with breakpoint max-widths + .container, + // 100% wide container at all breakpoints + .container-fluid { + @include make-container(); + } + + // Responsive containers that are 100% wide until a breakpoint + @each $breakpoint, $container-max-width in $container-max-widths { + .container-#{$breakpoint} { + @extend .container-fluid; + } + + @include media-breakpoint-up($breakpoint, $grid-breakpoints) { + %responsive-container-#{$breakpoint} { + max-width: $container-max-width; + } + + // Extend each breakpoint which is smaller or equal to the current breakpoint + $extend-breakpoint: true; + + @each $name, $width in $grid-breakpoints { + @if ($extend-breakpoint) { + .container#{breakpoint-infix($name, $grid-breakpoints)} { + @extend %responsive-container-#{$breakpoint}; + } + + // Once the current breakpoint is reached, stop extending + @if ($breakpoint == $name) { + $extend-breakpoint: false; + } + } + } + } + } +} + + +// Row +// +// Rows contain your columns. + +@if $enable-grid-classes { + .row { + @include make-row(); + } + + // Remove the negative margin from default .row, then the horizontal padding + // from all immediate children columns (to prevent runaway style inheritance). + .no-gutters { + margin-right: 0; + margin-left: 0; + + > .col, + > [class*="col-"] { + padding-right: 0; + padding-left: 0; + } + } +} + +// Columns +// +// Common styles for small and large grid columns + +@if $enable-grid-classes { + @include make-grid-columns(); +} diff --git a/scss/bs4/_images.scss b/scss/bs4/_images.scss new file mode 100644 index 0000000..3d6a101 --- /dev/null +++ b/scss/bs4/_images.scss @@ -0,0 +1,42 @@ +// Responsive images (ensure images don't scale beyond their parents) +// +// This is purposefully opt-in via an explicit class rather than being the default for all ``s. +// We previously tried the "images are responsive by default" approach in Bootstrap v2, +// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps) +// which weren't expecting the images within themselves to be involuntarily resized. +// See also https://github.com/twbs/bootstrap/issues/18178 +.img-fluid { + @include img-fluid(); +} + + +// Image thumbnails +.img-thumbnail { + padding: $thumbnail-padding; + background-color: $thumbnail-bg; + border: $thumbnail-border-width solid $thumbnail-border-color; + @include border-radius($thumbnail-border-radius); + @include box-shadow($thumbnail-box-shadow); + + // Keep them at most 100% wide + @include img-fluid(); +} + +// +// Figures +// + +.figure { + // Ensures the caption's text aligns with the image. + display: inline-block; +} + +.figure-img { + margin-bottom: $spacer * .5; + line-height: 1; +} + +.figure-caption { + @include font-size($figure-caption-font-size); + color: $figure-caption-color; +} diff --git a/scss/bs4/_mixins.scss b/scss/bs4/_mixins.scss new file mode 100644 index 0000000..7e7a23d --- /dev/null +++ b/scss/bs4/_mixins.scss @@ -0,0 +1,47 @@ +// Toggles +// +// Used in conjunction with global variables to enable certain theme features. + +// Vendor +@import "vendor/rfs"; + +// Deprecate +@import "mixins/deprecate"; + +// Utilities +@import "mixins/breakpoints"; +@import "mixins/hover"; +@import "mixins/image"; +@import "mixins/badge"; +@import "mixins/resize"; +@import "mixins/screen-reader"; +@import "mixins/size"; +@import "mixins/reset-text"; +@import "mixins/text-emphasis"; +@import "mixins/text-hide"; +@import "mixins/text-truncate"; +@import "mixins/visibility"; + +// Components +@import "mixins/alert"; +@import "mixins/buttons"; +@import "mixins/caret"; +@import "mixins/pagination"; +@import "mixins/lists"; +@import "mixins/list-group"; +@import "mixins/nav-divider"; +@import "mixins/forms"; +@import "mixins/table-row"; + +// Skins +@import "mixins/background-variant"; +@import "mixins/border-radius"; +@import "mixins/box-shadow"; +@import "mixins/gradients"; +@import "mixins/transition"; + +// Layout +@import "mixins/clearfix"; +@import "mixins/grid-framework"; +@import "mixins/grid"; +@import "mixins/float"; diff --git a/scss/bs4/_variables.scss b/scss/bs4/_variables.scss new file mode 100644 index 0000000..293d238 --- /dev/null +++ b/scss/bs4/_variables.scss @@ -0,0 +1,1149 @@ +// Variables +// +// Variables should follow the `$component-state-property-size` formula for +// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. + +// Color system + +$white: #fff !default; +$gray-100: #f8f9fa !default; +$gray-200: #e9ecef !default; +$gray-300: #dee2e6 !default; +$gray-400: #ced4da !default; +$gray-500: #adb5bd !default; +$gray-600: #6c757d !default; +$gray-700: #495057 !default; +$gray-800: #343a40 !default; +$gray-900: #212529 !default; +$black: #000 !default; + +$grays: () !default; +$grays: map-merge( + ( + "100": $gray-100, + "200": $gray-200, + "300": $gray-300, + "400": $gray-400, + "500": $gray-500, + "600": $gray-600, + "700": $gray-700, + "800": $gray-800, + "900": $gray-900 + ), + $grays +); + +$blue: #007bff !default; +$indigo: #6610f2 !default; +$purple: #6f42c1 !default; +$pink: #e83e8c !default; +$red: #dc3545 !default; +$orange: #fd7e14 !default; +$yellow: #ffc107 !default; +$green: #28a745 !default; +$teal: #20c997 !default; +$cyan: #17a2b8 !default; + +$colors: () !default; +$colors: map-merge( + ( + "blue": $blue, + "indigo": $indigo, + "purple": $purple, + "pink": $pink, + "red": $red, + "orange": $orange, + "yellow": $yellow, + "green": $green, + "teal": $teal, + "cyan": $cyan, + "white": $white, + "gray": $gray-600, + "gray-dark": $gray-800 + ), + $colors +); + +$primary: $blue !default; +$secondary: $gray-600 !default; +$success: $green !default; +$info: $cyan !default; +$warning: $yellow !default; +$danger: $red !default; +$light: $gray-100 !default; +$dark: $gray-800 !default; + +$theme-colors: () !default; +$theme-colors: map-merge( + ( + "primary": $primary, + "secondary": $secondary, + "success": $success, + "info": $info, + "warning": $warning, + "danger": $danger, + "light": $light, + "dark": $dark + ), + $theme-colors +); + +// Set a specific jump point for requesting color jumps +$theme-color-interval: 8% !default; + +// The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255. +$yiq-contrasted-threshold: 150 !default; + +// Customize the light and dark text colors for use in our YIQ color contrast function. +$yiq-text-dark: $gray-900 !default; +$yiq-text-light: $white !default; + +// Characters which are escaped by the escape-svg function +$escaped-characters: ( + ("<", "%3c"), + (">", "%3e"), + ("#", "%23"), + ("(", "%28"), + (")", "%29"), +) !default; + + +// Options +// +// Quickly modify global styling by enabling or disabling optional features. + +$enable-caret: true !default; +$enable-rounded: true !default; +$enable-shadows: false !default; +$enable-gradients: false !default; +$enable-transitions: true !default; +$enable-prefers-reduced-motion-media-query: true !default; +$enable-hover-media-query: false !default; // Deprecated, no longer affects any compiled CSS +$enable-grid-classes: true !default; +$enable-pointer-cursor-for-buttons: true !default; +$enable-print-styles: true !default; +$enable-responsive-font-sizes: false !default; +$enable-validation-icons: true !default; +$enable-deprecation-messages: true !default; + + +// Spacing +// +// Control the default styling of most Bootstrap elements by modifying these +// variables. Mostly focused on spacing. +// You can add more entries to the $spacers map, should you need more variation. + +$spacer: 1rem !default; +$spacers: () !default; +$spacers: map-merge( + ( + 0: 0, + 1: ($spacer * .25), + 2: ($spacer * .5), + 3: $spacer, + 4: ($spacer * 1.5), + 5: ($spacer * 3) + ), + $spacers +); + +// This variable affects the `.h-*` and `.w-*` classes. +$sizes: () !default; +$sizes: map-merge( + ( + 25: 25%, + 50: 50%, + 75: 75%, + 100: 100%, + auto: auto + ), + $sizes +); + + +// Body +// +// Settings for the `` element. + +$body-bg: $white !default; +$body-color: $gray-900 !default; + + +// Links +// +// Style anchor elements. + +$link-color: theme-color("primary") !default; +$link-decoration: none !default; +$link-hover-color: darken($link-color, 15%) !default; +$link-hover-decoration: underline !default; +// Darken percentage for links with `.text-*` class (e.g. `.text-success`) +$emphasized-link-hover-darken-percentage: 15% !default; + +// Paragraphs +// +// Style p element. + +$paragraph-margin-bottom: 1rem !default; + + +// Grid breakpoints +// +// Define the minimum dimensions at which your layout will change, +// adapting to different screen sizes, for use in media queries. + +$grid-breakpoints: ( + xs: 0, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px +) !default; + +@include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); +@include _assert-starts-at-zero($grid-breakpoints, "$grid-breakpoints"); + + +// Grid containers +// +// Define the maximum width of `.container` for different screen sizes. + +$container-max-widths: ( + sm: 540px, + md: 720px, + lg: 960px, + xl: 1140px +) !default; + +@include _assert-ascending($container-max-widths, "$container-max-widths"); + + +// Grid columns +// +// Set the number of columns and specify the width of the gutters. + +$grid-columns: 12 !default; +$grid-gutter-width: 30px !default; +$grid-row-columns: 6 !default; + + +// Components +// +// Define common padding and border radius sizes and more. + +$line-height-lg: 1.5 !default; +$line-height-sm: 1.5 !default; + +$border-width: 1px !default; +$border-color: $gray-300 !default; + +$border-radius: .25rem !default; +$border-radius-lg: .3rem !default; +$border-radius-sm: .2rem !default; + +$rounded-pill: 50rem !default; + +$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default; +$box-shadow: 0 .5rem 1rem rgba($black, .15) !default; +$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default; + +$component-active-color: $white !default; +$component-active-bg: theme-color("primary") !default; + +$caret-width: .3em !default; +$caret-vertical-align: $caret-width * .85 !default; +$caret-spacing: $caret-width * .85 !default; + +$transition-base: all .2s ease-in-out !default; +$transition-fade: opacity .15s linear !default; +$transition-collapse: height .35s ease !default; +$transition-collapse-width: width .35s ease !default; + +$embed-responsive-aspect-ratios: () !default; +$embed-responsive-aspect-ratios: join( + ( + (21 9), + (16 9), + (4 3), + (1 1), + ), + $embed-responsive-aspect-ratios +); + +// Typography +// +// Font, line-height, and color for body text, headings, and more. + +// stylelint-disable value-keyword-case +$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", "Liberation Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; +$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; +$font-family-base: $font-family-sans-serif !default; +// stylelint-enable value-keyword-case + +$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` +$font-size-lg: $font-size-base * 1.25 !default; +$font-size-sm: $font-size-base * .875 !default; + +$font-weight-lighter: lighter !default; +$font-weight-light: 300 !default; +$font-weight-normal: 400 !default; +$font-weight-bold: 700 !default; +$font-weight-bolder: bolder !default; + +$font-weight-base: $font-weight-normal !default; +$line-height-base: 1.5 !default; + +$h1-font-size: $font-size-base * 2.5 !default; +$h2-font-size: $font-size-base * 2 !default; +$h3-font-size: $font-size-base * 1.75 !default; +$h4-font-size: $font-size-base * 1.5 !default; +$h5-font-size: $font-size-base * 1.25 !default; +$h6-font-size: $font-size-base !default; + +$headings-margin-bottom: $spacer * .5 !default; +$headings-font-family: null !default; +$headings-font-weight: 500 !default; +$headings-line-height: 1.2 !default; +$headings-color: null !default; + +$display1-size: 6rem !default; +$display2-size: 5.5rem !default; +$display3-size: 4.5rem !default; +$display4-size: 3.5rem !default; + +$display1-weight: 300 !default; +$display2-weight: 300 !default; +$display3-weight: 300 !default; +$display4-weight: 300 !default; +$display-line-height: $headings-line-height !default; + +$lead-font-size: $font-size-base * 1.25 !default; +$lead-font-weight: 300 !default; + +$small-font-size: .875em !default; + +$text-muted: $gray-600 !default; + +$blockquote-small-color: $gray-600 !default; +$blockquote-small-font-size: $small-font-size !default; +$blockquote-font-size: $font-size-base * 1.25 !default; + +$hr-border-color: rgba($black, .1) !default; +$hr-border-width: $border-width !default; + +$mark-padding: .2em !default; + +$dt-font-weight: $font-weight-bold !default; + +$kbd-box-shadow: inset 0 -.1rem 0 rgba($black, .25) !default; +$nested-kbd-font-weight: $font-weight-bold !default; + +$list-inline-padding: .5rem !default; + +$mark-bg: #fcf8e3 !default; + +$hr-margin-y: $spacer !default; + + +// Tables +// +// Customizes the `.table` component with basic values, each used across all table variations. + +$table-cell-padding: .75rem !default; +$table-cell-padding-sm: .3rem !default; + +$table-color: $body-color !default; +$table-bg: null !default; +$table-accent-bg: rgba($black, .05) !default; +$table-hover-color: $table-color !default; +$table-hover-bg: rgba($black, .075) !default; +$table-active-bg: $table-hover-bg !default; + +$table-border-width: $border-width !default; +$table-border-color: $border-color !default; + +$table-head-bg: $gray-200 !default; +$table-head-color: $gray-700 !default; +$table-th-font-weight: null !default; + +$table-dark-color: $white !default; +$table-dark-bg: $gray-800 !default; +$table-dark-accent-bg: rgba($white, .05) !default; +$table-dark-hover-color: $table-dark-color !default; +$table-dark-hover-bg: rgba($white, .075) !default; +$table-dark-border-color: lighten($table-dark-bg, 7.5%) !default; + +$table-striped-order: odd !default; + +$table-caption-color: $text-muted !default; + +$table-bg-level: -9 !default; +$table-border-level: -6 !default; + + +// Buttons + Forms +// +// Shared variables that are reassigned to `$input-` and `$btn-` specific variables. + +$input-btn-padding-y: .375rem !default; +$input-btn-padding-x: .75rem !default; +$input-btn-font-family: null !default; +$input-btn-font-size: $font-size-base !default; +$input-btn-line-height: $line-height-base !default; + +$input-btn-focus-width: .2rem !default; +$input-btn-focus-color: rgba($component-active-bg, .25) !default; +$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default; + +$input-btn-padding-y-sm: .25rem !default; +$input-btn-padding-x-sm: .5rem !default; +$input-btn-font-size-sm: $font-size-sm !default; +$input-btn-line-height-sm: $line-height-sm !default; + +$input-btn-padding-y-lg: .5rem !default; +$input-btn-padding-x-lg: 1rem !default; +$input-btn-font-size-lg: $font-size-lg !default; +$input-btn-line-height-lg: $line-height-lg !default; + +$input-btn-border-width: $border-width !default; + + +// Buttons +// +// For each of Bootstrap's buttons, define text, background, and border color. + +$btn-padding-y: $input-btn-padding-y !default; +$btn-padding-x: $input-btn-padding-x !default; +$btn-font-family: $input-btn-font-family !default; +$btn-font-size: $input-btn-font-size !default; +$btn-line-height: $input-btn-line-height !default; +$btn-white-space: null !default; // Set to `nowrap` to prevent text wrapping + +$btn-padding-y-sm: $input-btn-padding-y-sm !default; +$btn-padding-x-sm: $input-btn-padding-x-sm !default; +$btn-font-size-sm: $input-btn-font-size-sm !default; +$btn-line-height-sm: $input-btn-line-height-sm !default; + +$btn-padding-y-lg: $input-btn-padding-y-lg !default; +$btn-padding-x-lg: $input-btn-padding-x-lg !default; +$btn-font-size-lg: $input-btn-font-size-lg !default; +$btn-line-height-lg: $input-btn-line-height-lg !default; + +$btn-border-width: $input-btn-border-width !default; + +$btn-font-weight: $font-weight-normal !default; +$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default; +$btn-focus-width: $input-btn-focus-width !default; +$btn-focus-box-shadow: $input-btn-focus-box-shadow !default; +$btn-disabled-opacity: .65 !default; +$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default; + +$btn-link-disabled-color: $gray-600 !default; + +$btn-block-spacing-y: .5rem !default; + +// Allows for customizing button radius independently from global border radius +$btn-border-radius: $border-radius !default; +$btn-border-radius-lg: $border-radius-lg !default; +$btn-border-radius-sm: $border-radius-sm !default; + +$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + + +// Forms + +$label-margin-bottom: .5rem !default; + +$input-padding-y: $input-btn-padding-y !default; +$input-padding-x: $input-btn-padding-x !default; +$input-font-family: $input-btn-font-family !default; +$input-font-size: $input-btn-font-size !default; +$input-font-weight: $font-weight-base !default; +$input-line-height: $input-btn-line-height !default; + +$input-padding-y-sm: $input-btn-padding-y-sm !default; +$input-padding-x-sm: $input-btn-padding-x-sm !default; +$input-font-size-sm: $input-btn-font-size-sm !default; +$input-line-height-sm: $input-btn-line-height-sm !default; + +$input-padding-y-lg: $input-btn-padding-y-lg !default; +$input-padding-x-lg: $input-btn-padding-x-lg !default; +$input-font-size-lg: $input-btn-font-size-lg !default; +$input-line-height-lg: $input-btn-line-height-lg !default; + +$input-bg: $white !default; +$input-disabled-bg: $gray-200 !default; + +$input-color: $gray-700 !default; +$input-border-color: $gray-400 !default; +$input-border-width: $input-btn-border-width !default; +$input-box-shadow: inset 0 1px 1px rgba($black, .075) !default; + +$input-border-radius: $border-radius !default; +$input-border-radius-lg: $border-radius-lg !default; +$input-border-radius-sm: $border-radius-sm !default; + +$input-focus-bg: $input-bg !default; +$input-focus-border-color: lighten($component-active-bg, 25%) !default; +$input-focus-color: $input-color !default; +$input-focus-width: $input-btn-focus-width !default; +$input-focus-box-shadow: $input-btn-focus-box-shadow !default; + +$input-placeholder-color: $gray-600 !default; +$input-plaintext-color: $body-color !default; + +$input-height-border: $input-border-width * 2 !default; + +$input-height-inner: add($input-line-height * 1em, $input-padding-y * 2) !default; +$input-height-inner-half: add($input-line-height * .5em, $input-padding-y) !default; +$input-height-inner-quarter: add($input-line-height * .25em, $input-padding-y * .5) !default; + +$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false)) !default; +$input-height-sm: add($input-line-height-sm * 1em, add($input-padding-y-sm * 2, $input-height-border, false)) !default; +$input-height-lg: add($input-line-height-lg * 1em, add($input-padding-y-lg * 2, $input-height-border, false)) !default; + +$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$form-text-margin-top: .25rem !default; + +$form-check-input-gutter: 1.25rem !default; +$form-check-input-margin-y: .3rem !default; +$form-check-input-margin-x: .25rem !default; + +$form-check-inline-margin-x: .75rem !default; +$form-check-inline-input-margin-x: .3125rem !default; + +$form-grid-gutter-width: 10px !default; +$form-group-margin-bottom: 1rem !default; + +$input-group-addon-color: $input-color !default; +$input-group-addon-bg: $gray-200 !default; +$input-group-addon-border-color: $input-border-color !default; + +$custom-forms-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$custom-control-gutter: .5rem !default; +$custom-control-spacer-x: 1rem !default; +$custom-control-cursor: null !default; + +$custom-control-indicator-size: 1rem !default; +$custom-control-indicator-bg: $input-bg !default; + +$custom-control-indicator-bg-size: 50% 50% !default; +$custom-control-indicator-box-shadow: $input-box-shadow !default; +$custom-control-indicator-border-color: $gray-500 !default; +$custom-control-indicator-border-width: $input-border-width !default; + +$custom-control-label-color: null !default; + +$custom-control-indicator-disabled-bg: $input-disabled-bg !default; +$custom-control-label-disabled-color: $gray-600 !default; + +$custom-control-indicator-checked-color: $component-active-color !default; +$custom-control-indicator-checked-bg: $component-active-bg !default; +$custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), .5) !default; +$custom-control-indicator-checked-box-shadow: null !default; +$custom-control-indicator-checked-border-color: $custom-control-indicator-checked-bg !default; + +$custom-control-indicator-focus-box-shadow: $input-focus-box-shadow !default; +$custom-control-indicator-focus-border-color: $input-focus-border-color !default; + +$custom-control-indicator-active-color: $component-active-color !default; +$custom-control-indicator-active-bg: lighten($component-active-bg, 35%) !default; +$custom-control-indicator-active-box-shadow: null !default; +$custom-control-indicator-active-border-color: $custom-control-indicator-active-bg !default; + +$custom-checkbox-indicator-border-radius: $border-radius !default; +$custom-checkbox-indicator-icon-checked: url("data:image/svg+xml,") !default; + +$custom-checkbox-indicator-indeterminate-bg: $component-active-bg !default; +$custom-checkbox-indicator-indeterminate-color: $custom-control-indicator-checked-color !default; +$custom-checkbox-indicator-icon-indeterminate: url("data:image/svg+xml,") !default; +$custom-checkbox-indicator-indeterminate-box-shadow: null !default; +$custom-checkbox-indicator-indeterminate-border-color: $custom-checkbox-indicator-indeterminate-bg !default; + +$custom-radio-indicator-border-radius: 50% !default; +$custom-radio-indicator-icon-checked: url("data:image/svg+xml,") !default; + +$custom-switch-width: $custom-control-indicator-size * 1.75 !default; +$custom-switch-indicator-border-radius: $custom-control-indicator-size * .5 !default; +$custom-switch-indicator-size: subtract($custom-control-indicator-size, $custom-control-indicator-border-width * 4) !default; + +$custom-select-padding-y: $input-padding-y !default; +$custom-select-padding-x: $input-padding-x !default; +$custom-select-font-family: $input-font-family !default; +$custom-select-font-size: $input-font-size !default; +$custom-select-height: $input-height !default; +$custom-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator +$custom-select-font-weight: $input-font-weight !default; +$custom-select-line-height: $input-line-height !default; +$custom-select-color: $input-color !default; +$custom-select-disabled-color: $gray-600 !default; +$custom-select-bg: $input-bg !default; +$custom-select-disabled-bg: $gray-200 !default; +$custom-select-bg-size: 8px 10px !default; // In pixels because image dimensions +$custom-select-indicator-color: $gray-800 !default; +$custom-select-indicator: url("data:image/svg+xml,") !default; +$custom-select-background: escape-svg($custom-select-indicator) right $custom-select-padding-x center / $custom-select-bg-size no-repeat !default; // Used so we can have multiple background elements (e.g., arrow and feedback icon) + +$custom-select-feedback-icon-padding-right: add(1em * .75, (2 * $custom-select-padding-y * .75) + $custom-select-padding-x + $custom-select-indicator-padding) !default; +$custom-select-feedback-icon-position: center right ($custom-select-padding-x + $custom-select-indicator-padding) !default; +$custom-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default; + +$custom-select-border-width: $input-border-width !default; +$custom-select-border-color: $input-border-color !default; +$custom-select-border-radius: $border-radius !default; +$custom-select-box-shadow: inset 0 1px 2px rgba($black, .075) !default; + +$custom-select-focus-border-color: $input-focus-border-color !default; +$custom-select-focus-width: $input-focus-width !default; +$custom-select-focus-box-shadow: 0 0 0 $custom-select-focus-width $input-btn-focus-color !default; + +$custom-select-padding-y-sm: $input-padding-y-sm !default; +$custom-select-padding-x-sm: $input-padding-x-sm !default; +$custom-select-font-size-sm: $input-font-size-sm !default; +$custom-select-height-sm: $input-height-sm !default; + +$custom-select-padding-y-lg: $input-padding-y-lg !default; +$custom-select-padding-x-lg: $input-padding-x-lg !default; +$custom-select-font-size-lg: $input-font-size-lg !default; +$custom-select-height-lg: $input-height-lg !default; + +$custom-range-track-width: 100% !default; +$custom-range-track-height: .5rem !default; +$custom-range-track-cursor: pointer !default; +$custom-range-track-bg: $gray-300 !default; +$custom-range-track-border-radius: 1rem !default; +$custom-range-track-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default; + +$custom-range-thumb-width: 1rem !default; +$custom-range-thumb-height: $custom-range-thumb-width !default; +$custom-range-thumb-bg: $component-active-bg !default; +$custom-range-thumb-border: 0 !default; +$custom-range-thumb-border-radius: 1rem !default; +$custom-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default; +$custom-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default; +$custom-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in IE/Edge +$custom-range-thumb-active-bg: lighten($component-active-bg, 35%) !default; +$custom-range-thumb-disabled-bg: $gray-500 !default; + +$custom-file-height: $input-height !default; +$custom-file-height-inner: $input-height-inner !default; +$custom-file-focus-border-color: $input-focus-border-color !default; +$custom-file-focus-box-shadow: $input-focus-box-shadow !default; +$custom-file-disabled-bg: $input-disabled-bg !default; + +$custom-file-padding-y: $input-padding-y !default; +$custom-file-padding-x: $input-padding-x !default; +$custom-file-line-height: $input-line-height !default; +$custom-file-font-family: $input-font-family !default; +$custom-file-font-weight: $input-font-weight !default; +$custom-file-color: $input-color !default; +$custom-file-bg: $input-bg !default; +$custom-file-border-width: $input-border-width !default; +$custom-file-border-color: $input-border-color !default; +$custom-file-border-radius: $input-border-radius !default; +$custom-file-box-shadow: $input-box-shadow !default; +$custom-file-button-color: $custom-file-color !default; +$custom-file-button-bg: $input-group-addon-bg !default; +$custom-file-text: ( + en: "Browse" +) !default; + + +// Form validation + +$form-feedback-margin-top: $form-text-margin-top !default; +$form-feedback-font-size: $small-font-size !default; +$form-feedback-valid-color: theme-color("success") !default; +$form-feedback-invalid-color: theme-color("danger") !default; + +$form-feedback-icon-valid-color: $form-feedback-valid-color !default; +$form-feedback-icon-valid: url("data:image/svg+xml,") !default; +$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default; +$form-feedback-icon-invalid: url("data:image/svg+xml,") !default; + +$form-validation-states: () !default; +$form-validation-states: map-merge( + ( + "valid": ( + "color": $form-feedback-valid-color, + "icon": $form-feedback-icon-valid + ), + "invalid": ( + "color": $form-feedback-invalid-color, + "icon": $form-feedback-icon-invalid + ), + ), + $form-validation-states +); + +// Z-index master list +// +// Warning: Avoid customizing these values. They're used for a bird's eye view +// of components dependent on the z-axis and are designed to all work together. + +$zindex-dropdown: 1000 !default; +$zindex-sticky: 1020 !default; +$zindex-fixed: 1030 !default; +$zindex-modal-backdrop: 1040 !default; +$zindex-modal: 1050 !default; +$zindex-popover: 1060 !default; +$zindex-tooltip: 1070 !default; + + +// Navs + +$nav-link-padding-y: .5rem !default; +$nav-link-padding-x: 1rem !default; +$nav-link-disabled-color: $gray-600 !default; + +$nav-tabs-border-color: $gray-300 !default; +$nav-tabs-border-width: $border-width !default; +$nav-tabs-border-radius: $border-radius !default; +$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default; +$nav-tabs-link-active-color: $gray-700 !default; +$nav-tabs-link-active-bg: $body-bg !default; +$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default; + +$nav-pills-border-radius: $border-radius !default; +$nav-pills-link-active-color: $component-active-color !default; +$nav-pills-link-active-bg: $component-active-bg !default; + +$nav-divider-color: $gray-200 !default; +$nav-divider-margin-y: $spacer * .5 !default; + + +// Navbar + +$navbar-padding-y: $spacer * .5 !default; +$navbar-padding-x: $spacer !default; + +$navbar-nav-link-padding-x: .5rem !default; + +$navbar-brand-font-size: $font-size-lg !default; +// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link +$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default; +$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; +$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) * .5 !default; + +$navbar-toggler-padding-y: .25rem !default; +$navbar-toggler-padding-x: .75rem !default; +$navbar-toggler-font-size: $font-size-lg !default; +$navbar-toggler-border-radius: $btn-border-radius !default; + +$navbar-nav-scroll-max-height: 75vh !default; + +$navbar-dark-color: rgba($white, .5) !default; +$navbar-dark-hover-color: rgba($white, .75) !default; +$navbar-dark-active-color: $white !default; +$navbar-dark-disabled-color: rgba($white, .25) !default; +$navbar-dark-toggler-icon-bg: url("data:image/svg+xml,") !default; +$navbar-dark-toggler-border-color: rgba($white, .1) !default; + +$navbar-light-color: rgba($black, .5) !default; +$navbar-light-hover-color: rgba($black, .7) !default; +$navbar-light-active-color: rgba($black, .9) !default; +$navbar-light-disabled-color: rgba($black, .3) !default; +$navbar-light-toggler-icon-bg: url("data:image/svg+xml,") !default; +$navbar-light-toggler-border-color: rgba($black, .1) !default; + +$navbar-light-brand-color: $navbar-light-active-color !default; +$navbar-light-brand-hover-color: $navbar-light-active-color !default; +$navbar-dark-brand-color: $navbar-dark-active-color !default; +$navbar-dark-brand-hover-color: $navbar-dark-active-color !default; + + +// Dropdowns +// +// Dropdown menu container and contents. + +$dropdown-min-width: 10rem !default; +$dropdown-padding-x: 0 !default; +$dropdown-padding-y: .5rem !default; +$dropdown-spacer: .125rem !default; +$dropdown-font-size: $font-size-base !default; +$dropdown-color: $body-color !default; +$dropdown-bg: $white !default; +$dropdown-border-color: rgba($black, .15) !default; +$dropdown-border-radius: $border-radius !default; +$dropdown-border-width: $border-width !default; +$dropdown-inner-border-radius: subtract($dropdown-border-radius, $dropdown-border-width) !default; +$dropdown-divider-bg: $gray-200 !default; +$dropdown-divider-margin-y: $nav-divider-margin-y !default; +$dropdown-box-shadow: 0 .5rem 1rem rgba($black, .175) !default; + +$dropdown-link-color: $gray-900 !default; +$dropdown-link-hover-color: darken($gray-900, 5%) !default; +$dropdown-link-hover-bg: $gray-200 !default; + +$dropdown-link-active-color: $component-active-color !default; +$dropdown-link-active-bg: $component-active-bg !default; + +$dropdown-link-disabled-color: $gray-500 !default; + +$dropdown-item-padding-y: .25rem !default; +$dropdown-item-padding-x: 1.5rem !default; + +$dropdown-header-color: $gray-600 !default; +$dropdown-header-padding: $dropdown-padding-y $dropdown-item-padding-x !default; + + +// Pagination + +$pagination-padding-y: .5rem !default; +$pagination-padding-x: .75rem !default; +$pagination-padding-y-sm: .25rem !default; +$pagination-padding-x-sm: .5rem !default; +$pagination-padding-y-lg: .75rem !default; +$pagination-padding-x-lg: 1.5rem !default; +$pagination-line-height: 1.25 !default; + +$pagination-color: $link-color !default; +$pagination-bg: $white !default; +$pagination-border-width: $border-width !default; +$pagination-border-color: $gray-300 !default; + +$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default; +$pagination-focus-outline: 0 !default; + +$pagination-hover-color: $link-hover-color !default; +$pagination-hover-bg: $gray-200 !default; +$pagination-hover-border-color: $gray-300 !default; + +$pagination-active-color: $component-active-color !default; +$pagination-active-bg: $component-active-bg !default; +$pagination-active-border-color: $pagination-active-bg !default; + +$pagination-disabled-color: $gray-600 !default; +$pagination-disabled-bg: $white !default; +$pagination-disabled-border-color: $gray-300 !default; + +$pagination-border-radius-sm: $border-radius-sm !default; +$pagination-border-radius-lg: $border-radius-lg !default; + + +// Jumbotron + +$jumbotron-padding: 2rem !default; +$jumbotron-color: null !default; +$jumbotron-bg: $gray-200 !default; + + +// Cards + +$card-spacer-y: .75rem !default; +$card-spacer-x: 1.25rem !default; +$card-border-width: $border-width !default; +$card-border-radius: $border-radius !default; +$card-border-color: rgba($black, .125) !default; +$card-inner-border-radius: subtract($card-border-radius, $card-border-width) !default; +$card-cap-bg: rgba($black, .03) !default; +$card-cap-color: null !default; +$card-height: null !default; +$card-color: null !default; +$card-bg: $white !default; + +$card-img-overlay-padding: 1.25rem !default; + +$card-group-margin: $grid-gutter-width * .5 !default; +$card-deck-margin: $card-group-margin !default; + +$card-columns-count: 3 !default; +$card-columns-gap: 1.25rem !default; +$card-columns-margin: $card-spacer-y !default; + + +// Tooltips + +$tooltip-font-size: $font-size-sm !default; +$tooltip-max-width: 200px !default; +$tooltip-color: $white !default; +$tooltip-bg: $black !default; +$tooltip-border-radius: $border-radius !default; +$tooltip-opacity: .9 !default; +$tooltip-padding-y: .25rem !default; +$tooltip-padding-x: .5rem !default; +$tooltip-margin: 0 !default; + +$tooltip-arrow-width: .8rem !default; +$tooltip-arrow-height: .4rem !default; +$tooltip-arrow-color: $tooltip-bg !default; + +// Form tooltips must come after regular tooltips +$form-feedback-tooltip-padding-y: $tooltip-padding-y !default; +$form-feedback-tooltip-padding-x: $tooltip-padding-x !default; +$form-feedback-tooltip-font-size: $tooltip-font-size !default; +$form-feedback-tooltip-line-height: $line-height-base !default; +$form-feedback-tooltip-opacity: $tooltip-opacity !default; +$form-feedback-tooltip-border-radius: $tooltip-border-radius !default; + + +// Popovers + +$popover-font-size: $font-size-sm !default; +$popover-bg: $white !default; +$popover-max-width: 276px !default; +$popover-border-width: $border-width !default; +$popover-border-color: rgba($black, .2) !default; +$popover-border-radius: $border-radius-lg !default; +$popover-inner-border-radius: subtract($popover-border-radius, $popover-border-width) !default; +$popover-box-shadow: 0 .25rem .5rem rgba($black, .2) !default; + +$popover-header-bg: darken($popover-bg, 3%) !default; +$popover-header-color: $headings-color !default; +$popover-header-padding-y: .5rem !default; +$popover-header-padding-x: .75rem !default; + +$popover-body-color: $body-color !default; +$popover-body-padding-y: $popover-header-padding-y !default; +$popover-body-padding-x: $popover-header-padding-x !default; + +$popover-arrow-width: 1rem !default; +$popover-arrow-height: .5rem !default; +$popover-arrow-color: $popover-bg !default; + +$popover-arrow-outer-color: fade-in($popover-border-color, .05) !default; + + +// Toasts + +$toast-max-width: 350px !default; +$toast-padding-x: .75rem !default; +$toast-padding-y: .25rem !default; +$toast-font-size: .875rem !default; +$toast-color: null !default; +$toast-background-color: rgba($white, .85) !default; +$toast-border-width: 1px !default; +$toast-border-color: rgba(0, 0, 0, .1) !default; +$toast-border-radius: .25rem !default; +$toast-box-shadow: 0 .25rem .75rem rgba($black, .1) !default; + +$toast-header-color: $gray-600 !default; +$toast-header-background-color: rgba($white, .85) !default; +$toast-header-border-color: rgba(0, 0, 0, .05) !default; + + +// Badges + +$badge-font-size: 75% !default; +$badge-font-weight: $font-weight-bold !default; +$badge-padding-y: .25em !default; +$badge-padding-x: .4em !default; +$badge-border-radius: $border-radius !default; + +$badge-transition: $btn-transition !default; +$badge-focus-width: $input-btn-focus-width !default; + +$badge-pill-padding-x: .6em !default; +// Use a higher than normal value to ensure completely rounded edges when +// customizing padding or font-size on labels. +$badge-pill-border-radius: 10rem !default; + + +// Modals + +// Padding applied to the modal body +$modal-inner-padding: 1rem !default; + +// Margin between elements in footer, must be lower than or equal to 2 * $modal-inner-padding +$modal-footer-margin-between: .5rem !default; + +$modal-dialog-margin: .5rem !default; +$modal-dialog-margin-y-sm-up: 1.75rem !default; + +$modal-title-line-height: $line-height-base !default; + +$modal-content-color: null !default; +$modal-content-bg: $white !default; +$modal-content-border-color: rgba($black, .2) !default; +$modal-content-border-width: $border-width !default; +$modal-content-border-radius: $border-radius-lg !default; +$modal-content-inner-border-radius: subtract($modal-content-border-radius, $modal-content-border-width) !default; +$modal-content-box-shadow-xs: 0 .25rem .5rem rgba($black, .5) !default; +$modal-content-box-shadow-sm-up: 0 .5rem 1rem rgba($black, .5) !default; + +$modal-backdrop-bg: $black !default; +$modal-backdrop-opacity: .5 !default; +$modal-header-border-color: $border-color !default; +$modal-footer-border-color: $modal-header-border-color !default; +$modal-header-border-width: $modal-content-border-width !default; +$modal-footer-border-width: $modal-header-border-width !default; +$modal-header-padding-y: 1rem !default; +$modal-header-padding-x: 1rem !default; +$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility + +$modal-xl: 1140px !default; +$modal-lg: 800px !default; +$modal-md: 500px !default; +$modal-sm: 300px !default; + +$modal-fade-transform: translate(0, -50px) !default; +$modal-show-transform: none !default; +$modal-transition: transform .3s ease-out !default; +$modal-scale-transform: scale(1.02) !default; + + +// Alerts +// +// Define alert colors, border radius, and padding. + +$alert-padding-y: .75rem !default; +$alert-padding-x: 1.25rem !default; +$alert-margin-bottom: 1rem !default; +$alert-border-radius: $border-radius !default; +$alert-link-font-weight: $font-weight-bold !default; +$alert-border-width: $border-width !default; + +$alert-bg-level: -10 !default; +$alert-border-level: -9 !default; +$alert-color-level: 6 !default; + + +// Progress bars + +$progress-height: 1rem !default; +$progress-font-size: $font-size-base * .75 !default; +$progress-bg: $gray-200 !default; +$progress-border-radius: $border-radius !default; +$progress-box-shadow: inset 0 .1rem .1rem rgba($black, .1) !default; +$progress-bar-color: $white !default; +$progress-bar-bg: theme-color("primary") !default; +$progress-bar-animation-timing: 1s linear infinite !default; +$progress-bar-transition: width .6s ease !default; + + +// List group + +$list-group-color: null !default; +$list-group-bg: $white !default; +$list-group-border-color: rgba($black, .125) !default; +$list-group-border-width: $border-width !default; +$list-group-border-radius: $border-radius !default; + +$list-group-item-padding-y: .75rem !default; +$list-group-item-padding-x: 1.25rem !default; + +$list-group-hover-bg: $gray-100 !default; +$list-group-active-color: $component-active-color !default; +$list-group-active-bg: $component-active-bg !default; +$list-group-active-border-color: $list-group-active-bg !default; + +$list-group-disabled-color: $gray-600 !default; +$list-group-disabled-bg: $list-group-bg !default; + +$list-group-action-color: $gray-700 !default; +$list-group-action-hover-color: $list-group-action-color !default; + +$list-group-action-active-color: $body-color !default; +$list-group-action-active-bg: $gray-200 !default; + + +// Image thumbnails + +$thumbnail-padding: .25rem !default; +$thumbnail-bg: $body-bg !default; +$thumbnail-border-width: $border-width !default; +$thumbnail-border-color: $gray-300 !default; +$thumbnail-border-radius: $border-radius !default; +$thumbnail-box-shadow: 0 1px 2px rgba($black, .075) !default; + + +// Figures + +$figure-caption-font-size: 90% !default; +$figure-caption-color: $gray-600 !default; + + +// Breadcrumbs + +$breadcrumb-font-size: null !default; + +$breadcrumb-padding-y: .75rem !default; +$breadcrumb-padding-x: 1rem !default; +$breadcrumb-item-padding: .5rem !default; + +$breadcrumb-margin-bottom: 1rem !default; + +$breadcrumb-bg: $gray-200 !default; +$breadcrumb-divider-color: $gray-600 !default; +$breadcrumb-active-color: $gray-600 !default; +$breadcrumb-divider: quote("/") !default; + +$breadcrumb-border-radius: $border-radius !default; + + +// Carousel + +$carousel-control-color: $white !default; +$carousel-control-width: 15% !default; +$carousel-control-opacity: .5 !default; +$carousel-control-hover-opacity: .9 !default; +$carousel-control-transition: opacity .15s ease !default; + +$carousel-indicator-width: 30px !default; +$carousel-indicator-height: 3px !default; +$carousel-indicator-hit-area-height: 10px !default; +$carousel-indicator-spacer: 3px !default; +$carousel-indicator-active-bg: $white !default; +$carousel-indicator-transition: opacity .6s ease !default; + +$carousel-caption-width: 70% !default; +$carousel-caption-color: $white !default; + +$carousel-control-icon-width: 20px !default; + +$carousel-control-prev-icon-bg: url("data:image/svg+xml,") !default; +$carousel-control-next-icon-bg: url("data:image/svg+xml,") !default; + +$carousel-transition-duration: .6s !default; +$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`) + + +// Spinners + +$spinner-width: 2rem !default; +$spinner-height: $spinner-width !default; +$spinner-vertical-align: -.125em !default; +$spinner-border-width: .25em !default; + +$spinner-width-sm: 1rem !default; +$spinner-height-sm: $spinner-width-sm !default; +$spinner-border-width-sm: .2em !default; + + +// Close + +$close-font-size: $font-size-base * 1.5 !default; +$close-font-weight: $font-weight-bold !default; +$close-color: $black !default; +$close-text-shadow: 0 1px 0 $white !default; + + +// Code + +$code-font-size: 87.5% !default; +$code-color: $pink !default; + +$kbd-padding-y: .2rem !default; +$kbd-padding-x: .4rem !default; +$kbd-font-size: $code-font-size !default; +$kbd-color: $white !default; +$kbd-bg: $gray-900 !default; + +$pre-color: $gray-900 !default; +$pre-scrollable-max-height: 340px !default; + + +// Utilities + +$displays: none, inline, inline-block, block, table, table-row, table-cell, flex, inline-flex !default; +$overflows: auto, hidden !default; +$positions: static, relative, absolute, fixed, sticky !default; +$user-selects: all, auto, none !default; + + +// Printing + +$print-page-size: a3 !default; +$print-body-min-width: map-get($grid-breakpoints, "lg") !default; diff --git a/scss/bs4/mixins/_alert.scss b/scss/bs4/mixins/_alert.scss new file mode 100644 index 0000000..db5a7eb --- /dev/null +++ b/scss/bs4/mixins/_alert.scss @@ -0,0 +1,13 @@ +@mixin alert-variant($background, $border, $color) { + color: $color; + @include gradient-bg($background); + border-color: $border; + + hr { + border-top-color: darken($border, 5%); + } + + .alert-link { + color: darken($color, 10%); + } +} diff --git a/scss/bs4/mixins/_background-variant.scss b/scss/bs4/mixins/_background-variant.scss new file mode 100644 index 0000000..8058018 --- /dev/null +++ b/scss/bs4/mixins/_background-variant.scss @@ -0,0 +1,23 @@ +// stylelint-disable declaration-no-important + +// Contextual backgrounds + +@mixin bg-variant($parent, $color, $ignore-warning: false) { + #{$parent} { + background-color: $color !important; + } + a#{$parent}, + button#{$parent} { + @include hover-focus() { + background-color: darken($color, 10%) !important; + } + } + @include deprecate("The `bg-variant` mixin", "v4.4.0", "v5", $ignore-warning); +} + +@mixin bg-gradient-variant($parent, $color, $ignore-warning: false) { + #{$parent} { + background: $color linear-gradient(180deg, mix($body-bg, $color, 15%), $color) repeat-x !important; + } + @include deprecate("The `bg-gradient-variant` mixin", "v4.5.0", "v5", $ignore-warning); +} diff --git a/scss/bs4/mixins/_badge.scss b/scss/bs4/mixins/_badge.scss new file mode 100644 index 0000000..f1c4991 --- /dev/null +++ b/scss/bs4/mixins/_badge.scss @@ -0,0 +1,17 @@ +@mixin badge-variant($bg) { + color: color-yiq($bg); + background-color: $bg; + + @at-root a#{&} { + @include hover-focus() { + color: color-yiq($bg); + background-color: darken($bg, 10%); + } + + &:focus, + &.focus { + outline: 0; + box-shadow: 0 0 0 $badge-focus-width rgba($bg, .5); + } + } +} diff --git a/scss/bs4/mixins/_border-radius.scss b/scss/bs4/mixins/_border-radius.scss new file mode 100644 index 0000000..4fad91d --- /dev/null +++ b/scss/bs4/mixins/_border-radius.scss @@ -0,0 +1,76 @@ +// stylelint-disable property-disallowed-list +// Single side border-radius + +// Helper function to replace negative values with 0 +@function valid-radius($radius) { + $return: (); + @each $value in $radius { + @if type-of($value) == number { + $return: append($return, max($value, 0)); + } @else { + $return: append($return, $value); + } + } + @return $return; +} + +@mixin border-radius($radius: $border-radius, $fallback-border-radius: false) { + @if $enable-rounded { + border-radius: valid-radius($radius); + } + @else if $fallback-border-radius != false { + border-radius: $fallback-border-radius; + } +} + +@mixin border-top-radius($radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + border-top-right-radius: valid-radius($radius); + } +} + +@mixin border-right-radius($radius) { + @if $enable-rounded { + border-top-right-radius: valid-radius($radius); + border-bottom-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-radius($radius) { + @if $enable-rounded { + border-bottom-right-radius: valid-radius($radius); + border-bottom-left-radius: valid-radius($radius); + } +} + +@mixin border-left-radius($radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + border-bottom-left-radius: valid-radius($radius); + } +} + +@mixin border-top-left-radius($radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + } +} + +@mixin border-top-right-radius($radius) { + @if $enable-rounded { + border-top-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-right-radius($radius) { + @if $enable-rounded { + border-bottom-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-left-radius($radius) { + @if $enable-rounded { + border-bottom-left-radius: valid-radius($radius); + } +} diff --git a/scss/bs4/mixins/_box-shadow.scss b/scss/bs4/mixins/_box-shadow.scss new file mode 100644 index 0000000..0726d43 --- /dev/null +++ b/scss/bs4/mixins/_box-shadow.scss @@ -0,0 +1,20 @@ +@mixin box-shadow($shadow...) { + @if $enable-shadows { + $result: (); + + @if (length($shadow) == 1) { + // We can pass `@include box-shadow(none);` + $result: $shadow; + } @else { + // Filter to avoid invalid properties for example `box-shadow: none, 1px 1px black;` + @for $i from 1 through length($shadow) { + @if nth($shadow, $i) != "none" { + $result: append($result, nth($shadow, $i), "comma"); + } + } + } + @if (length($result) > 0) { + box-shadow: $result; + } + } +} diff --git a/scss/bs4/mixins/_breakpoints.scss b/scss/bs4/mixins/_breakpoints.scss new file mode 100644 index 0000000..23a5de9 --- /dev/null +++ b/scss/bs4/mixins/_breakpoints.scss @@ -0,0 +1,123 @@ +// Breakpoint viewport sizes and media queries. +// +// Breakpoints are defined as a map of (name: minimum width), order from small to large: +// +// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px) +// +// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. + +// Name of the next breakpoint, or null for the last breakpoint. +// +// >> breakpoint-next(sm) +// md +// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// md +// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl)) +// md +@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { + $n: index($breakpoint-names, $name); + @return if($n != null and $n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); +} + +// Minimum breakpoint width. Null for the smallest (first) breakpoint. +// +// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// 576px +@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { + $min: map-get($breakpoints, $name); + @return if($min != 0, $min, null); +} + +// Maximum breakpoint width. Null for the largest (last) breakpoint. +// The maximum value is calculated as the minimum of the next one less 0.02px +// to work around the limitations of `min-` and `max-` prefixes and viewports with fractional widths. +// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max +// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari. +// See https://bugs.webkit.org/show_bug.cgi?id=178261 +// +// >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// 767.98px +@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { + $next: breakpoint-next($name, $breakpoints); + @return if($next, breakpoint-min($next, $breakpoints) - .02, null); +} + +// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front. +// Useful for making responsive utilities. +// +// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// "" (Returns a blank string) +// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) +// "-sm" +@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) { + @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}"); +} + +// Media of at least the minimum breakpoint width. No query for the smallest breakpoint. +// Makes the @content apply to the given breakpoint and wider. +@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + @if $min { + @media (min-width: $min) { + @content; + } + } @else { + @content; + } +} + +// Media of at most the maximum breakpoint width. No query for the largest breakpoint. +// Makes the @content apply to the given breakpoint and narrower. +@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) { + $max: breakpoint-max($name, $breakpoints); + @if $max { + @media (max-width: $max) { + @content; + } + } @else { + @content; + } +} + +// Media that spans multiple breakpoint widths. +// Makes the @content apply between the min and max breakpoints +@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($lower, $breakpoints); + $max: breakpoint-max($upper, $breakpoints); + + @if $min != null and $max != null { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else if $max == null { + @include media-breakpoint-up($lower, $breakpoints) { + @content; + } + } @else if $min == null { + @include media-breakpoint-down($upper, $breakpoints) { + @content; + } + } +} + +// Media between the breakpoint's minimum and maximum widths. +// No minimum for the smallest breakpoint, and no maximum for the largest one. +// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower. +@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + $max: breakpoint-max($name, $breakpoints); + + @if $min != null and $max != null { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else if $max == null { + @include media-breakpoint-up($name, $breakpoints) { + @content; + } + } @else if $min == null { + @include media-breakpoint-down($name, $breakpoints) { + @content; + } + } +} diff --git a/scss/bs4/mixins/_buttons.scss b/scss/bs4/mixins/_buttons.scss new file mode 100644 index 0000000..d6235aa --- /dev/null +++ b/scss/bs4/mixins/_buttons.scss @@ -0,0 +1,110 @@ +// Button variants +// +// Easily pump out default styles, as well as :hover, :focus, :active, +// and disabled options for all buttons + +@mixin button-variant($background, $border, $hover-background: darken($background, 7.5%), $hover-border: darken($border, 10%), $active-background: darken($background, 10%), $active-border: darken($border, 12.5%)) { + color: color-yiq($background); + @include gradient-bg($background); + border-color: $border; + @include box-shadow($btn-box-shadow); + + @include hover() { + color: color-yiq($hover-background); + @include gradient-bg($hover-background); + border-color: $hover-border; + } + + &:focus, + &.focus { + color: color-yiq($hover-background); + @include gradient-bg($hover-background); + border-color: $hover-border; + @if $enable-shadows { + @include box-shadow($btn-box-shadow, 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5)); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5); + } + } + + // Disabled comes first so active can properly restyle + &.disabled, + &:disabled { + color: color-yiq($background); + background-color: $background; + border-color: $border; + // Remove CSS gradients if they're enabled + @if $enable-gradients { + background-image: none; + } + } + + &:not(:disabled):not(.disabled):active, + &:not(:disabled):not(.disabled).active, + .show > &.dropdown-toggle { + color: color-yiq($active-background); + background-color: $active-background; + @if $enable-gradients { + background-image: none; // Remove the gradient for the pressed/active state + } + border-color: $active-border; + + &:focus { + @if $enable-shadows and $btn-active-box-shadow != none { + @include box-shadow($btn-active-box-shadow, 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5)); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5); + } + } + } +} + +@mixin button-outline-variant($color, $color-hover: color-yiq($color), $active-background: $color, $active-border: $color) { + color: $color; + border-color: $color; + + @include hover() { + color: $color-hover; + background-color: $active-background; + border-color: $active-border; + } + + &:focus, + &.focus { + box-shadow: 0 0 0 $btn-focus-width rgba($color, .5); + } + + &.disabled, + &:disabled { + color: $color; + background-color: transparent; + } + + &:not(:disabled):not(.disabled):active, + &:not(:disabled):not(.disabled).active, + .show > &.dropdown-toggle { + color: color-yiq($active-background); + background-color: $active-background; + border-color: $active-border; + + &:focus { + @if $enable-shadows and $btn-active-box-shadow != none { + @include box-shadow($btn-active-box-shadow, 0 0 0 $btn-focus-width rgba($color, .5)); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: 0 0 0 $btn-focus-width rgba($color, .5); + } + } + } +} + +// Button sizes +@mixin button-size($padding-y, $padding-x, $font-size, $line-height, $border-radius) { + padding: $padding-y $padding-x; + @include font-size($font-size); + line-height: $line-height; + // Manually declare to provide an override to the browser default + @include border-radius($border-radius, 0); +} diff --git a/scss/bs4/mixins/_caret.scss b/scss/bs4/mixins/_caret.scss new file mode 100644 index 0000000..2746649 --- /dev/null +++ b/scss/bs4/mixins/_caret.scss @@ -0,0 +1,62 @@ +@mixin caret-down() { + border-top: $caret-width solid; + border-right: $caret-width solid transparent; + border-bottom: 0; + border-left: $caret-width solid transparent; +} + +@mixin caret-up() { + border-top: 0; + border-right: $caret-width solid transparent; + border-bottom: $caret-width solid; + border-left: $caret-width solid transparent; +} + +@mixin caret-right() { + border-top: $caret-width solid transparent; + border-right: 0; + border-bottom: $caret-width solid transparent; + border-left: $caret-width solid; +} + +@mixin caret-left() { + border-top: $caret-width solid transparent; + border-right: $caret-width solid; + border-bottom: $caret-width solid transparent; +} + +@mixin caret($direction: down) { + @if $enable-caret { + &::after { + display: inline-block; + margin-left: $caret-spacing; + vertical-align: $caret-vertical-align; + content: ""; + @if $direction == down { + @include caret-down(); + } @else if $direction == up { + @include caret-up(); + } @else if $direction == right { + @include caret-right(); + } + } + + @if $direction == left { + &::after { + display: none; + } + + &::before { + display: inline-block; + margin-right: $caret-spacing; + vertical-align: $caret-vertical-align; + content: ""; + @include caret-left(); + } + } + + &:empty::after { + margin-left: 0; + } + } +} diff --git a/scss/bs4/mixins/_clearfix.scss b/scss/bs4/mixins/_clearfix.scss new file mode 100644 index 0000000..11a977b --- /dev/null +++ b/scss/bs4/mixins/_clearfix.scss @@ -0,0 +1,7 @@ +@mixin clearfix() { + &::after { + display: block; + clear: both; + content: ""; + } +} diff --git a/scss/bs4/mixins/_deprecate.scss b/scss/bs4/mixins/_deprecate.scss new file mode 100644 index 0000000..df070bc --- /dev/null +++ b/scss/bs4/mixins/_deprecate.scss @@ -0,0 +1,10 @@ +// Deprecate mixin +// +// This mixin can be used to deprecate mixins or functions. +// `$enable-deprecation-messages` is a global variable, `$ignore-warning` is a variable that can be passed to +// some deprecated mixins to suppress the warning (for example if the mixin is still be used in the current version of Bootstrap) +@mixin deprecate($name, $deprecate-version, $remove-version, $ignore-warning: false) { + @if ($enable-deprecation-messages != false and $ignore-warning != true) { + @warn "#{$name} has been deprecated as of #{$deprecate-version}. It will be removed entirely in #{$remove-version}."; + } +} diff --git a/scss/bs4/mixins/_float.scss b/scss/bs4/mixins/_float.scss new file mode 100644 index 0000000..6b376a2 --- /dev/null +++ b/scss/bs4/mixins/_float.scss @@ -0,0 +1,14 @@ +// stylelint-disable declaration-no-important + +@mixin float-left() { + float: left !important; + @include deprecate("The `float-left` mixin", "v4.3.0", "v5"); +} +@mixin float-right() { + float: right !important; + @include deprecate("The `float-right` mixin", "v4.3.0", "v5"); +} +@mixin float-none() { + float: none !important; + @include deprecate("The `float-none` mixin", "v4.3.0", "v5"); +} diff --git a/scss/bs4/mixins/_forms.scss b/scss/bs4/mixins/_forms.scss new file mode 100644 index 0000000..b8847cc --- /dev/null +++ b/scss/bs4/mixins/_forms.scss @@ -0,0 +1,195 @@ +// Form control focus state +// +// Generate a customized focus state and for any input with the specified color, +// which defaults to the `$input-focus-border-color` variable. +// +// We highly encourage you to not customize the default value, but instead use +// this to tweak colors on an as-needed basis. This aesthetic change is based on +// WebKit's default styles, but applicable to a wider range of browsers. Its +// usability and accessibility should be taken into account with any change. +// +// Example usage: change the default blue border and shadow to white for better +// contrast against a dark gray background. +@mixin form-control-focus($ignore-warning: false) { + &:focus { + color: $input-focus-color; + background-color: $input-focus-bg; + border-color: $input-focus-border-color; + outline: 0; + @if $enable-shadows { + @include box-shadow($input-box-shadow, $input-focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $input-focus-box-shadow; + } + } + @include deprecate("The `form-control-focus()` mixin", "v4.4.0", "v5", $ignore-warning); +} + +// This mixin uses an `if()` technique to be compatible with Dart Sass +// See https://github.com/sass/sass/issues/1873#issuecomment-152293725 for more details +@mixin form-validation-state-selector($state) { + @if ($state == "valid" or $state == "invalid") { + .was-validated #{if(&, "&", "")}:#{$state}, + #{if(&, "&", "")}.is-#{$state} { + @content; + } + } @else { + #{if(&, "&", "")}.is-#{$state} { + @content; + } + } +} + +@mixin form-validation-state($state, $color, $icon) { + .#{$state}-feedback { + display: none; + width: 100%; + margin-top: $form-feedback-margin-top; + @include font-size($form-feedback-font-size); + color: $color; + } + + .#{$state}-tooltip { + position: absolute; + top: 100%; + left: 0; + z-index: 5; + display: none; + max-width: 100%; // Contain to parent when possible + padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x; + margin-top: .1rem; + @include font-size($form-feedback-tooltip-font-size); + line-height: $form-feedback-tooltip-line-height; + color: color-yiq($color); + background-color: rgba($color, $form-feedback-tooltip-opacity); + @include border-radius($form-feedback-tooltip-border-radius); + + // See https://github.com/twbs/bootstrap/pull/31557 + // Align tooltip to form elements + .form-row > .col > &, + .form-row > [class*="col-"] > & { + left: $form-grid-gutter-width * .5; + } + } + + @include form-validation-state-selector($state) { + ~ .#{$state}-feedback, + ~ .#{$state}-tooltip { + display: block; + } + } + + .form-control { + @include form-validation-state-selector($state) { + border-color: $color; + + @if $enable-validation-icons { + padding-right: $input-height-inner !important; // stylelint-disable-line declaration-no-important + background-image: escape-svg($icon); + background-repeat: no-repeat; + background-position: right $input-height-inner-quarter center; + background-size: $input-height-inner-half $input-height-inner-half; + } + + &:focus { + border-color: $color; + box-shadow: 0 0 0 $input-focus-width rgba($color, .25); + } + } + } + + // stylelint-disable-next-line selector-no-qualifying-type + select.form-control { + @include form-validation-state-selector($state) { + @if $enable-validation-icons { + padding-right: $input-padding-x * 4 !important; // stylelint-disable-line declaration-no-important + background-position: right $input-padding-x * 2 center; + } + } + } + + // stylelint-disable-next-line selector-no-qualifying-type + textarea.form-control { + @include form-validation-state-selector($state) { + @if $enable-validation-icons { + padding-right: $input-height-inner; + background-position: top $input-height-inner-quarter right $input-height-inner-quarter; + } + } + } + + .custom-select { + @include form-validation-state-selector($state) { + border-color: $color; + + @if $enable-validation-icons { + padding-right: $custom-select-feedback-icon-padding-right !important; // stylelint-disable-line declaration-no-important + background: $custom-select-background, $custom-select-bg escape-svg($icon) $custom-select-feedback-icon-position / $custom-select-feedback-icon-size no-repeat; + } + + &:focus { + border-color: $color; + box-shadow: 0 0 0 $input-focus-width rgba($color, .25); + } + } + } + + .form-check-input { + @include form-validation-state-selector($state) { + ~ .form-check-label { + color: $color; + } + + ~ .#{$state}-feedback, + ~ .#{$state}-tooltip { + display: block; + } + } + } + + .custom-control-input { + @include form-validation-state-selector($state) { + ~ .custom-control-label { + color: $color; + + &::before { + border-color: $color; + } + } + + &:checked { + ~ .custom-control-label::before { + border-color: lighten($color, 10%); + @include gradient-bg(lighten($color, 10%)); + } + } + + &:focus { + ~ .custom-control-label::before { + box-shadow: 0 0 0 $input-focus-width rgba($color, .25); + } + + &:not(:checked) ~ .custom-control-label::before { + border-color: $color; + } + } + } + } + + // custom file + .custom-file-input { + @include form-validation-state-selector($state) { + ~ .custom-file-label { + border-color: $color; + } + + &:focus { + ~ .custom-file-label { + border-color: $color; + box-shadow: 0 0 0 $input-focus-width rgba($color, .25); + } + } + } + } +} diff --git a/scss/bs4/mixins/_gradients.scss b/scss/bs4/mixins/_gradients.scss new file mode 100644 index 0000000..88c4d64 --- /dev/null +++ b/scss/bs4/mixins/_gradients.scss @@ -0,0 +1,45 @@ +// Gradients + +@mixin gradient-bg($color) { + @if $enable-gradients { + background: $color linear-gradient(180deg, mix($body-bg, $color, 15%), $color) repeat-x; + } @else { + background-color: $color; + } +} + +// Horizontal gradient, from left to right +// +// Creates two color stops, start and end, by specifying a color and position for each color stop. +@mixin gradient-x($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) { + background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent); + background-repeat: repeat-x; +} + +// Vertical gradient, from top to bottom +// +// Creates two color stops, start and end, by specifying a color and position for each color stop. +@mixin gradient-y($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) { + background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); + background-repeat: repeat-x; +} + +@mixin gradient-directional($start-color: $gray-700, $end-color: $gray-800, $deg: 45deg) { + background-image: linear-gradient($deg, $start-color, $end-color); + background-repeat: repeat-x; +} +@mixin gradient-x-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { + background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color); + background-repeat: no-repeat; +} +@mixin gradient-y-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { + background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color); + background-repeat: no-repeat; +} +@mixin gradient-radial($inner-color: $gray-700, $outer-color: $gray-800) { + background-image: radial-gradient(circle, $inner-color, $outer-color); + background-repeat: no-repeat; +} +@mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) { + background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent); +} diff --git a/scss/bs4/mixins/_grid-framework.scss b/scss/bs4/mixins/_grid-framework.scss new file mode 100644 index 0000000..ef32917 --- /dev/null +++ b/scss/bs4/mixins/_grid-framework.scss @@ -0,0 +1,80 @@ +// Framework grid generation +// +// Used only by Bootstrap to generate the correct number of grid classes given +// any value of `$grid-columns`. + +@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) { + // Common properties for all breakpoints + %grid-column { + position: relative; + width: 100%; + padding-right: $gutter * .5; + padding-left: $gutter * .5; + } + + @each $breakpoint in map-keys($breakpoints) { + $infix: breakpoint-infix($breakpoint, $breakpoints); + + @if $columns > 0 { + // Allow columns to stretch full width below their breakpoints + @for $i from 1 through $columns { + .col#{$infix}-#{$i} { + @extend %grid-column; + } + } + } + + .col#{$infix}, + .col#{$infix}-auto { + @extend %grid-column; + } + + @include media-breakpoint-up($breakpoint, $breakpoints) { + // Provide basic `.col-{bp}` classes for equal-width flexbox columns + .col#{$infix} { + flex-basis: 0; + flex-grow: 1; + max-width: 100%; + } + + @if $grid-row-columns > 0 { + @for $i from 1 through $grid-row-columns { + .row-cols#{$infix}-#{$i} { + @include row-cols($i); + } + } + } + + .col#{$infix}-auto { + @include make-col-auto(); + } + + @if $columns > 0 { + @for $i from 1 through $columns { + .col#{$infix}-#{$i} { + @include make-col($i, $columns); + } + } + } + + .order#{$infix}-first { order: -1; } + + .order#{$infix}-last { order: $columns + 1; } + + @for $i from 0 through $columns { + .order#{$infix}-#{$i} { order: $i; } + } + + @if $columns > 0 { + // `$columns - 1` because offsetting by the width of an entire row isn't possible + @for $i from 0 through ($columns - 1) { + @if not ($infix == "" and $i == 0) { // Avoid emitting useless .offset-0 + .offset#{$infix}-#{$i} { + @include make-col-offset($i, $columns); + } + } + } + } + } + } +} diff --git a/scss/bs4/mixins/_grid.scss b/scss/bs4/mixins/_grid.scss new file mode 100644 index 0000000..0eb0991 --- /dev/null +++ b/scss/bs4/mixins/_grid.scss @@ -0,0 +1,69 @@ +/// Grid system +// +// Generate semantic grid columns with these mixins. + +@mixin make-container($gutter: $grid-gutter-width) { + width: 100%; + padding-right: $gutter * .5; + padding-left: $gutter * .5; + margin-right: auto; + margin-left: auto; +} + +@mixin make-row($gutter: $grid-gutter-width) { + display: flex; + flex-wrap: wrap; + margin-right: -$gutter * .5; + margin-left: -$gutter * .5; +} + +// For each breakpoint, define the maximum width of the container in a media query +@mixin make-container-max-widths($max-widths: $container-max-widths, $breakpoints: $grid-breakpoints) { + @each $breakpoint, $container-max-width in $max-widths { + @include media-breakpoint-up($breakpoint, $breakpoints) { + max-width: $container-max-width; + } + } + @include deprecate("The `make-container-max-widths` mixin", "v4.5.2", "v5"); +} + +@mixin make-col-ready($gutter: $grid-gutter-width) { + position: relative; + // Prevent columns from becoming too narrow when at smaller grid tiers by + // always setting `width: 100%;`. This works because we use `flex` values + // later on to override this initial width. + width: 100%; + padding-right: $gutter * .5; + padding-left: $gutter * .5; +} + +@mixin make-col($size, $columns: $grid-columns) { + flex: 0 0 percentage(divide($size, $columns)); + // Add a `max-width` to ensure content within each column does not blow out + // the width of the column. Applies to IE10+ and Firefox. Chrome and Safari + // do not appear to require this. + max-width: percentage(divide($size, $columns)); +} + +@mixin make-col-auto() { + flex: 0 0 auto; + width: auto; + max-width: 100%; // Reset earlier grid tiers +} + +@mixin make-col-offset($size, $columns: $grid-columns) { + $num: divide($size, $columns); + margin-left: if($num == 0, 0, percentage($num)); +} + +// Row columns +// +// Specify on a parent element(e.g., .row) to force immediate children into NN +// numberof columns. Supports wrapping to new lines, but does not do a Masonry +// style grid. +@mixin row-cols($count) { + > * { + flex: 0 0 divide(100%, $count); + max-width: divide(100%, $count); + } +} diff --git a/scss/bs4/mixins/_hover.scss b/scss/bs4/mixins/_hover.scss new file mode 100644 index 0000000..409f824 --- /dev/null +++ b/scss/bs4/mixins/_hover.scss @@ -0,0 +1,37 @@ +// Hover mixin and `$enable-hover-media-query` are deprecated. +// +// Originally added during our alphas and maintained during betas, this mixin was +// designed to prevent `:hover` stickiness on iOS-an issue where hover styles +// would persist after initial touch. +// +// For backward compatibility, we've kept these mixins and updated them to +// always return their regular pseudo-classes instead of a shimmed media query. +// +// Issue: https://github.com/twbs/bootstrap/issues/25195 + +@mixin hover() { + &:hover { @content; } +} + +@mixin hover-focus() { + &:hover, + &:focus { + @content; + } +} + +@mixin plain-hover-focus() { + &, + &:hover, + &:focus { + @content; + } +} + +@mixin hover-focus-active() { + &:hover, + &:focus, + &:active { + @content; + } +} diff --git a/scss/bs4/mixins/_image.scss b/scss/bs4/mixins/_image.scss new file mode 100644 index 0000000..3aaa0d7 --- /dev/null +++ b/scss/bs4/mixins/_image.scss @@ -0,0 +1,36 @@ +// Image Mixins +// - Responsive image +// - Retina image + + +// Responsive image +// +// Keep images from scaling beyond the width of their parents. + +@mixin img-fluid() { + // Part 1: Set a maximum relative to the parent + max-width: 100%; + // Part 2: Override the height to auto, otherwise images will be stretched + // when setting a width and height attribute on the img element. + height: auto; +} + + +// Retina image +// +// Short retina mixin for setting background-image and -size. + +@mixin img-retina($file-1x, $file-2x, $width-1x, $height-1x) { + background-image: url($file-1x); + + // Autoprefixer takes care of adding -webkit-min-device-pixel-ratio and -o-min-device-pixel-ratio, + // but doesn't convert dppx=>dpi. + // There's no such thing as unprefixed min-device-pixel-ratio since it's nonstandard. + // Compatibility info: https://caniuse.com/css-media-resolution + @media only screen and (min-resolution: 192dpi), // IE9-11 don't support dppx + only screen and (min-resolution: 2dppx) { // Standardized + background-image: url($file-2x); + background-size: $width-1x $height-1x; + } + @include deprecate("`img-retina()`", "v4.3.0", "v5"); +} diff --git a/scss/bs4/mixins/_list-group.scss b/scss/bs4/mixins/_list-group.scss new file mode 100644 index 0000000..0da3531 --- /dev/null +++ b/scss/bs4/mixins/_list-group.scss @@ -0,0 +1,21 @@ +// List Groups + +@mixin list-group-item-variant($state, $background, $color) { + .list-group-item-#{$state} { + color: $color; + background-color: $background; + + &.list-group-item-action { + @include hover-focus() { + color: $color; + background-color: darken($background, 5%); + } + + &.active { + color: $white; + background-color: $color; + border-color: $color; + } + } + } +} diff --git a/scss/bs4/mixins/_lists.scss b/scss/bs4/mixins/_lists.scss new file mode 100644 index 0000000..251cb07 --- /dev/null +++ b/scss/bs4/mixins/_lists.scss @@ -0,0 +1,7 @@ +// Lists + +// Unstyled keeps list items block level, just removes default browser padding and list-style +@mixin list-unstyled() { + padding-left: 0; + list-style: none; +} diff --git a/scss/bs4/mixins/_nav-divider.scss b/scss/bs4/mixins/_nav-divider.scss new file mode 100644 index 0000000..3e0ccea --- /dev/null +++ b/scss/bs4/mixins/_nav-divider.scss @@ -0,0 +1,11 @@ +// Horizontal dividers +// +// Dividers (basically an hr) within dropdowns and nav lists + +@mixin nav-divider($color: $nav-divider-color, $margin-y: $nav-divider-margin-y, $ignore-warning: false) { + height: 0; + margin: $margin-y 0; + overflow: hidden; + border-top: 1px solid $color; + @include deprecate("The `nav-divider()` mixin", "v4.4.0", "v5", $ignore-warning); +} diff --git a/scss/bs4/mixins/_pagination.scss b/scss/bs4/mixins/_pagination.scss new file mode 100644 index 0000000..af8e16d --- /dev/null +++ b/scss/bs4/mixins/_pagination.scss @@ -0,0 +1,22 @@ +// Pagination + +@mixin pagination-size($padding-y, $padding-x, $font-size, $line-height, $border-radius) { + .page-link { + padding: $padding-y $padding-x; + @include font-size($font-size); + line-height: $line-height; + } + + .page-item { + &:first-child { + .page-link { + @include border-left-radius($border-radius); + } + } + &:last-child { + .page-link { + @include border-right-radius($border-radius); + } + } + } +} diff --git a/scss/bs4/mixins/_reset-text.scss b/scss/bs4/mixins/_reset-text.scss new file mode 100644 index 0000000..8682533 --- /dev/null +++ b/scss/bs4/mixins/_reset-text.scss @@ -0,0 +1,17 @@ +@mixin reset-text() { + font-family: $font-family-base; + // We deliberately do NOT reset font-size or word-wrap. + font-style: normal; + font-weight: $font-weight-normal; + line-height: $line-height-base; + text-align: left; // Fallback for where `start` is not supported + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; +} diff --git a/scss/bs4/mixins/_resize.scss b/scss/bs4/mixins/_resize.scss new file mode 100644 index 0000000..66f233a --- /dev/null +++ b/scss/bs4/mixins/_resize.scss @@ -0,0 +1,6 @@ +// Resize anything + +@mixin resizable($direction) { + overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` + resize: $direction; // Options: horizontal, vertical, both +} diff --git a/scss/bs4/mixins/_screen-reader.scss b/scss/bs4/mixins/_screen-reader.scss new file mode 100644 index 0000000..70b677e --- /dev/null +++ b/scss/bs4/mixins/_screen-reader.scss @@ -0,0 +1,34 @@ +// Only display content to screen readers +// +// See: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/ +// See: https://kittygiraudel.com/2016/10/13/css-hide-and-seek/ + +@mixin sr-only() { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; // Fix for https://github.com/twbs/bootstrap/issues/25686 + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: 0; +} + +// Use in conjunction with .sr-only to only display content when it's focused. +// +// Useful for "Skip to main content" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 +// +// Credit: HTML5 Boilerplate + +@mixin sr-only-focusable() { + &:active, + &:focus { + position: static; + width: auto; + height: auto; + overflow: visible; + clip: auto; + white-space: normal; + } +} diff --git a/scss/bs4/mixins/_size.scss b/scss/bs4/mixins/_size.scss new file mode 100644 index 0000000..69e056d --- /dev/null +++ b/scss/bs4/mixins/_size.scss @@ -0,0 +1,7 @@ +// Sizing shortcuts + +@mixin size($width, $height: $width) { + width: $width; + height: $height; + @include deprecate("`size()`", "v4.3.0", "v5"); +} diff --git a/scss/bs4/mixins/_table-row.scss b/scss/bs4/mixins/_table-row.scss new file mode 100644 index 0000000..1ccde6b --- /dev/null +++ b/scss/bs4/mixins/_table-row.scss @@ -0,0 +1,39 @@ +// Tables + +@mixin table-row-variant($state, $background, $border: null) { + // Exact selectors below required to override `.table-striped` and prevent + // inheritance to nested tables. + .table-#{$state} { + &, + > th, + > td { + background-color: $background; + } + + @if $border != null { + th, + td, + thead th, + tbody + tbody { + border-color: $border; + } + } + } + + // Hover states for `.table-hover` + // Note: this is not available for cells or rows within `thead` or `tfoot`. + .table-hover { + $hover-background: darken($background, 5%); + + .table-#{$state} { + @include hover() { + background-color: $hover-background; + + > td, + > th { + background-color: $hover-background; + } + } + } + } +} diff --git a/scss/bs4/mixins/_text-emphasis.scss b/scss/bs4/mixins/_text-emphasis.scss new file mode 100644 index 0000000..5eb8a55 --- /dev/null +++ b/scss/bs4/mixins/_text-emphasis.scss @@ -0,0 +1,17 @@ +// stylelint-disable declaration-no-important + +// Typography + +@mixin text-emphasis-variant($parent, $color, $ignore-warning: false) { + #{$parent} { + color: $color !important; + } + @if $emphasized-link-hover-darken-percentage != 0 { + a#{$parent} { + @include hover-focus() { + color: darken($color, $emphasized-link-hover-darken-percentage) !important; + } + } + } + @include deprecate("`text-emphasis-variant()`", "v4.4.0", "v5", $ignore-warning); +} diff --git a/scss/bs4/mixins/_text-hide.scss b/scss/bs4/mixins/_text-hide.scss new file mode 100644 index 0000000..3a92301 --- /dev/null +++ b/scss/bs4/mixins/_text-hide.scss @@ -0,0 +1,11 @@ +// CSS image replacement +@mixin text-hide($ignore-warning: false) { + // stylelint-disable-next-line font-family-no-missing-generic-family-keyword + font: 0/0 a; + color: transparent; + text-shadow: none; + background-color: transparent; + border: 0; + + @include deprecate("`text-hide()`", "v4.1.0", "v5", $ignore-warning); +} diff --git a/scss/bs4/mixins/_text-truncate.scss b/scss/bs4/mixins/_text-truncate.scss new file mode 100644 index 0000000..3504bb1 --- /dev/null +++ b/scss/bs4/mixins/_text-truncate.scss @@ -0,0 +1,8 @@ +// Text truncate +// Requires inline-block or block for proper styling + +@mixin text-truncate() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/scss/bs4/mixins/_transition.scss b/scss/bs4/mixins/_transition.scss new file mode 100644 index 0000000..54870bf --- /dev/null +++ b/scss/bs4/mixins/_transition.scss @@ -0,0 +1,26 @@ +// stylelint-disable property-disallowed-list +@mixin transition($transition...) { + @if length($transition) == 0 { + $transition: $transition-base; + } + + @if length($transition) > 1 { + @each $value in $transition { + @if $value == null or $value == none { + @warn "The keyword 'none' or 'null' must be used as a single argument."; + } + } + } + + @if $enable-transitions { + @if nth($transition, 1) != null { + transition: $transition; + } + + @if $enable-prefers-reduced-motion-media-query and nth($transition, 1) != null and nth($transition, 1) != none { + @media (prefers-reduced-motion: reduce) { + transition: none; + } + } + } +} diff --git a/scss/bs4/mixins/_visibility.scss b/scss/bs4/mixins/_visibility.scss new file mode 100644 index 0000000..f174673 --- /dev/null +++ b/scss/bs4/mixins/_visibility.scss @@ -0,0 +1,8 @@ +// stylelint-disable declaration-no-important + +// Visibility + +@mixin invisible($visibility) { + visibility: $visibility !important; + @include deprecate("`invisible()`", "v4.3.0", "v5"); +} diff --git a/scss/bs4/utilities/_align.scss b/scss/bs4/utilities/_align.scss new file mode 100644 index 0000000..8b7df9f --- /dev/null +++ b/scss/bs4/utilities/_align.scss @@ -0,0 +1,8 @@ +// stylelint-disable declaration-no-important + +.align-baseline { vertical-align: baseline !important; } // Browser default +.align-top { vertical-align: top !important; } +.align-middle { vertical-align: middle !important; } +.align-bottom { vertical-align: bottom !important; } +.align-text-bottom { vertical-align: text-bottom !important; } +.align-text-top { vertical-align: text-top !important; } diff --git a/scss/bs4/utilities/_background.scss b/scss/bs4/utilities/_background.scss new file mode 100644 index 0000000..3accbc4 --- /dev/null +++ b/scss/bs4/utilities/_background.scss @@ -0,0 +1,19 @@ +// stylelint-disable declaration-no-important + +@each $color, $value in $theme-colors { + @include bg-variant(".bg-#{$color}", $value, true); +} + +@if $enable-gradients { + @each $color, $value in $theme-colors { + @include bg-gradient-variant(".bg-gradient-#{$color}", $value, true); + } +} + +.bg-white { + background-color: $white !important; +} + +.bg-transparent { + background-color: transparent !important; +} diff --git a/scss/bs4/utilities/_borders.scss b/scss/bs4/utilities/_borders.scss new file mode 100644 index 0000000..205f3fc --- /dev/null +++ b/scss/bs4/utilities/_borders.scss @@ -0,0 +1,75 @@ +// stylelint-disable property-disallowed-list, declaration-no-important + +// +// Border +// + +.border { border: $border-width solid $border-color !important; } +.border-top { border-top: $border-width solid $border-color !important; } +.border-right { border-right: $border-width solid $border-color !important; } +.border-bottom { border-bottom: $border-width solid $border-color !important; } +.border-left { border-left: $border-width solid $border-color !important; } + +.border-0 { border: 0 !important; } +.border-top-0 { border-top: 0 !important; } +.border-right-0 { border-right: 0 !important; } +.border-bottom-0 { border-bottom: 0 !important; } +.border-left-0 { border-left: 0 !important; } + +@each $color, $value in $theme-colors { + .border-#{$color} { + border-color: $value !important; + } +} + +.border-white { + border-color: $white !important; +} + +// +// Border-radius +// + +.rounded-sm { + border-radius: $border-radius-sm !important; +} + +.rounded { + border-radius: $border-radius !important; +} + +.rounded-top { + border-top-left-radius: $border-radius !important; + border-top-right-radius: $border-radius !important; +} + +.rounded-right { + border-top-right-radius: $border-radius !important; + border-bottom-right-radius: $border-radius !important; +} + +.rounded-bottom { + border-bottom-right-radius: $border-radius !important; + border-bottom-left-radius: $border-radius !important; +} + +.rounded-left { + border-top-left-radius: $border-radius !important; + border-bottom-left-radius: $border-radius !important; +} + +.rounded-lg { + border-radius: $border-radius-lg !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: $rounded-pill !important; +} + +.rounded-0 { + border-radius: 0 !important; +} diff --git a/scss/bs4/utilities/_clearfix.scss b/scss/bs4/utilities/_clearfix.scss new file mode 100644 index 0000000..e92522a --- /dev/null +++ b/scss/bs4/utilities/_clearfix.scss @@ -0,0 +1,3 @@ +.clearfix { + @include clearfix(); +} diff --git a/scss/bs4/utilities/_display.scss b/scss/bs4/utilities/_display.scss new file mode 100644 index 0000000..1303679 --- /dev/null +++ b/scss/bs4/utilities/_display.scss @@ -0,0 +1,26 @@ +// stylelint-disable declaration-no-important + +// +// Utilities for common `display` values +// + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + @each $value in $displays { + .d#{$infix}-#{$value} { display: $value !important; } + } + } +} + + +// +// Utilities for toggling `display` in print +// + +@media print { + @each $value in $displays { + .d-print-#{$value} { display: $value !important; } + } +} diff --git a/scss/bs4/utilities/_embed.scss b/scss/bs4/utilities/_embed.scss new file mode 100644 index 0000000..e37465e --- /dev/null +++ b/scss/bs4/utilities/_embed.scss @@ -0,0 +1,39 @@ +// Credit: Nicolas Gallagher and SUIT CSS. + +.embed-responsive { + position: relative; + display: block; + width: 100%; + padding: 0; + overflow: hidden; + + &::before { + display: block; + content: ""; + } + + .embed-responsive-item, + iframe, + embed, + object, + video { + position: absolute; + top: 0; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + border: 0; + } +} + +@each $embed-responsive-aspect-ratio in $embed-responsive-aspect-ratios { + $embed-responsive-aspect-ratio-x: nth($embed-responsive-aspect-ratio, 1); + $embed-responsive-aspect-ratio-y: nth($embed-responsive-aspect-ratio, 2); + + .embed-responsive-#{$embed-responsive-aspect-ratio-x}by#{$embed-responsive-aspect-ratio-y} { + &::before { + padding-top: percentage(divide($embed-responsive-aspect-ratio-y, $embed-responsive-aspect-ratio-x)); + } + } +} diff --git a/scss/bs4/utilities/_flex.scss b/scss/bs4/utilities/_flex.scss new file mode 100644 index 0000000..3d4266e --- /dev/null +++ b/scss/bs4/utilities/_flex.scss @@ -0,0 +1,51 @@ +// stylelint-disable declaration-no-important + +// Flex variation +// +// Custom styles for additional flex alignment options. + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .flex#{$infix}-row { flex-direction: row !important; } + .flex#{$infix}-column { flex-direction: column !important; } + .flex#{$infix}-row-reverse { flex-direction: row-reverse !important; } + .flex#{$infix}-column-reverse { flex-direction: column-reverse !important; } + + .flex#{$infix}-wrap { flex-wrap: wrap !important; } + .flex#{$infix}-nowrap { flex-wrap: nowrap !important; } + .flex#{$infix}-wrap-reverse { flex-wrap: wrap-reverse !important; } + .flex#{$infix}-fill { flex: 1 1 auto !important; } + .flex#{$infix}-grow-0 { flex-grow: 0 !important; } + .flex#{$infix}-grow-1 { flex-grow: 1 !important; } + .flex#{$infix}-shrink-0 { flex-shrink: 0 !important; } + .flex#{$infix}-shrink-1 { flex-shrink: 1 !important; } + + .justify-content#{$infix}-start { justify-content: flex-start !important; } + .justify-content#{$infix}-end { justify-content: flex-end !important; } + .justify-content#{$infix}-center { justify-content: center !important; } + .justify-content#{$infix}-between { justify-content: space-between !important; } + .justify-content#{$infix}-around { justify-content: space-around !important; } + + .align-items#{$infix}-start { align-items: flex-start !important; } + .align-items#{$infix}-end { align-items: flex-end !important; } + .align-items#{$infix}-center { align-items: center !important; } + .align-items#{$infix}-baseline { align-items: baseline !important; } + .align-items#{$infix}-stretch { align-items: stretch !important; } + + .align-content#{$infix}-start { align-content: flex-start !important; } + .align-content#{$infix}-end { align-content: flex-end !important; } + .align-content#{$infix}-center { align-content: center !important; } + .align-content#{$infix}-between { align-content: space-between !important; } + .align-content#{$infix}-around { align-content: space-around !important; } + .align-content#{$infix}-stretch { align-content: stretch !important; } + + .align-self#{$infix}-auto { align-self: auto !important; } + .align-self#{$infix}-start { align-self: flex-start !important; } + .align-self#{$infix}-end { align-self: flex-end !important; } + .align-self#{$infix}-center { align-self: center !important; } + .align-self#{$infix}-baseline { align-self: baseline !important; } + .align-self#{$infix}-stretch { align-self: stretch !important; } + } +} diff --git a/scss/bs4/utilities/_float.scss b/scss/bs4/utilities/_float.scss new file mode 100644 index 0000000..5425084 --- /dev/null +++ b/scss/bs4/utilities/_float.scss @@ -0,0 +1,11 @@ +// stylelint-disable declaration-no-important + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .float#{$infix}-left { float: left !important; } + .float#{$infix}-right { float: right !important; } + .float#{$infix}-none { float: none !important; } + } +} diff --git a/scss/bs4/utilities/_interactions.scss b/scss/bs4/utilities/_interactions.scss new file mode 100644 index 0000000..cc75fc2 --- /dev/null +++ b/scss/bs4/utilities/_interactions.scss @@ -0,0 +1,5 @@ +// stylelint-disable declaration-no-important + +@each $value in $user-selects { + .user-select-#{$value} { user-select: $value !important; } +} diff --git a/scss/bs4/utilities/_overflow.scss b/scss/bs4/utilities/_overflow.scss new file mode 100644 index 0000000..8326c30 --- /dev/null +++ b/scss/bs4/utilities/_overflow.scss @@ -0,0 +1,5 @@ +// stylelint-disable declaration-no-important + +@each $value in $overflows { + .overflow-#{$value} { overflow: $value !important; } +} diff --git a/scss/bs4/utilities/_position.scss b/scss/bs4/utilities/_position.scss new file mode 100644 index 0000000..cdf6c11 --- /dev/null +++ b/scss/bs4/utilities/_position.scss @@ -0,0 +1,32 @@ +// stylelint-disable declaration-no-important + +// Common values +@each $position in $positions { + .position-#{$position} { position: $position !important; } +} + +// Shorthand + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: $zindex-fixed; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: $zindex-fixed; +} + +.sticky-top { + @supports (position: sticky) { + position: sticky; + top: 0; + z-index: $zindex-sticky; + } +} diff --git a/scss/bs4/utilities/_screenreaders.scss b/scss/bs4/utilities/_screenreaders.scss new file mode 100644 index 0000000..9f26fde --- /dev/null +++ b/scss/bs4/utilities/_screenreaders.scss @@ -0,0 +1,11 @@ +// +// Screenreaders +// + +.sr-only { + @include sr-only(); +} + +.sr-only-focusable { + @include sr-only-focusable(); +} diff --git a/scss/bs4/utilities/_shadows.scss b/scss/bs4/utilities/_shadows.scss new file mode 100644 index 0000000..f5d03fc --- /dev/null +++ b/scss/bs4/utilities/_shadows.scss @@ -0,0 +1,6 @@ +// stylelint-disable declaration-no-important + +.shadow-sm { box-shadow: $box-shadow-sm !important; } +.shadow { box-shadow: $box-shadow !important; } +.shadow-lg { box-shadow: $box-shadow-lg !important; } +.shadow-none { box-shadow: none !important; } diff --git a/scss/bs4/utilities/_sizing.scss b/scss/bs4/utilities/_sizing.scss new file mode 100644 index 0000000..f376488 --- /dev/null +++ b/scss/bs4/utilities/_sizing.scss @@ -0,0 +1,20 @@ +// stylelint-disable declaration-no-important + +// Width and height + +@each $prop, $abbrev in (width: w, height: h) { + @each $size, $length in $sizes { + .#{$abbrev}-#{$size} { #{$prop}: $length !important; } + } +} + +.mw-100 { max-width: 100% !important; } +.mh-100 { max-height: 100% !important; } + +// Viewport additional helpers + +.min-vw-100 { min-width: 100vw !important; } +.min-vh-100 { min-height: 100vh !important; } + +.vw-100 { width: 100vw !important; } +.vh-100 { height: 100vh !important; } diff --git a/scss/bs4/utilities/_spacing.scss b/scss/bs4/utilities/_spacing.scss new file mode 100644 index 0000000..3e98581 --- /dev/null +++ b/scss/bs4/utilities/_spacing.scss @@ -0,0 +1,73 @@ +// stylelint-disable declaration-no-important + +// Margin and Padding + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + @each $prop, $abbrev in (margin: m, padding: p) { + @each $size, $length in $spacers { + .#{$abbrev}#{$infix}-#{$size} { #{$prop}: $length !important; } + .#{$abbrev}t#{$infix}-#{$size}, + .#{$abbrev}y#{$infix}-#{$size} { + #{$prop}-top: $length !important; + } + .#{$abbrev}r#{$infix}-#{$size}, + .#{$abbrev}x#{$infix}-#{$size} { + #{$prop}-right: $length !important; + } + .#{$abbrev}b#{$infix}-#{$size}, + .#{$abbrev}y#{$infix}-#{$size} { + #{$prop}-bottom: $length !important; + } + .#{$abbrev}l#{$infix}-#{$size}, + .#{$abbrev}x#{$infix}-#{$size} { + #{$prop}-left: $length !important; + } + } + } + + // Negative margins (e.g., where `.mb-n1` is negative version of `.mb-1`) + @each $size, $length in $spacers { + @if "#{$size}" != "0" { + .m#{$infix}-n#{$size} { margin: -$length !important; } + .mt#{$infix}-n#{$size}, + .my#{$infix}-n#{$size} { + margin-top: -$length !important; + } + .mr#{$infix}-n#{$size}, + .mx#{$infix}-n#{$size} { + margin-right: -$length !important; + } + .mb#{$infix}-n#{$size}, + .my#{$infix}-n#{$size} { + margin-bottom: -$length !important; + } + .ml#{$infix}-n#{$size}, + .mx#{$infix}-n#{$size} { + margin-left: -$length !important; + } + } + } + + // Some special margin utils + .m#{$infix}-auto { margin: auto !important; } + .mt#{$infix}-auto, + .my#{$infix}-auto { + margin-top: auto !important; + } + .mr#{$infix}-auto, + .mx#{$infix}-auto { + margin-right: auto !important; + } + .mb#{$infix}-auto, + .my#{$infix}-auto { + margin-bottom: auto !important; + } + .ml#{$infix}-auto, + .mx#{$infix}-auto { + margin-left: auto !important; + } + } +} diff --git a/scss/bs4/utilities/_stretched-link.scss b/scss/bs4/utilities/_stretched-link.scss new file mode 100644 index 0000000..fb5066b --- /dev/null +++ b/scss/bs4/utilities/_stretched-link.scss @@ -0,0 +1,19 @@ +// +// Stretched link +// + +.stretched-link { + &::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + // Just in case `pointer-events: none` is set on a parent + pointer-events: auto; + content: ""; + // IE10 bugfix, see https://stackoverflow.com/questions/16947967/ie10-hover-pseudo-class-doesnt-work-without-background-color + background-color: rgba(0, 0, 0, 0); + } +} diff --git a/scss/bs4/utilities/_text.scss b/scss/bs4/utilities/_text.scss new file mode 100644 index 0000000..3a9f83e --- /dev/null +++ b/scss/bs4/utilities/_text.scss @@ -0,0 +1,72 @@ +// stylelint-disable declaration-no-important + +// +// Text +// + +.text-monospace { font-family: $font-family-monospace !important; } + +// Alignment + +.text-justify { text-align: justify !important; } +.text-wrap { white-space: normal !important; } +.text-nowrap { white-space: nowrap !important; } +.text-truncate { @include text-truncate(); } + +// Responsive alignment + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .text#{$infix}-left { text-align: left !important; } + .text#{$infix}-right { text-align: right !important; } + .text#{$infix}-center { text-align: center !important; } + } +} + +// Transformation + +.text-lowercase { text-transform: lowercase !important; } +.text-uppercase { text-transform: uppercase !important; } +.text-capitalize { text-transform: capitalize !important; } + +// Weight and italics + +.font-weight-light { font-weight: $font-weight-light !important; } +.font-weight-lighter { font-weight: $font-weight-lighter !important; } +.font-weight-normal { font-weight: $font-weight-normal !important; } +.font-weight-bold { font-weight: $font-weight-bold !important; } +.font-weight-bolder { font-weight: $font-weight-bolder !important; } +.font-italic { font-style: italic !important; } + +// Contextual colors + +.text-white { color: $white !important; } + +@each $color, $value in $theme-colors { + @include text-emphasis-variant(".text-#{$color}", $value, true); +} + +.text-body { color: $body-color !important; } +.text-muted { color: $text-muted !important; } + +.text-black-50 { color: rgba($black, .5) !important; } +.text-white-50 { color: rgba($white, .5) !important; } + +// Misc + +.text-hide { + @include text-hide($ignore-warning: true); +} + +.text-decoration-none { text-decoration: none !important; } + +.text-break { + word-break: break-word !important; // Deprecated, but avoids issues with flex containers + word-wrap: break-word !important; // Used instead of `overflow-wrap` for IE & Edge Legacy +} + +// Reset + +.text-reset { color: inherit !important; } diff --git a/scss/bs4/utilities/_visibility.scss b/scss/bs4/utilities/_visibility.scss new file mode 100644 index 0000000..7756c3b --- /dev/null +++ b/scss/bs4/utilities/_visibility.scss @@ -0,0 +1,13 @@ +// stylelint-disable declaration-no-important + +// +// Visibility utilities +// + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} diff --git a/scss/bs5/README.md b/scss/bs5/README.md new file mode 100644 index 0000000..cb51a56 --- /dev/null +++ b/scss/bs5/README.md @@ -0,0 +1,246 @@ +

+ + Bootstrap logo + +

+ +

Bootstrap

+ +

+ Sleek, intuitive, and powerful front-end framework for faster and easier web development. +
+ Explore Bootstrap docs » +
+
+ Report bug + · + Request feature + · + Themes + · + Blog +

+ + +## Bootstrap 5 + +Our default branch is for development of our Bootstrap 5 release. Head to the [`v4-dev` branch](https://github.com/twbs/bootstrap/tree/v4-dev) to view the readme, documentation, and source code for Bootstrap 4. + + +## Table of contents + +- [Quick start](#quick-start) +- [Status](#status) +- [What's included](#whats-included) +- [Bugs and feature requests](#bugs-and-feature-requests) +- [Documentation](#documentation) +- [Contributing](#contributing) +- [Community](#community) +- [Versioning](#versioning) +- [Creators](#creators) +- [Thanks](#thanks) +- [Copyright and license](#copyright-and-license) + + +## Quick start + +Several quick start options are available: + +- [Download the latest release](https://github.com/twbs/bootstrap/archive/v5.3.3.zip) +- Clone the repo: `git clone https://github.com/twbs/bootstrap.git` +- Install with [npm](https://www.npmjs.com/): `npm install bootstrap@v5.3.3` +- Install with [yarn](https://yarnpkg.com/): `yarn add bootstrap@v5.3.3` +- Install with [Composer](https://getcomposer.org/): `composer require twbs/bootstrap:5.3.3` +- Install with [NuGet](https://www.nuget.org/): CSS: `Install-Package bootstrap` Sass: `Install-Package bootstrap.sass` + +Read the [Getting started page](https://getbootstrap.com/docs/5.3/getting-started/introduction/) for information on the framework contents, templates, examples, and more. + + +## Status + +[![Build Status](https://img.shields.io/github/actions/workflow/status/twbs/bootstrap/js.yml?branch=main&label=JS%20Tests&logo=github)](https://github.com/twbs/bootstrap/actions/workflows/js.yml?query=workflow%3AJS+branch%3Amain) +[![npm version](https://img.shields.io/npm/v/bootstrap?logo=npm&logoColor=fff)](https://www.npmjs.com/package/bootstrap) +[![Gem version](https://img.shields.io/gem/v/bootstrap?logo=rubygems&logoColor=fff)](https://rubygems.org/gems/bootstrap) +[![Meteor Atmosphere](https://img.shields.io/badge/meteor-twbs%3Abootstrap-blue?logo=meteor&logoColor=fff)](https://atmospherejs.com/twbs/bootstrap) +[![Packagist Prerelease](https://img.shields.io/packagist/vpre/twbs/bootstrap?logo=packagist&logoColor=fff)](https://packagist.org/packages/twbs/bootstrap) +[![NuGet](https://img.shields.io/nuget/vpre/bootstrap?logo=nuget&logoColor=fff)](https://www.nuget.org/packages/bootstrap/absoluteLatest) +[![Coverage Status](https://img.shields.io/coveralls/github/twbs/bootstrap/main?logo=coveralls&logoColor=fff)](https://coveralls.io/github/twbs/bootstrap?branch=main) +[![CSS gzip size](https://img.badgesize.io/twbs/bootstrap/main/dist/css/bootstrap.min.css?compression=gzip&label=CSS%20gzip%20size)](https://github.com/twbs/bootstrap/blob/main/dist/css/bootstrap.min.css) +[![CSS Brotli size](https://img.badgesize.io/twbs/bootstrap/main/dist/css/bootstrap.min.css?compression=brotli&label=CSS%20Brotli%20size)](https://github.com/twbs/bootstrap/blob/main/dist/css/bootstrap.min.css) +[![JS gzip size](https://img.badgesize.io/twbs/bootstrap/main/dist/js/bootstrap.min.js?compression=gzip&label=JS%20gzip%20size)](https://github.com/twbs/bootstrap/blob/main/dist/js/bootstrap.min.js) +[![JS Brotli size](https://img.badgesize.io/twbs/bootstrap/main/dist/js/bootstrap.min.js?compression=brotli&label=JS%20Brotli%20size)](https://github.com/twbs/bootstrap/blob/main/dist/js/bootstrap.min.js) +[![Backers on Open Collective](https://img.shields.io/opencollective/backers/bootstrap?logo=opencollective&logoColor=fff)](#backers) +[![Sponsors on Open Collective](https://img.shields.io/opencollective/sponsors/bootstrap?logo=opencollective&logoColor=fff)](#sponsors) + + +## What's included + +Within the download you'll find the following directories and files, logically grouping common assets and providing both compiled and minified variations. + +
+ Download contents + + ```text + bootstrap/ + ├── css/ + │ ├── bootstrap-grid.css + │ ├── bootstrap-grid.css.map + │ ├── bootstrap-grid.min.css + │ ├── bootstrap-grid.min.css.map + │ ├── bootstrap-grid.rtl.css + │ ├── bootstrap-grid.rtl.css.map + │ ├── bootstrap-grid.rtl.min.css + │ ├── bootstrap-grid.rtl.min.css.map + │ ├── bootstrap-reboot.css + │ ├── bootstrap-reboot.css.map + │ ├── bootstrap-reboot.min.css + │ ├── bootstrap-reboot.min.css.map + │ ├── bootstrap-reboot.rtl.css + │ ├── bootstrap-reboot.rtl.css.map + │ ├── bootstrap-reboot.rtl.min.css + │ ├── bootstrap-reboot.rtl.min.css.map + │ ├── bootstrap-utilities.css + │ ├── bootstrap-utilities.css.map + │ ├── bootstrap-utilities.min.css + │ ├── bootstrap-utilities.min.css.map + │ ├── bootstrap-utilities.rtl.css + │ ├── bootstrap-utilities.rtl.css.map + │ ├── bootstrap-utilities.rtl.min.css + │ ├── bootstrap-utilities.rtl.min.css.map + │ ├── bootstrap.css + │ ├── bootstrap.css.map + │ ├── bootstrap.min.css + │ ├── bootstrap.min.css.map + │ ├── bootstrap.rtl.css + │ ├── bootstrap.rtl.css.map + │ ├── bootstrap.rtl.min.css + │ └── bootstrap.rtl.min.css.map + └── js/ + ├── bootstrap.bundle.js + ├── bootstrap.bundle.js.map + ├── bootstrap.bundle.min.js + ├── bootstrap.bundle.min.js.map + ├── bootstrap.esm.js + ├── bootstrap.esm.js.map + ├── bootstrap.esm.min.js + ├── bootstrap.esm.min.js.map + ├── bootstrap.js + ├── bootstrap.js.map + ├── bootstrap.min.js + └── bootstrap.min.js.map + ``` +
+ +We provide compiled CSS and JS (`bootstrap.*`), as well as compiled and minified CSS and JS (`bootstrap.min.*`). [Source maps](https://developers.google.com/web/tools/chrome-devtools/javascript/source-maps) (`bootstrap.*.map`) are available for use with certain browsers' developer tools. Bundled JS files (`bootstrap.bundle.js` and minified `bootstrap.bundle.min.js`) include [Popper](https://popper.js.org/). + + +## Bugs and feature requests + +Have a bug or a feature request? Please first read the [issue guidelines](https://github.com/twbs/bootstrap/blob/main/.github/CONTRIBUTING.md#using-the-issue-tracker) and search for existing and closed issues. If your problem or idea is not addressed yet, [please open a new issue](https://github.com/twbs/bootstrap/issues/new/choose). + + +## Documentation + +Bootstrap's documentation, included in this repo in the root directory, is built with [Hugo](https://gohugo.io/) and publicly hosted on GitHub Pages at . The docs may also be run locally. + +Documentation search is powered by [Algolia's DocSearch](https://docsearch.algolia.com/). + +### Running documentation locally + +1. Run `npm install` to install the Node.js dependencies, including Hugo (the site builder). +2. Run `npm run test` (or a specific npm script) to rebuild distributed CSS and JavaScript files, as well as our docs assets. +3. From the root `/bootstrap` directory, run `npm run docs-serve` in the command line. +4. Open `http://localhost:9001/` in your browser, and voilà. + +Learn more about using Hugo by reading its [documentation](https://gohugo.io/documentation/). + +### Documentation for previous releases + +You can find all our previous releases docs on . + +[Previous releases](https://github.com/twbs/bootstrap/releases) and their documentation are also available for download. + + +## Contributing + +Please read through our [contributing guidelines](https://github.com/twbs/bootstrap/blob/main/.github/CONTRIBUTING.md). Included are directions for opening issues, coding standards, and notes on development. + +Moreover, if your pull request contains JavaScript patches or features, you must include [relevant unit tests](https://github.com/twbs/bootstrap/tree/main/js/tests). All HTML and CSS should conform to the [Code Guide](https://github.com/mdo/code-guide), maintained by [Mark Otto](https://github.com/mdo). + +Editor preferences are available in the [editor config](https://github.com/twbs/bootstrap/blob/main/.editorconfig) for easy use in common text editors. Read more and download plugins at . + + +## Community + +Get updates on Bootstrap's development and chat with the project maintainers and community members. + +- Follow [@getbootstrap on Twitter](https://twitter.com/getbootstrap). +- Read and subscribe to [The Official Bootstrap Blog](https://blog.getbootstrap.com/). +- Ask questions and explore [our GitHub Discussions](https://github.com/twbs/bootstrap/discussions). +- Discuss, ask questions, and more on [the community Discord](https://discord.gg/bZUvakRU3M) or [Bootstrap subreddit](https://reddit.com/r/bootstrap). +- Chat with fellow Bootstrappers in IRC. On the `irc.libera.chat` server, in the `#bootstrap` channel. +- Implementation help may be found at Stack Overflow (tagged [`bootstrap-5`](https://stackoverflow.com/questions/tagged/bootstrap-5)). +- Developers should use the keyword `bootstrap` on packages which modify or add to the functionality of Bootstrap when distributing through [npm](https://www.npmjs.com/browse/keyword/bootstrap) or similar delivery mechanisms for maximum discoverability. + + +## Versioning + +For transparency into our release cycle and in striving to maintain backward compatibility, Bootstrap is maintained under [the Semantic Versioning guidelines](https://semver.org/). Sometimes we screw up, but we adhere to those rules whenever possible. + +See [the Releases section of our GitHub project](https://github.com/twbs/bootstrap/releases) for changelogs for each release version of Bootstrap. Release announcement posts on [the official Bootstrap blog](https://blog.getbootstrap.com/) contain summaries of the most noteworthy changes made in each release. + + +## Creators + +**Mark Otto** + +- +- + +**Jacob Thornton** + +- +- + + +## Thanks + + + BrowserStack + + +Thanks to [BrowserStack](https://www.browserstack.com/) for providing the infrastructure that allows us to test in real browsers! + + + Netlify + + +Thanks to [Netlify](https://www.netlify.com/) for providing us with Deploy Previews! + + +## Sponsors + +Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/bootstrap#sponsor)] + +[![OC sponsor 0](https://opencollective.com/bootstrap/sponsor/0/avatar.svg)](https://opencollective.com/bootstrap/sponsor/0/website) +[![OC sponsor 1](https://opencollective.com/bootstrap/sponsor/1/avatar.svg)](https://opencollective.com/bootstrap/sponsor/1/website) +[![OC sponsor 2](https://opencollective.com/bootstrap/sponsor/2/avatar.svg)](https://opencollective.com/bootstrap/sponsor/2/website) +[![OC sponsor 3](https://opencollective.com/bootstrap/sponsor/3/avatar.svg)](https://opencollective.com/bootstrap/sponsor/3/website) +[![OC sponsor 4](https://opencollective.com/bootstrap/sponsor/4/avatar.svg)](https://opencollective.com/bootstrap/sponsor/4/website) +[![OC sponsor 5](https://opencollective.com/bootstrap/sponsor/5/avatar.svg)](https://opencollective.com/bootstrap/sponsor/5/website) +[![OC sponsor 6](https://opencollective.com/bootstrap/sponsor/6/avatar.svg)](https://opencollective.com/bootstrap/sponsor/6/website) +[![OC sponsor 7](https://opencollective.com/bootstrap/sponsor/7/avatar.svg)](https://opencollective.com/bootstrap/sponsor/7/website) +[![OC sponsor 8](https://opencollective.com/bootstrap/sponsor/8/avatar.svg)](https://opencollective.com/bootstrap/sponsor/8/website) +[![OC sponsor 9](https://opencollective.com/bootstrap/sponsor/9/avatar.svg)](https://opencollective.com/bootstrap/sponsor/9/website) + + +## Backers + +Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/bootstrap#backer)] + +[![Backers](https://opencollective.com/bootstrap/backers.svg?width=890)](https://opencollective.com/bootstrap#backers) + + +## Copyright and license + +Code and documentation copyright 2011–2024 the [Bootstrap Authors](https://github.com/twbs/bootstrap/graphs/contributors). Code released under the [MIT License](https://github.com/twbs/bootstrap/blob/main/LICENSE). Docs released under [Creative Commons](https://creativecommons.org/licenses/by/3.0/). diff --git a/scss/bs5/_functions.scss b/scss/bs5/_functions.scss new file mode 100644 index 0000000..9029658 --- /dev/null +++ b/scss/bs5/_functions.scss @@ -0,0 +1,302 @@ +// Bootstrap functions +// +// Utility mixins and functions for evaluating source code across our variables, maps, and mixins. + +// Ascending +// Used to evaluate Sass maps like our grid breakpoints. +@mixin _assert-ascending($map, $map-name) { + $prev-key: null; + $prev-num: null; + @each $key, $num in $map { + @if $prev-num == null or unit($num) == "%" or unit($prev-num) == "%" { + // Do nothing + } @else if not comparable($prev-num, $num) { + @warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !"; + } @else if $prev-num >= $num { + @warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !"; + } + $prev-key: $key; + $prev-num: $num; + } +} + +// Starts at zero +// Used to ensure the min-width of the lowest breakpoint starts at 0. +@mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") { + @if length($map) > 0 { + $values: map-values($map); + $first-value: nth($values, 1); + @if $first-value != 0 { + @warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}."; + } + } +} + +// Colors +@function to-rgb($value) { + @return red($value), green($value), blue($value); +} + +// stylelint-disable scss/dollar-variable-pattern +@function rgba-css-var($identifier, $target) { + @if $identifier == "body" and $target == "bg" { + @return rgba(var(--#{$prefix}#{$identifier}-bg-rgb), var(--#{$prefix}#{$target}-opacity)); + } @if $identifier == "body" and $target == "text" { + @return rgba(var(--#{$prefix}#{$identifier}-color-rgb), var(--#{$prefix}#{$target}-opacity)); + } @else { + @return rgba(var(--#{$prefix}#{$identifier}-rgb), var(--#{$prefix}#{$target}-opacity)); + } +} + +@function map-loop($map, $func, $args...) { + $_map: (); + + @each $key, $value in $map { + // allow to pass the $key and $value of the map as an function argument + $_args: (); + @each $arg in $args { + $_args: append($_args, if($arg == "$key", $key, if($arg == "$value", $value, $arg))); + } + + $_map: map-merge($_map, ($key: call(get-function($func), $_args...))); + } + + @return $_map; +} +// stylelint-enable scss/dollar-variable-pattern + +@function varify($list) { + $result: null; + @each $entry in $list { + $result: append($result, var(--#{$prefix}#{$entry}), space); + } + @return $result; +} + +// Internal Bootstrap function to turn maps into its negative variant. +// It prefixes the keys with `n` and makes the value negative. +@function negativify-map($map) { + $result: (); + @each $key, $value in $map { + @if $key != 0 { + $result: map-merge($result, ("n" + $key: (-$value))); + } + } + @return $result; +} + +// Get multiple keys from a sass map +@function map-get-multiple($map, $values) { + $result: (); + @each $key, $value in $map { + @if (index($values, $key) != null) { + $result: map-merge($result, ($key: $value)); + } + } + @return $result; +} + +// Merge multiple maps +@function map-merge-multiple($maps...) { + $merged-maps: (); + + @each $map in $maps { + $merged-maps: map-merge($merged-maps, $map); + } + @return $merged-maps; +} + +// Replace `$search` with `$replace` in `$string` +// Used on our SVG icon backgrounds for custom forms. +// +// @author Kitty Giraudel +// @param {String} $string - Initial string +// @param {String} $search - Substring to replace +// @param {String} $replace ('') - New value +// @return {String} - Updated string +@function str-replace($string, $search, $replace: "") { + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); + } + + @return $string; +} + +// See https://codepen.io/kevinweber/pen/dXWoRw +// +// Requires the use of quotes around data URIs. + +@function escape-svg($string) { + @if str-index($string, "data:image/svg+xml") { + @each $char, $encoded in $escaped-characters { + // Do not escape the url brackets + @if str-index($string, "url(") == 1 { + $string: url("#{str-replace(str-slice($string, 6, -3), $char, $encoded)}"); + } @else { + $string: str-replace($string, $char, $encoded); + } + } + } + + @return $string; +} + +// Color contrast +// See https://github.com/twbs/bootstrap/pull/30168 + +// A list of pre-calculated numbers of pow(divide((divide($value, 255) + .055), 1.055), 2.4). (from 0 to 255) +// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern +$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0123 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1; + +@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) { + $foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black; + $max-ratio: 0; + $max-ratio-color: null; + + @each $color in $foregrounds { + $contrast-ratio: contrast-ratio($background, $color); + @if $contrast-ratio > $min-contrast-ratio { + @return $color; + } @else if $contrast-ratio > $max-ratio { + $max-ratio: $contrast-ratio; + $max-ratio-color: $color; + } + } + + @warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}..."; + + @return $max-ratio-color; +} + +@function contrast-ratio($background, $foreground: $color-contrast-light) { + $l1: luminance($background); + $l2: luminance(opaque($background, $foreground)); + + @return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05)); +} + +// Return WCAG2.1 relative luminance +// See https://www.w3.org/TR/WCAG/#dfn-relative-luminance +// See https://www.w3.org/TR/WCAG/#dfn-contrast-ratio +@function luminance($color) { + $rgb: ( + "r": red($color), + "g": green($color), + "b": blue($color) + ); + + @each $name, $value in $rgb { + $value: if(divide($value, 255) < .04045, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1)); + $rgb: map-merge($rgb, ($name: $value)); + } + + @return (map-get($rgb, "r") * .2126) + (map-get($rgb, "g") * .7152) + (map-get($rgb, "b") * .0722); +} + +// Return opaque color +// opaque(#fff, rgba(0, 0, 0, .5)) => #808080 +@function opaque($background, $foreground) { + @return mix(rgba($foreground, 1), $background, opacity($foreground) * 100%); +} + +// scss-docs-start color-functions +// Tint a color: mix a color with white +@function tint-color($color, $weight) { + @return mix(white, $color, $weight); +} + +// Shade a color: mix a color with black +@function shade-color($color, $weight) { + @return mix(black, $color, $weight); +} + +// Shade the color if the weight is positive, else tint it +@function shift-color($color, $weight) { + @return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight)); +} +// scss-docs-end color-functions + +// Return valid calc +@function add($value1, $value2, $return-calc: true) { + @if $value1 == null { + @return $value2; + } + + @if $value2 == null { + @return $value1; + } + + @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { + @return $value1 + $value2; + } + + @return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2); +} + +@function subtract($value1, $value2, $return-calc: true) { + @if $value1 == null and $value2 == null { + @return null; + } + + @if $value1 == null { + @return -$value2; + } + + @if $value2 == null { + @return $value1; + } + + @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { + @return $value1 - $value2; + } + + @if type-of($value2) != number { + $value2: unquote("(") + $value2 + unquote(")"); + } + + @return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2); +} + +@function divide($dividend, $divisor, $precision: 10) { + $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1); + $dividend: abs($dividend); + $divisor: abs($divisor); + @if $dividend == 0 { + @return 0; + } + @if $divisor == 0 { + @error "Cannot divide by 0"; + } + $remainder: $dividend; + $result: 0; + $factor: 10; + @while ($remainder > 0 and $precision >= 0) { + $quotient: 0; + @while ($remainder >= $divisor) { + $remainder: $remainder - $divisor; + $quotient: $quotient + 1; + } + $result: $result * 10 + $quotient; + $factor: $factor * .1; + $remainder: $remainder * 10; + $precision: $precision - 1; + @if ($precision < 0 and $remainder >= $divisor * 5) { + $result: $result + 1; + } + } + $result: $result * $factor * $sign; + $dividend-unit: unit($dividend); + $divisor-unit: unit($divisor); + $unit-map: ( + "px": 1px, + "rem": 1rem, + "em": 1em, + "%": 1% + ); + @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) { + $result: $result * map-get($unit-map, $dividend-unit); + } + @return $result; +} diff --git a/scss/bs5/_grid.scss b/scss/bs5/_grid.scss new file mode 100644 index 0000000..048f800 --- /dev/null +++ b/scss/bs5/_grid.scss @@ -0,0 +1,39 @@ +// Row +// +// Rows contain your columns. + +:root { + @each $name, $value in $grid-breakpoints { + --#{$prefix}breakpoint-#{$name}: #{$value}; + } +} + +@if $enable-grid-classes { + .row { + @include make-row(); + + > * { + @include make-col-ready(); + } + } +} + +@if $enable-cssgrid { + .grid { + display: grid; + grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr); + grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr); + gap: var(--#{$prefix}gap, #{$grid-gutter-width}); + + @include make-cssgrid(); + } +} + + +// Columns +// +// Common styles for small and large grid columns + +@if $enable-grid-classes { + @include make-grid-columns(); +} diff --git a/scss/bs5/_images.scss b/scss/bs5/_images.scss new file mode 100644 index 0000000..3d6a101 --- /dev/null +++ b/scss/bs5/_images.scss @@ -0,0 +1,42 @@ +// Responsive images (ensure images don't scale beyond their parents) +// +// This is purposefully opt-in via an explicit class rather than being the default for all ``s. +// We previously tried the "images are responsive by default" approach in Bootstrap v2, +// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps) +// which weren't expecting the images within themselves to be involuntarily resized. +// See also https://github.com/twbs/bootstrap/issues/18178 +.img-fluid { + @include img-fluid(); +} + + +// Image thumbnails +.img-thumbnail { + padding: $thumbnail-padding; + background-color: $thumbnail-bg; + border: $thumbnail-border-width solid $thumbnail-border-color; + @include border-radius($thumbnail-border-radius); + @include box-shadow($thumbnail-box-shadow); + + // Keep them at most 100% wide + @include img-fluid(); +} + +// +// Figures +// + +.figure { + // Ensures the caption's text aligns with the image. + display: inline-block; +} + +.figure-img { + margin-bottom: $spacer * .5; + line-height: 1; +} + +.figure-caption { + @include font-size($figure-caption-font-size); + color: $figure-caption-color; +} diff --git a/scss/bs5/_mixins.scss b/scss/bs5/_mixins.scss new file mode 100644 index 0000000..e1e130b --- /dev/null +++ b/scss/bs5/_mixins.scss @@ -0,0 +1,42 @@ +// Toggles +// +// Used in conjunction with global variables to enable certain theme features. + +// Vendor +@import "vendor/rfs"; + +// Deprecate +@import "mixins/deprecate"; + +// Helpers +@import "mixins/breakpoints"; +@import "mixins/color-mode"; +@import "mixins/color-scheme"; +@import "mixins/image"; +@import "mixins/resize"; +@import "mixins/visually-hidden"; +@import "mixins/reset-text"; +@import "mixins/text-truncate"; + +// Utilities +@import "mixins/utilities"; + +// Components +@import "mixins/backdrop"; +@import "mixins/buttons"; +@import "mixins/caret"; +@import "mixins/pagination"; +@import "mixins/lists"; +@import "mixins/forms"; +@import "mixins/table-variants"; + +// Skins +@import "mixins/border-radius"; +@import "mixins/box-shadow"; +@import "mixins/gradients"; +@import "mixins/transition"; + +// Layout +@import "mixins/clearfix"; +@import "mixins/container"; +@import "mixins/grid"; diff --git a/scss/bs5/_variables-dark.scss b/scss/bs5/_variables-dark.scss new file mode 100644 index 0000000..6422b38 --- /dev/null +++ b/scss/bs5/_variables-dark.scss @@ -0,0 +1,87 @@ +// Dark color mode variables +// +// Custom variables for the `[data-bs-theme="dark"]` theme. Use this as a starting point for your own custom color modes by creating a new theme-specific file like `_variables-dark.scss` and adding the variables you need. + +// +// Global colors +// + +// scss-docs-start sass-dark-mode-vars +// scss-docs-start theme-text-dark-variables +$primary-text-emphasis-dark: tint-color($primary, 40%) !default; +$secondary-text-emphasis-dark: tint-color($secondary, 40%) !default; +$success-text-emphasis-dark: tint-color($success, 40%) !default; +$info-text-emphasis-dark: tint-color($info, 40%) !default; +$warning-text-emphasis-dark: tint-color($warning, 40%) !default; +$danger-text-emphasis-dark: tint-color($danger, 40%) !default; +$light-text-emphasis-dark: $gray-100 !default; +$dark-text-emphasis-dark: $gray-300 !default; +// scss-docs-end theme-text-dark-variables + +// scss-docs-start theme-bg-subtle-dark-variables +$primary-bg-subtle-dark: shade-color($primary, 80%) !default; +$secondary-bg-subtle-dark: shade-color($secondary, 80%) !default; +$success-bg-subtle-dark: shade-color($success, 80%) !default; +$info-bg-subtle-dark: shade-color($info, 80%) !default; +$warning-bg-subtle-dark: shade-color($warning, 80%) !default; +$danger-bg-subtle-dark: shade-color($danger, 80%) !default; +$light-bg-subtle-dark: $gray-800 !default; +$dark-bg-subtle-dark: mix($gray-800, $black) !default; +// scss-docs-end theme-bg-subtle-dark-variables + +// scss-docs-start theme-border-subtle-dark-variables +$primary-border-subtle-dark: shade-color($primary, 40%) !default; +$secondary-border-subtle-dark: shade-color($secondary, 40%) !default; +$success-border-subtle-dark: shade-color($success, 40%) !default; +$info-border-subtle-dark: shade-color($info, 40%) !default; +$warning-border-subtle-dark: shade-color($warning, 40%) !default; +$danger-border-subtle-dark: shade-color($danger, 40%) !default; +$light-border-subtle-dark: $gray-700 !default; +$dark-border-subtle-dark: $gray-800 !default; +// scss-docs-end theme-border-subtle-dark-variables + +$body-color-dark: $gray-300 !default; +$body-bg-dark: $gray-900 !default; +$body-secondary-color-dark: rgba($body-color-dark, .75) !default; +$body-secondary-bg-dark: $gray-800 !default; +$body-tertiary-color-dark: rgba($body-color-dark, .5) !default; +$body-tertiary-bg-dark: mix($gray-800, $gray-900, 50%) !default; +$body-emphasis-color-dark: $white !default; +$border-color-dark: $gray-700 !default; +$border-color-translucent-dark: rgba($white, .15) !default; +$headings-color-dark: inherit !default; +$link-color-dark: tint-color($primary, 40%) !default; +$link-hover-color-dark: shift-color($link-color-dark, -$link-shade-percentage) !default; +$code-color-dark: tint-color($code-color, 40%) !default; +$mark-color-dark: $body-color-dark !default; +$mark-bg-dark: $yellow-800 !default; + + +// +// Forms +// + +$form-select-indicator-color-dark: $body-color-dark !default; +$form-select-indicator-dark: url("data:image/svg+xml,") !default; + +$form-switch-color-dark: rgba($white, .25) !default; +$form-switch-bg-image-dark: url("data:image/svg+xml,") !default; + +// scss-docs-start form-validation-colors-dark +$form-valid-color-dark: $green-300 !default; +$form-valid-border-color-dark: $green-300 !default; +$form-invalid-color-dark: $red-300 !default; +$form-invalid-border-color-dark: $red-300 !default; +// scss-docs-end form-validation-colors-dark + + +// +// Accordion +// + +$accordion-icon-color-dark: $primary-text-emphasis-dark !default; +$accordion-icon-active-color-dark: $primary-text-emphasis-dark !default; + +$accordion-button-icon-dark: url("data:image/svg+xml,") !default; +$accordion-button-active-icon-dark: url("data:image/svg+xml,") !default; +// scss-docs-end sass-dark-mode-vars diff --git a/scss/bs5/_variables.scss b/scss/bs5/_variables.scss new file mode 100644 index 0000000..0653139 --- /dev/null +++ b/scss/bs5/_variables.scss @@ -0,0 +1,1751 @@ +// Variables +// +// Variables should follow the `$component-state-property-size` formula for +// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. + +// Color system + +// scss-docs-start gray-color-variables +$white: #fff !default; +$gray-100: #f8f9fa !default; +$gray-200: #e9ecef !default; +$gray-300: #dee2e6 !default; +$gray-400: #ced4da !default; +$gray-500: #adb5bd !default; +$gray-600: #6c757d !default; +$gray-700: #495057 !default; +$gray-800: #343a40 !default; +$gray-900: #212529 !default; +$black: #000 !default; +// scss-docs-end gray-color-variables + +// fusv-disable +// scss-docs-start gray-colors-map +$grays: ( + "100": $gray-100, + "200": $gray-200, + "300": $gray-300, + "400": $gray-400, + "500": $gray-500, + "600": $gray-600, + "700": $gray-700, + "800": $gray-800, + "900": $gray-900 +) !default; +// scss-docs-end gray-colors-map +// fusv-enable + +// scss-docs-start color-variables +$blue: #0d6efd !default; +$indigo: #6610f2 !default; +$purple: #6f42c1 !default; +$pink: #d63384 !default; +$red: #dc3545 !default; +$orange: #fd7e14 !default; +$yellow: #ffc107 !default; +$green: #198754 !default; +$teal: #20c997 !default; +$cyan: #0dcaf0 !default; +// scss-docs-end color-variables + +// scss-docs-start colors-map +$colors: ( + "blue": $blue, + "indigo": $indigo, + "purple": $purple, + "pink": $pink, + "red": $red, + "orange": $orange, + "yellow": $yellow, + "green": $green, + "teal": $teal, + "cyan": $cyan, + "black": $black, + "white": $white, + "gray": $gray-600, + "gray-dark": $gray-800 +) !default; +// scss-docs-end colors-map + +// The contrast ratio to reach against white, to determine if color changes from "light" to "dark". Acceptable values for WCAG 2.0 are 3, 4.5 and 7. +// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast +$min-contrast-ratio: 4.5 !default; + +// Customize the light and dark text colors for use in our color contrast function. +$color-contrast-dark: $black !default; +$color-contrast-light: $white !default; + +// fusv-disable +$blue-100: tint-color($blue, 80%) !default; +$blue-200: tint-color($blue, 60%) !default; +$blue-300: tint-color($blue, 40%) !default; +$blue-400: tint-color($blue, 20%) !default; +$blue-500: $blue !default; +$blue-600: shade-color($blue, 20%) !default; +$blue-700: shade-color($blue, 40%) !default; +$blue-800: shade-color($blue, 60%) !default; +$blue-900: shade-color($blue, 80%) !default; + +$indigo-100: tint-color($indigo, 80%) !default; +$indigo-200: tint-color($indigo, 60%) !default; +$indigo-300: tint-color($indigo, 40%) !default; +$indigo-400: tint-color($indigo, 20%) !default; +$indigo-500: $indigo !default; +$indigo-600: shade-color($indigo, 20%) !default; +$indigo-700: shade-color($indigo, 40%) !default; +$indigo-800: shade-color($indigo, 60%) !default; +$indigo-900: shade-color($indigo, 80%) !default; + +$purple-100: tint-color($purple, 80%) !default; +$purple-200: tint-color($purple, 60%) !default; +$purple-300: tint-color($purple, 40%) !default; +$purple-400: tint-color($purple, 20%) !default; +$purple-500: $purple !default; +$purple-600: shade-color($purple, 20%) !default; +$purple-700: shade-color($purple, 40%) !default; +$purple-800: shade-color($purple, 60%) !default; +$purple-900: shade-color($purple, 80%) !default; + +$pink-100: tint-color($pink, 80%) !default; +$pink-200: tint-color($pink, 60%) !default; +$pink-300: tint-color($pink, 40%) !default; +$pink-400: tint-color($pink, 20%) !default; +$pink-500: $pink !default; +$pink-600: shade-color($pink, 20%) !default; +$pink-700: shade-color($pink, 40%) !default; +$pink-800: shade-color($pink, 60%) !default; +$pink-900: shade-color($pink, 80%) !default; + +$red-100: tint-color($red, 80%) !default; +$red-200: tint-color($red, 60%) !default; +$red-300: tint-color($red, 40%) !default; +$red-400: tint-color($red, 20%) !default; +$red-500: $red !default; +$red-600: shade-color($red, 20%) !default; +$red-700: shade-color($red, 40%) !default; +$red-800: shade-color($red, 60%) !default; +$red-900: shade-color($red, 80%) !default; + +$orange-100: tint-color($orange, 80%) !default; +$orange-200: tint-color($orange, 60%) !default; +$orange-300: tint-color($orange, 40%) !default; +$orange-400: tint-color($orange, 20%) !default; +$orange-500: $orange !default; +$orange-600: shade-color($orange, 20%) !default; +$orange-700: shade-color($orange, 40%) !default; +$orange-800: shade-color($orange, 60%) !default; +$orange-900: shade-color($orange, 80%) !default; + +$yellow-100: tint-color($yellow, 80%) !default; +$yellow-200: tint-color($yellow, 60%) !default; +$yellow-300: tint-color($yellow, 40%) !default; +$yellow-400: tint-color($yellow, 20%) !default; +$yellow-500: $yellow !default; +$yellow-600: shade-color($yellow, 20%) !default; +$yellow-700: shade-color($yellow, 40%) !default; +$yellow-800: shade-color($yellow, 60%) !default; +$yellow-900: shade-color($yellow, 80%) !default; + +$green-100: tint-color($green, 80%) !default; +$green-200: tint-color($green, 60%) !default; +$green-300: tint-color($green, 40%) !default; +$green-400: tint-color($green, 20%) !default; +$green-500: $green !default; +$green-600: shade-color($green, 20%) !default; +$green-700: shade-color($green, 40%) !default; +$green-800: shade-color($green, 60%) !default; +$green-900: shade-color($green, 80%) !default; + +$teal-100: tint-color($teal, 80%) !default; +$teal-200: tint-color($teal, 60%) !default; +$teal-300: tint-color($teal, 40%) !default; +$teal-400: tint-color($teal, 20%) !default; +$teal-500: $teal !default; +$teal-600: shade-color($teal, 20%) !default; +$teal-700: shade-color($teal, 40%) !default; +$teal-800: shade-color($teal, 60%) !default; +$teal-900: shade-color($teal, 80%) !default; + +$cyan-100: tint-color($cyan, 80%) !default; +$cyan-200: tint-color($cyan, 60%) !default; +$cyan-300: tint-color($cyan, 40%) !default; +$cyan-400: tint-color($cyan, 20%) !default; +$cyan-500: $cyan !default; +$cyan-600: shade-color($cyan, 20%) !default; +$cyan-700: shade-color($cyan, 40%) !default; +$cyan-800: shade-color($cyan, 60%) !default; +$cyan-900: shade-color($cyan, 80%) !default; + +$blues: ( + "blue-100": $blue-100, + "blue-200": $blue-200, + "blue-300": $blue-300, + "blue-400": $blue-400, + "blue-500": $blue-500, + "blue-600": $blue-600, + "blue-700": $blue-700, + "blue-800": $blue-800, + "blue-900": $blue-900 +) !default; + +$indigos: ( + "indigo-100": $indigo-100, + "indigo-200": $indigo-200, + "indigo-300": $indigo-300, + "indigo-400": $indigo-400, + "indigo-500": $indigo-500, + "indigo-600": $indigo-600, + "indigo-700": $indigo-700, + "indigo-800": $indigo-800, + "indigo-900": $indigo-900 +) !default; + +$purples: ( + "purple-100": $purple-100, + "purple-200": $purple-200, + "purple-300": $purple-300, + "purple-400": $purple-400, + "purple-500": $purple-500, + "purple-600": $purple-600, + "purple-700": $purple-700, + "purple-800": $purple-800, + "purple-900": $purple-900 +) !default; + +$pinks: ( + "pink-100": $pink-100, + "pink-200": $pink-200, + "pink-300": $pink-300, + "pink-400": $pink-400, + "pink-500": $pink-500, + "pink-600": $pink-600, + "pink-700": $pink-700, + "pink-800": $pink-800, + "pink-900": $pink-900 +) !default; + +$reds: ( + "red-100": $red-100, + "red-200": $red-200, + "red-300": $red-300, + "red-400": $red-400, + "red-500": $red-500, + "red-600": $red-600, + "red-700": $red-700, + "red-800": $red-800, + "red-900": $red-900 +) !default; + +$oranges: ( + "orange-100": $orange-100, + "orange-200": $orange-200, + "orange-300": $orange-300, + "orange-400": $orange-400, + "orange-500": $orange-500, + "orange-600": $orange-600, + "orange-700": $orange-700, + "orange-800": $orange-800, + "orange-900": $orange-900 +) !default; + +$yellows: ( + "yellow-100": $yellow-100, + "yellow-200": $yellow-200, + "yellow-300": $yellow-300, + "yellow-400": $yellow-400, + "yellow-500": $yellow-500, + "yellow-600": $yellow-600, + "yellow-700": $yellow-700, + "yellow-800": $yellow-800, + "yellow-900": $yellow-900 +) !default; + +$greens: ( + "green-100": $green-100, + "green-200": $green-200, + "green-300": $green-300, + "green-400": $green-400, + "green-500": $green-500, + "green-600": $green-600, + "green-700": $green-700, + "green-800": $green-800, + "green-900": $green-900 +) !default; + +$teals: ( + "teal-100": $teal-100, + "teal-200": $teal-200, + "teal-300": $teal-300, + "teal-400": $teal-400, + "teal-500": $teal-500, + "teal-600": $teal-600, + "teal-700": $teal-700, + "teal-800": $teal-800, + "teal-900": $teal-900 +) !default; + +$cyans: ( + "cyan-100": $cyan-100, + "cyan-200": $cyan-200, + "cyan-300": $cyan-300, + "cyan-400": $cyan-400, + "cyan-500": $cyan-500, + "cyan-600": $cyan-600, + "cyan-700": $cyan-700, + "cyan-800": $cyan-800, + "cyan-900": $cyan-900 +) !default; +// fusv-enable + +// scss-docs-start theme-color-variables +$primary: $blue !default; +$secondary: $gray-600 !default; +$success: $green !default; +$info: $cyan !default; +$warning: $yellow !default; +$danger: $red !default; +$light: $gray-100 !default; +$dark: $gray-900 !default; +// scss-docs-end theme-color-variables + +// scss-docs-start theme-colors-map +$theme-colors: ( + "primary": $primary, + "secondary": $secondary, + "success": $success, + "info": $info, + "warning": $warning, + "danger": $danger, + "light": $light, + "dark": $dark +) !default; +// scss-docs-end theme-colors-map + +// scss-docs-start theme-text-variables +$primary-text-emphasis: shade-color($primary, 60%) !default; +$secondary-text-emphasis: shade-color($secondary, 60%) !default; +$success-text-emphasis: shade-color($success, 60%) !default; +$info-text-emphasis: shade-color($info, 60%) !default; +$warning-text-emphasis: shade-color($warning, 60%) !default; +$danger-text-emphasis: shade-color($danger, 60%) !default; +$light-text-emphasis: $gray-700 !default; +$dark-text-emphasis: $gray-700 !default; +// scss-docs-end theme-text-variables + +// scss-docs-start theme-bg-subtle-variables +$primary-bg-subtle: tint-color($primary, 80%) !default; +$secondary-bg-subtle: tint-color($secondary, 80%) !default; +$success-bg-subtle: tint-color($success, 80%) !default; +$info-bg-subtle: tint-color($info, 80%) !default; +$warning-bg-subtle: tint-color($warning, 80%) !default; +$danger-bg-subtle: tint-color($danger, 80%) !default; +$light-bg-subtle: mix($gray-100, $white) !default; +$dark-bg-subtle: $gray-400 !default; +// scss-docs-end theme-bg-subtle-variables + +// scss-docs-start theme-border-subtle-variables +$primary-border-subtle: tint-color($primary, 60%) !default; +$secondary-border-subtle: tint-color($secondary, 60%) !default; +$success-border-subtle: tint-color($success, 60%) !default; +$info-border-subtle: tint-color($info, 60%) !default; +$warning-border-subtle: tint-color($warning, 60%) !default; +$danger-border-subtle: tint-color($danger, 60%) !default; +$light-border-subtle: $gray-200 !default; +$dark-border-subtle: $gray-500 !default; +// scss-docs-end theme-border-subtle-variables + +// Characters which are escaped by the escape-svg function +$escaped-characters: ( + ("<", "%3c"), + (">", "%3e"), + ("#", "%23"), + ("(", "%28"), + (")", "%29"), +) !default; + +// Options +// +// Quickly modify global styling by enabling or disabling optional features. + +$enable-caret: true !default; +$enable-rounded: true !default; +$enable-shadows: false !default; +$enable-gradients: false !default; +$enable-transitions: true !default; +$enable-reduced-motion: true !default; +$enable-smooth-scroll: true !default; +$enable-grid-classes: true !default; +$enable-container-classes: true !default; +$enable-cssgrid: false !default; +$enable-button-pointers: true !default; +$enable-rfs: true !default; +$enable-validation-icons: true !default; +$enable-negative-margins: false !default; +$enable-deprecation-messages: true !default; +$enable-important-utilities: true !default; + +$enable-dark-mode: true !default; +$color-mode-type: data !default; // `data` or `media-query` + +// Prefix for :root CSS variables + +$variable-prefix: bs- !default; // Deprecated in v5.2.0 for the shorter `$prefix` +$prefix: $variable-prefix !default; + +// Gradient +// +// The gradient which is added to components if `$enable-gradients` is `true` +// This gradient is also added to elements with `.bg-gradient` +// scss-docs-start variable-gradient +$gradient: linear-gradient(180deg, rgba($white, .15), rgba($white, 0)) !default; +// scss-docs-end variable-gradient + +// Spacing +// +// Control the default styling of most Bootstrap elements by modifying these +// variables. Mostly focused on spacing. +// You can add more entries to the $spacers map, should you need more variation. + +// scss-docs-start spacer-variables-maps +$spacer: 1rem !default; +$spacers: ( + 0: 0, + 1: $spacer * .25, + 2: $spacer * .5, + 3: $spacer, + 4: $spacer * 1.5, + 5: $spacer * 3, +) !default; +// scss-docs-end spacer-variables-maps + +// Position +// +// Define the edge positioning anchors of the position utilities. + +// scss-docs-start position-map +$position-values: ( + 0: 0, + 50: 50%, + 100: 100% +) !default; +// scss-docs-end position-map + +// Body +// +// Settings for the `` element. + +$body-text-align: null !default; +$body-color: $gray-900 !default; +$body-bg: $white !default; + +$body-secondary-color: rgba($body-color, .75) !default; +$body-secondary-bg: $gray-200 !default; + +$body-tertiary-color: rgba($body-color, .5) !default; +$body-tertiary-bg: $gray-100 !default; + +$body-emphasis-color: $black !default; + +// Links +// +// Style anchor elements. + +$link-color: $primary !default; +$link-decoration: underline !default; +$link-shade-percentage: 20% !default; +$link-hover-color: shift-color($link-color, $link-shade-percentage) !default; +$link-hover-decoration: null !default; + +$stretched-link-pseudo-element: after !default; +$stretched-link-z-index: 1 !default; + +// Icon links +// scss-docs-start icon-link-variables +$icon-link-gap: .375rem !default; +$icon-link-underline-offset: .25em !default; +$icon-link-icon-size: 1em !default; +$icon-link-icon-transition: .2s ease-in-out transform !default; +$icon-link-icon-transform: translate3d(.25em, 0, 0) !default; +// scss-docs-end icon-link-variables + +// Paragraphs +// +// Style p element. + +$paragraph-margin-bottom: 1rem !default; + + +// Grid breakpoints +// +// Define the minimum dimensions at which your layout will change, +// adapting to different screen sizes, for use in media queries. + +// scss-docs-start grid-breakpoints +$grid-breakpoints: ( + xs: 0, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px, + xxl: 1400px +) !default; +// scss-docs-end grid-breakpoints + +@include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); +@include _assert-starts-at-zero($grid-breakpoints, "$grid-breakpoints"); + + +// Grid containers +// +// Define the maximum width of `.container` for different screen sizes. + +// scss-docs-start container-max-widths +$container-max-widths: ( + sm: 540px, + md: 720px, + lg: 960px, + xl: 1140px, + xxl: 1320px +) !default; +// scss-docs-end container-max-widths + +@include _assert-ascending($container-max-widths, "$container-max-widths"); + + +// Grid columns +// +// Set the number of columns and specify the width of the gutters. + +$grid-columns: 12 !default; +$grid-gutter-width: 1.5rem !default; +$grid-row-columns: 6 !default; + +// Container padding + +$container-padding-x: $grid-gutter-width !default; + + +// Components +// +// Define common padding and border radius sizes and more. + +// scss-docs-start border-variables +$border-width: 1px !default; +$border-widths: ( + 1: 1px, + 2: 2px, + 3: 3px, + 4: 4px, + 5: 5px +) !default; +$border-style: solid !default; +$border-color: $gray-300 !default; +$border-color-translucent: rgba($black, .175) !default; +// scss-docs-end border-variables + +// scss-docs-start border-radius-variables +$border-radius: .375rem !default; +$border-radius-sm: .25rem !default; +$border-radius-lg: .5rem !default; +$border-radius-xl: 1rem !default; +$border-radius-xxl: 2rem !default; +$border-radius-pill: 50rem !default; +// scss-docs-end border-radius-variables +// fusv-disable +$border-radius-2xl: $border-radius-xxl !default; // Deprecated in v5.3.0 +// fusv-enable + +// scss-docs-start box-shadow-variables +$box-shadow: 0 .5rem 1rem rgba($black, .15) !default; +$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default; +$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default; +$box-shadow-inset: inset 0 1px 2px rgba($black, .075) !default; +// scss-docs-end box-shadow-variables + +$component-active-color: $white !default; +$component-active-bg: $primary !default; + +// scss-docs-start focus-ring-variables +$focus-ring-width: .25rem !default; +$focus-ring-opacity: .25 !default; +$focus-ring-color: rgba($primary, $focus-ring-opacity) !default; +$focus-ring-blur: 0 !default; +$focus-ring-box-shadow: 0 0 $focus-ring-blur $focus-ring-width $focus-ring-color !default; +// scss-docs-end focus-ring-variables + +// scss-docs-start caret-variables +$caret-width: .3em !default; +$caret-vertical-align: $caret-width * .85 !default; +$caret-spacing: $caret-width * .85 !default; +// scss-docs-end caret-variables + +$transition-base: all .2s ease-in-out !default; +$transition-fade: opacity .15s linear !default; +// scss-docs-start collapse-transition +$transition-collapse: height .35s ease !default; +$transition-collapse-width: width .35s ease !default; +// scss-docs-end collapse-transition + +// stylelint-disable function-disallowed-list +// scss-docs-start aspect-ratios +$aspect-ratios: ( + "1x1": 100%, + "4x3": calc(3 / 4 * 100%), + "16x9": calc(9 / 16 * 100%), + "21x9": calc(9 / 21 * 100%) +) !default; +// scss-docs-end aspect-ratios +// stylelint-enable function-disallowed-list + +// Typography +// +// Font, line-height, and color for body text, headings, and more. + +// scss-docs-start font-variables +// stylelint-disable value-keyword-case +$font-family-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; +$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; +// stylelint-enable value-keyword-case +$font-family-base: var(--#{$prefix}font-sans-serif) !default; +$font-family-code: var(--#{$prefix}font-monospace) !default; + +// $font-size-root affects the value of `rem`, which is used for as well font sizes, paddings, and margins +// $font-size-base affects the font size of the body text +$font-size-root: null !default; +$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` +$font-size-sm: $font-size-base * .875 !default; +$font-size-lg: $font-size-base * 1.25 !default; + +$font-weight-lighter: lighter !default; +$font-weight-light: 300 !default; +$font-weight-normal: 400 !default; +$font-weight-medium: 500 !default; +$font-weight-semibold: 600 !default; +$font-weight-bold: 700 !default; +$font-weight-bolder: bolder !default; + +$font-weight-base: $font-weight-normal !default; + +$line-height-base: 1.5 !default; +$line-height-sm: 1.25 !default; +$line-height-lg: 2 !default; + +$h1-font-size: $font-size-base * 2.5 !default; +$h2-font-size: $font-size-base * 2 !default; +$h3-font-size: $font-size-base * 1.75 !default; +$h4-font-size: $font-size-base * 1.5 !default; +$h5-font-size: $font-size-base * 1.25 !default; +$h6-font-size: $font-size-base !default; +// scss-docs-end font-variables + +// scss-docs-start font-sizes +$font-sizes: ( + 1: $h1-font-size, + 2: $h2-font-size, + 3: $h3-font-size, + 4: $h4-font-size, + 5: $h5-font-size, + 6: $h6-font-size +) !default; +// scss-docs-end font-sizes + +// scss-docs-start headings-variables +$headings-margin-bottom: $spacer * .5 !default; +$headings-font-family: null !default; +$headings-font-style: null !default; +$headings-font-weight: 500 !default; +$headings-line-height: 1.2 !default; +$headings-color: inherit !default; +// scss-docs-end headings-variables + +// scss-docs-start display-headings +$display-font-sizes: ( + 1: 5rem, + 2: 4.5rem, + 3: 4rem, + 4: 3.5rem, + 5: 3rem, + 6: 2.5rem +) !default; + +$display-font-family: null !default; +$display-font-style: null !default; +$display-font-weight: 300 !default; +$display-line-height: $headings-line-height !default; +// scss-docs-end display-headings + +// scss-docs-start type-variables +$lead-font-size: $font-size-base * 1.25 !default; +$lead-font-weight: 300 !default; + +$small-font-size: .875em !default; + +$sub-sup-font-size: .75em !default; + +// fusv-disable +$text-muted: var(--#{$prefix}secondary-color) !default; // Deprecated in 5.3.0 +// fusv-enable + +$initialism-font-size: $small-font-size !default; + +$blockquote-margin-y: $spacer !default; +$blockquote-font-size: $font-size-base * 1.25 !default; +$blockquote-footer-color: $gray-600 !default; +$blockquote-footer-font-size: $small-font-size !default; + +$hr-margin-y: $spacer !default; +$hr-color: inherit !default; + +// fusv-disable +$hr-bg-color: null !default; // Deprecated in v5.2.0 +$hr-height: null !default; // Deprecated in v5.2.0 +// fusv-enable + +$hr-border-color: null !default; // Allows for inherited colors +$hr-border-width: var(--#{$prefix}border-width) !default; +$hr-opacity: .25 !default; + +// scss-docs-start vr-variables +$vr-border-width: var(--#{$prefix}border-width) !default; +// scss-docs-end vr-variables + +$legend-margin-bottom: .5rem !default; +$legend-font-size: 1.5rem !default; +$legend-font-weight: null !default; + +$dt-font-weight: $font-weight-bold !default; + +$list-inline-padding: .5rem !default; + +$mark-padding: .1875em !default; +$mark-color: $body-color !default; +$mark-bg: $yellow-100 !default; +// scss-docs-end type-variables + + +// Tables +// +// Customizes the `.table` component with basic values, each used across all table variations. + +// scss-docs-start table-variables +$table-cell-padding-y: .5rem !default; +$table-cell-padding-x: .5rem !default; +$table-cell-padding-y-sm: .25rem !default; +$table-cell-padding-x-sm: .25rem !default; + +$table-cell-vertical-align: top !default; + +$table-color: var(--#{$prefix}emphasis-color) !default; +$table-bg: var(--#{$prefix}body-bg) !default; +$table-accent-bg: transparent !default; + +$table-th-font-weight: null !default; + +$table-striped-color: $table-color !default; +$table-striped-bg-factor: .05 !default; +$table-striped-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-striped-bg-factor) !default; + +$table-active-color: $table-color !default; +$table-active-bg-factor: .1 !default; +$table-active-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-active-bg-factor) !default; + +$table-hover-color: $table-color !default; +$table-hover-bg-factor: .075 !default; +$table-hover-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-hover-bg-factor) !default; + +$table-border-factor: .2 !default; +$table-border-width: var(--#{$prefix}border-width) !default; +$table-border-color: var(--#{$prefix}border-color) !default; + +$table-striped-order: odd !default; +$table-striped-columns-order: even !default; + +$table-group-separator-color: currentcolor !default; + +$table-caption-color: var(--#{$prefix}secondary-color) !default; + +$table-bg-scale: -80% !default; +// scss-docs-end table-variables + +// scss-docs-start table-loop +$table-variants: ( + "primary": shift-color($primary, $table-bg-scale), + "secondary": shift-color($secondary, $table-bg-scale), + "success": shift-color($success, $table-bg-scale), + "info": shift-color($info, $table-bg-scale), + "warning": shift-color($warning, $table-bg-scale), + "danger": shift-color($danger, $table-bg-scale), + "light": $light, + "dark": $dark, +) !default; +// scss-docs-end table-loop + + +// Buttons + Forms +// +// Shared variables that are reassigned to `$input-` and `$btn-` specific variables. + +// scss-docs-start input-btn-variables +$input-btn-padding-y: .375rem !default; +$input-btn-padding-x: .75rem !default; +$input-btn-font-family: null !default; +$input-btn-font-size: $font-size-base !default; +$input-btn-line-height: $line-height-base !default; + +$input-btn-focus-width: $focus-ring-width !default; +$input-btn-focus-color-opacity: $focus-ring-opacity !default; +$input-btn-focus-color: $focus-ring-color !default; +$input-btn-focus-blur: $focus-ring-blur !default; +$input-btn-focus-box-shadow: $focus-ring-box-shadow !default; + +$input-btn-padding-y-sm: .25rem !default; +$input-btn-padding-x-sm: .5rem !default; +$input-btn-font-size-sm: $font-size-sm !default; + +$input-btn-padding-y-lg: .5rem !default; +$input-btn-padding-x-lg: 1rem !default; +$input-btn-font-size-lg: $font-size-lg !default; + +$input-btn-border-width: var(--#{$prefix}border-width) !default; +// scss-docs-end input-btn-variables + + +// Buttons +// +// For each of Bootstrap's buttons, define text, background, and border color. + +// scss-docs-start btn-variables +$btn-color: var(--#{$prefix}body-color) !default; +$btn-padding-y: $input-btn-padding-y !default; +$btn-padding-x: $input-btn-padding-x !default; +$btn-font-family: $input-btn-font-family !default; +$btn-font-size: $input-btn-font-size !default; +$btn-line-height: $input-btn-line-height !default; +$btn-white-space: null !default; // Set to `nowrap` to prevent text wrapping + +$btn-padding-y-sm: $input-btn-padding-y-sm !default; +$btn-padding-x-sm: $input-btn-padding-x-sm !default; +$btn-font-size-sm: $input-btn-font-size-sm !default; + +$btn-padding-y-lg: $input-btn-padding-y-lg !default; +$btn-padding-x-lg: $input-btn-padding-x-lg !default; +$btn-font-size-lg: $input-btn-font-size-lg !default; + +$btn-border-width: $input-btn-border-width !default; + +$btn-font-weight: $font-weight-normal !default; +$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default; +$btn-focus-width: $input-btn-focus-width !default; +$btn-focus-box-shadow: $input-btn-focus-box-shadow !default; +$btn-disabled-opacity: .65 !default; +$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default; + +$btn-link-color: var(--#{$prefix}link-color) !default; +$btn-link-hover-color: var(--#{$prefix}link-hover-color) !default; +$btn-link-disabled-color: $gray-600 !default; +$btn-link-focus-shadow-rgb: to-rgb(mix(color-contrast($link-color), $link-color, 15%)) !default; + +// Allows for customizing button radius independently from global border radius +$btn-border-radius: var(--#{$prefix}border-radius) !default; +$btn-border-radius-sm: var(--#{$prefix}border-radius-sm) !default; +$btn-border-radius-lg: var(--#{$prefix}border-radius-lg) !default; + +$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$btn-hover-bg-shade-amount: 15% !default; +$btn-hover-bg-tint-amount: 15% !default; +$btn-hover-border-shade-amount: 20% !default; +$btn-hover-border-tint-amount: 10% !default; +$btn-active-bg-shade-amount: 20% !default; +$btn-active-bg-tint-amount: 20% !default; +$btn-active-border-shade-amount: 25% !default; +$btn-active-border-tint-amount: 10% !default; +// scss-docs-end btn-variables + + +// Forms + +// scss-docs-start form-text-variables +$form-text-margin-top: .25rem !default; +$form-text-font-size: $small-font-size !default; +$form-text-font-style: null !default; +$form-text-font-weight: null !default; +$form-text-color: var(--#{$prefix}secondary-color) !default; +// scss-docs-end form-text-variables + +// scss-docs-start form-label-variables +$form-label-margin-bottom: .5rem !default; +$form-label-font-size: null !default; +$form-label-font-style: null !default; +$form-label-font-weight: null !default; +$form-label-color: null !default; +// scss-docs-end form-label-variables + +// scss-docs-start form-input-variables +$input-padding-y: $input-btn-padding-y !default; +$input-padding-x: $input-btn-padding-x !default; +$input-font-family: $input-btn-font-family !default; +$input-font-size: $input-btn-font-size !default; +$input-font-weight: $font-weight-base !default; +$input-line-height: $input-btn-line-height !default; + +$input-padding-y-sm: $input-btn-padding-y-sm !default; +$input-padding-x-sm: $input-btn-padding-x-sm !default; +$input-font-size-sm: $input-btn-font-size-sm !default; + +$input-padding-y-lg: $input-btn-padding-y-lg !default; +$input-padding-x-lg: $input-btn-padding-x-lg !default; +$input-font-size-lg: $input-btn-font-size-lg !default; + +$input-bg: var(--#{$prefix}body-bg) !default; +$input-disabled-color: null !default; +$input-disabled-bg: var(--#{$prefix}secondary-bg) !default; +$input-disabled-border-color: null !default; + +$input-color: var(--#{$prefix}body-color) !default; +$input-border-color: var(--#{$prefix}border-color) !default; +$input-border-width: $input-btn-border-width !default; +$input-box-shadow: var(--#{$prefix}box-shadow-inset) !default; + +$input-border-radius: var(--#{$prefix}border-radius) !default; +$input-border-radius-sm: var(--#{$prefix}border-radius-sm) !default; +$input-border-radius-lg: var(--#{$prefix}border-radius-lg) !default; + +$input-focus-bg: $input-bg !default; +$input-focus-border-color: tint-color($component-active-bg, 50%) !default; +$input-focus-color: $input-color !default; +$input-focus-width: $input-btn-focus-width !default; +$input-focus-box-shadow: $input-btn-focus-box-shadow !default; + +$input-placeholder-color: var(--#{$prefix}secondary-color) !default; +$input-plaintext-color: var(--#{$prefix}body-color) !default; + +$input-height-border: calc(#{$input-border-width} * 2) !default; // stylelint-disable-line function-disallowed-list + +$input-height-inner: add($input-line-height * 1em, $input-padding-y * 2) !default; +$input-height-inner-half: add($input-line-height * .5em, $input-padding-y) !default; +$input-height-inner-quarter: add($input-line-height * .25em, $input-padding-y * .5) !default; + +$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false)) !default; +$input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-height-border, false)) !default; +$input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-height-border, false)) !default; + +$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$form-color-width: 3rem !default; +// scss-docs-end form-input-variables + +// scss-docs-start form-check-variables +$form-check-input-width: 1em !default; +$form-check-min-height: $font-size-base * $line-height-base !default; +$form-check-padding-start: $form-check-input-width + .5em !default; +$form-check-margin-bottom: .125rem !default; +$form-check-label-color: null !default; +$form-check-label-cursor: null !default; +$form-check-transition: null !default; + +$form-check-input-active-filter: brightness(90%) !default; + +$form-check-input-bg: $input-bg !default; +$form-check-input-border: var(--#{$prefix}border-width) solid var(--#{$prefix}border-color) !default; +$form-check-input-border-radius: .25em !default; +$form-check-radio-border-radius: 50% !default; +$form-check-input-focus-border: $input-focus-border-color !default; +$form-check-input-focus-box-shadow: $focus-ring-box-shadow !default; + +$form-check-input-checked-color: $component-active-color !default; +$form-check-input-checked-bg-color: $component-active-bg !default; +$form-check-input-checked-border-color: $form-check-input-checked-bg-color !default; +$form-check-input-checked-bg-image: url("data:image/svg+xml,") !default; +$form-check-radio-checked-bg-image: url("data:image/svg+xml,") !default; + +$form-check-input-indeterminate-color: $component-active-color !default; +$form-check-input-indeterminate-bg-color: $component-active-bg !default; +$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default; +$form-check-input-indeterminate-bg-image: url("data:image/svg+xml,") !default; + +$form-check-input-disabled-opacity: .5 !default; +$form-check-label-disabled-opacity: $form-check-input-disabled-opacity !default; +$form-check-btn-check-disabled-opacity: $btn-disabled-opacity !default; + +$form-check-inline-margin-end: 1rem !default; +// scss-docs-end form-check-variables + +// scss-docs-start form-switch-variables +$form-switch-color: rgba($black, .25) !default; +$form-switch-width: 2em !default; +$form-switch-padding-start: $form-switch-width + .5em !default; +$form-switch-bg-image: url("data:image/svg+xml,") !default; +$form-switch-border-radius: $form-switch-width !default; +$form-switch-transition: background-position .15s ease-in-out !default; + +$form-switch-focus-color: $input-focus-border-color !default; +$form-switch-focus-bg-image: url("data:image/svg+xml,") !default; + +$form-switch-checked-color: $component-active-color !default; +$form-switch-checked-bg-image: url("data:image/svg+xml,") !default; +$form-switch-checked-bg-position: right center !default; +// scss-docs-end form-switch-variables + +// scss-docs-start input-group-variables +$input-group-addon-padding-y: $input-padding-y !default; +$input-group-addon-padding-x: $input-padding-x !default; +$input-group-addon-font-weight: $input-font-weight !default; +$input-group-addon-color: $input-color !default; +$input-group-addon-bg: var(--#{$prefix}tertiary-bg) !default; +$input-group-addon-border-color: $input-border-color !default; +// scss-docs-end input-group-variables + +// scss-docs-start form-select-variables +$form-select-padding-y: $input-padding-y !default; +$form-select-padding-x: $input-padding-x !default; +$form-select-font-family: $input-font-family !default; +$form-select-font-size: $input-font-size !default; +$form-select-indicator-padding: $form-select-padding-x * 3 !default; // Extra padding for background-image +$form-select-font-weight: $input-font-weight !default; +$form-select-line-height: $input-line-height !default; +$form-select-color: $input-color !default; +$form-select-bg: $input-bg !default; +$form-select-disabled-color: null !default; +$form-select-disabled-bg: $input-disabled-bg !default; +$form-select-disabled-border-color: $input-disabled-border-color !default; +$form-select-bg-position: right $form-select-padding-x center !default; +$form-select-bg-size: 16px 12px !default; // In pixels because image dimensions +$form-select-indicator-color: $gray-800 !default; +$form-select-indicator: url("data:image/svg+xml,") !default; + +$form-select-feedback-icon-padding-end: $form-select-padding-x * 2.5 + $form-select-indicator-padding !default; +$form-select-feedback-icon-position: center right $form-select-indicator-padding !default; +$form-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default; + +$form-select-border-width: $input-border-width !default; +$form-select-border-color: $input-border-color !default; +$form-select-border-radius: $input-border-radius !default; +$form-select-box-shadow: var(--#{$prefix}box-shadow-inset) !default; + +$form-select-focus-border-color: $input-focus-border-color !default; +$form-select-focus-width: $input-focus-width !default; +$form-select-focus-box-shadow: 0 0 0 $form-select-focus-width $input-btn-focus-color !default; + +$form-select-padding-y-sm: $input-padding-y-sm !default; +$form-select-padding-x-sm: $input-padding-x-sm !default; +$form-select-font-size-sm: $input-font-size-sm !default; +$form-select-border-radius-sm: $input-border-radius-sm !default; + +$form-select-padding-y-lg: $input-padding-y-lg !default; +$form-select-padding-x-lg: $input-padding-x-lg !default; +$form-select-font-size-lg: $input-font-size-lg !default; +$form-select-border-radius-lg: $input-border-radius-lg !default; + +$form-select-transition: $input-transition !default; +// scss-docs-end form-select-variables + +// scss-docs-start form-range-variables +$form-range-track-width: 100% !default; +$form-range-track-height: .5rem !default; +$form-range-track-cursor: pointer !default; +$form-range-track-bg: var(--#{$prefix}secondary-bg) !default; +$form-range-track-border-radius: 1rem !default; +$form-range-track-box-shadow: var(--#{$prefix}box-shadow-inset) !default; + +$form-range-thumb-width: 1rem !default; +$form-range-thumb-height: $form-range-thumb-width !default; +$form-range-thumb-bg: $component-active-bg !default; +$form-range-thumb-border: 0 !default; +$form-range-thumb-border-radius: 1rem !default; +$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default; +$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default; +$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in Edge +$form-range-thumb-active-bg: tint-color($component-active-bg, 70%) !default; +$form-range-thumb-disabled-bg: var(--#{$prefix}secondary-color) !default; +$form-range-thumb-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; +// scss-docs-end form-range-variables + +// scss-docs-start form-file-variables +$form-file-button-color: $input-color !default; +$form-file-button-bg: var(--#{$prefix}tertiary-bg) !default; +$form-file-button-hover-bg: var(--#{$prefix}secondary-bg) !default; +// scss-docs-end form-file-variables + +// scss-docs-start form-floating-variables +$form-floating-height: add(3.5rem, $input-height-border) !default; +$form-floating-line-height: 1.25 !default; +$form-floating-padding-x: $input-padding-x !default; +$form-floating-padding-y: 1rem !default; +$form-floating-input-padding-t: 1.625rem !default; +$form-floating-input-padding-b: .625rem !default; +$form-floating-label-height: 1.5em !default; +$form-floating-label-opacity: .65 !default; +$form-floating-label-transform: scale(.85) translateY(-.5rem) translateX(.15rem) !default; +$form-floating-label-disabled-color: $gray-600 !default; +$form-floating-transition: opacity .1s ease-in-out, transform .1s ease-in-out !default; +// scss-docs-end form-floating-variables + +// Form validation + +// scss-docs-start form-feedback-variables +$form-feedback-margin-top: $form-text-margin-top !default; +$form-feedback-font-size: $form-text-font-size !default; +$form-feedback-font-style: $form-text-font-style !default; +$form-feedback-valid-color: $success !default; +$form-feedback-invalid-color: $danger !default; + +$form-feedback-icon-valid-color: $form-feedback-valid-color !default; +$form-feedback-icon-valid: url("data:image/svg+xml,") !default; +$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default; +$form-feedback-icon-invalid: url("data:image/svg+xml,") !default; +// scss-docs-end form-feedback-variables + +// scss-docs-start form-validation-colors +$form-valid-color: $form-feedback-valid-color !default; +$form-valid-border-color: $form-feedback-valid-color !default; +$form-invalid-color: $form-feedback-invalid-color !default; +$form-invalid-border-color: $form-feedback-invalid-color !default; +// scss-docs-end form-validation-colors + +// scss-docs-start form-validation-states +$form-validation-states: ( + "valid": ( + "color": var(--#{$prefix}form-valid-color), + "icon": $form-feedback-icon-valid, + "tooltip-color": #fff, + "tooltip-bg-color": var(--#{$prefix}success), + "focus-box-shadow": 0 0 $input-btn-focus-blur $input-focus-width rgba(var(--#{$prefix}success-rgb), $input-btn-focus-color-opacity), + "border-color": var(--#{$prefix}form-valid-border-color), + ), + "invalid": ( + "color": var(--#{$prefix}form-invalid-color), + "icon": $form-feedback-icon-invalid, + "tooltip-color": #fff, + "tooltip-bg-color": var(--#{$prefix}danger), + "focus-box-shadow": 0 0 $input-btn-focus-blur $input-focus-width rgba(var(--#{$prefix}danger-rgb), $input-btn-focus-color-opacity), + "border-color": var(--#{$prefix}form-invalid-border-color), + ) +) !default; +// scss-docs-end form-validation-states + +// Z-index master list +// +// Warning: Avoid customizing these values. They're used for a bird's eye view +// of components dependent on the z-axis and are designed to all work together. + +// scss-docs-start zindex-stack +$zindex-dropdown: 1000 !default; +$zindex-sticky: 1020 !default; +$zindex-fixed: 1030 !default; +$zindex-offcanvas-backdrop: 1040 !default; +$zindex-offcanvas: 1045 !default; +$zindex-modal-backdrop: 1050 !default; +$zindex-modal: 1055 !default; +$zindex-popover: 1070 !default; +$zindex-tooltip: 1080 !default; +$zindex-toast: 1090 !default; +// scss-docs-end zindex-stack + +// scss-docs-start zindex-levels-map +$zindex-levels: ( + n1: -1, + 0: 0, + 1: 1, + 2: 2, + 3: 3 +) !default; +// scss-docs-end zindex-levels-map + + +// Navs + +// scss-docs-start nav-variables +$nav-link-padding-y: .5rem !default; +$nav-link-padding-x: 1rem !default; +$nav-link-font-size: null !default; +$nav-link-font-weight: null !default; +$nav-link-color: var(--#{$prefix}link-color) !default; +$nav-link-hover-color: var(--#{$prefix}link-hover-color) !default; +$nav-link-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default; +$nav-link-disabled-color: var(--#{$prefix}secondary-color) !default; +$nav-link-focus-box-shadow: $focus-ring-box-shadow !default; + +$nav-tabs-border-color: var(--#{$prefix}border-color) !default; +$nav-tabs-border-width: var(--#{$prefix}border-width) !default; +$nav-tabs-border-radius: var(--#{$prefix}border-radius) !default; +$nav-tabs-link-hover-border-color: var(--#{$prefix}secondary-bg) var(--#{$prefix}secondary-bg) $nav-tabs-border-color !default; +$nav-tabs-link-active-color: var(--#{$prefix}emphasis-color) !default; +$nav-tabs-link-active-bg: var(--#{$prefix}body-bg) !default; +$nav-tabs-link-active-border-color: var(--#{$prefix}border-color) var(--#{$prefix}border-color) $nav-tabs-link-active-bg !default; + +$nav-pills-border-radius: var(--#{$prefix}border-radius) !default; +$nav-pills-link-active-color: $component-active-color !default; +$nav-pills-link-active-bg: $component-active-bg !default; + +$nav-underline-gap: 1rem !default; +$nav-underline-border-width: .125rem !default; +$nav-underline-link-active-color: var(--#{$prefix}emphasis-color) !default; +// scss-docs-end nav-variables + + +// Navbar + +// scss-docs-start navbar-variables +$navbar-padding-y: $spacer * .5 !default; +$navbar-padding-x: null !default; + +$navbar-nav-link-padding-x: .5rem !default; + +$navbar-brand-font-size: $font-size-lg !default; +// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link +$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default; +$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; +$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) * .5 !default; +$navbar-brand-margin-end: 1rem !default; + +$navbar-toggler-padding-y: .25rem !default; +$navbar-toggler-padding-x: .75rem !default; +$navbar-toggler-font-size: $font-size-lg !default; +$navbar-toggler-border-radius: $btn-border-radius !default; +$navbar-toggler-focus-width: $btn-focus-width !default; +$navbar-toggler-transition: box-shadow .15s ease-in-out !default; + +$navbar-light-color: rgba(var(--#{$prefix}emphasis-color-rgb), .65) !default; +$navbar-light-hover-color: rgba(var(--#{$prefix}emphasis-color-rgb), .8) !default; +$navbar-light-active-color: rgba(var(--#{$prefix}emphasis-color-rgb), 1) !default; +$navbar-light-disabled-color: rgba(var(--#{$prefix}emphasis-color-rgb), .3) !default; +$navbar-light-icon-color: rgba($body-color, .75) !default; +$navbar-light-toggler-icon-bg: url("data:image/svg+xml,") !default; +$navbar-light-toggler-border-color: rgba(var(--#{$prefix}emphasis-color-rgb), .15) !default; +$navbar-light-brand-color: $navbar-light-active-color !default; +$navbar-light-brand-hover-color: $navbar-light-active-color !default; +// scss-docs-end navbar-variables + +// scss-docs-start navbar-dark-variables +$navbar-dark-color: rgba($white, .55) !default; +$navbar-dark-hover-color: rgba($white, .75) !default; +$navbar-dark-active-color: $white !default; +$navbar-dark-disabled-color: rgba($white, .25) !default; +$navbar-dark-icon-color: $navbar-dark-color !default; +$navbar-dark-toggler-icon-bg: url("data:image/svg+xml,") !default; +$navbar-dark-toggler-border-color: rgba($white, .1) !default; +$navbar-dark-brand-color: $navbar-dark-active-color !default; +$navbar-dark-brand-hover-color: $navbar-dark-active-color !default; +// scss-docs-end navbar-dark-variables + + +// Dropdowns +// +// Dropdown menu container and contents. + +// scss-docs-start dropdown-variables +$dropdown-min-width: 10rem !default; +$dropdown-padding-x: 0 !default; +$dropdown-padding-y: .5rem !default; +$dropdown-spacer: .125rem !default; +$dropdown-font-size: $font-size-base !default; +$dropdown-color: var(--#{$prefix}body-color) !default; +$dropdown-bg: var(--#{$prefix}body-bg) !default; +$dropdown-border-color: var(--#{$prefix}border-color-translucent) !default; +$dropdown-border-radius: var(--#{$prefix}border-radius) !default; +$dropdown-border-width: var(--#{$prefix}border-width) !default; +$dropdown-inner-border-radius: calc(#{$dropdown-border-radius} - #{$dropdown-border-width}) !default; // stylelint-disable-line function-disallowed-list +$dropdown-divider-bg: $dropdown-border-color !default; +$dropdown-divider-margin-y: $spacer * .5 !default; +$dropdown-box-shadow: var(--#{$prefix}box-shadow) !default; + +$dropdown-link-color: var(--#{$prefix}body-color) !default; +$dropdown-link-hover-color: $dropdown-link-color !default; +$dropdown-link-hover-bg: var(--#{$prefix}tertiary-bg) !default; + +$dropdown-link-active-color: $component-active-color !default; +$dropdown-link-active-bg: $component-active-bg !default; + +$dropdown-link-disabled-color: var(--#{$prefix}tertiary-color) !default; + +$dropdown-item-padding-y: $spacer * .25 !default; +$dropdown-item-padding-x: $spacer !default; + +$dropdown-header-color: $gray-600 !default; +$dropdown-header-padding-x: $dropdown-item-padding-x !default; +$dropdown-header-padding-y: $dropdown-padding-y !default; +// fusv-disable +$dropdown-header-padding: $dropdown-header-padding-y $dropdown-header-padding-x !default; // Deprecated in v5.2.0 +// fusv-enable +// scss-docs-end dropdown-variables + +// scss-docs-start dropdown-dark-variables +$dropdown-dark-color: $gray-300 !default; +$dropdown-dark-bg: $gray-800 !default; +$dropdown-dark-border-color: $dropdown-border-color !default; +$dropdown-dark-divider-bg: $dropdown-divider-bg !default; +$dropdown-dark-box-shadow: null !default; +$dropdown-dark-link-color: $dropdown-dark-color !default; +$dropdown-dark-link-hover-color: $white !default; +$dropdown-dark-link-hover-bg: rgba($white, .15) !default; +$dropdown-dark-link-active-color: $dropdown-link-active-color !default; +$dropdown-dark-link-active-bg: $dropdown-link-active-bg !default; +$dropdown-dark-link-disabled-color: $gray-500 !default; +$dropdown-dark-header-color: $gray-500 !default; +// scss-docs-end dropdown-dark-variables + + +// Pagination + +// scss-docs-start pagination-variables +$pagination-padding-y: .375rem !default; +$pagination-padding-x: .75rem !default; +$pagination-padding-y-sm: .25rem !default; +$pagination-padding-x-sm: .5rem !default; +$pagination-padding-y-lg: .75rem !default; +$pagination-padding-x-lg: 1.5rem !default; + +$pagination-font-size: $font-size-base !default; + +$pagination-color: var(--#{$prefix}link-color) !default; +$pagination-bg: var(--#{$prefix}body-bg) !default; +$pagination-border-radius: var(--#{$prefix}border-radius) !default; +$pagination-border-width: var(--#{$prefix}border-width) !default; +$pagination-margin-start: calc(#{$pagination-border-width} * -1) !default; // stylelint-disable-line function-disallowed-list +$pagination-border-color: var(--#{$prefix}border-color) !default; + +$pagination-focus-color: var(--#{$prefix}link-hover-color) !default; +$pagination-focus-bg: var(--#{$prefix}secondary-bg) !default; +$pagination-focus-box-shadow: $focus-ring-box-shadow !default; +$pagination-focus-outline: 0 !default; + +$pagination-hover-color: var(--#{$prefix}link-hover-color) !default; +$pagination-hover-bg: var(--#{$prefix}tertiary-bg) !default; +$pagination-hover-border-color: var(--#{$prefix}border-color) !default; // Todo in v6: remove this? + +$pagination-active-color: $component-active-color !default; +$pagination-active-bg: $component-active-bg !default; +$pagination-active-border-color: $component-active-bg !default; + +$pagination-disabled-color: var(--#{$prefix}secondary-color) !default; +$pagination-disabled-bg: var(--#{$prefix}secondary-bg) !default; +$pagination-disabled-border-color: var(--#{$prefix}border-color) !default; + +$pagination-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$pagination-border-radius-sm: var(--#{$prefix}border-radius-sm) !default; +$pagination-border-radius-lg: var(--#{$prefix}border-radius-lg) !default; +// scss-docs-end pagination-variables + + +// Placeholders + +// scss-docs-start placeholders +$placeholder-opacity-max: .5 !default; +$placeholder-opacity-min: .2 !default; +// scss-docs-end placeholders + +// Cards + +// scss-docs-start card-variables +$card-spacer-y: $spacer !default; +$card-spacer-x: $spacer !default; +$card-title-spacer-y: $spacer * .5 !default; +$card-title-color: null !default; +$card-subtitle-color: null !default; +$card-border-width: var(--#{$prefix}border-width) !default; +$card-border-color: var(--#{$prefix}border-color-translucent) !default; +$card-border-radius: var(--#{$prefix}border-radius) !default; +$card-box-shadow: null !default; +$card-inner-border-radius: subtract($card-border-radius, $card-border-width) !default; +$card-cap-padding-y: $card-spacer-y * .5 !default; +$card-cap-padding-x: $card-spacer-x !default; +$card-cap-bg: rgba(var(--#{$prefix}body-color-rgb), .03) !default; +$card-cap-color: null !default; +$card-height: null !default; +$card-color: null !default; +$card-bg: var(--#{$prefix}body-bg) !default; +$card-img-overlay-padding: $spacer !default; +$card-group-margin: $grid-gutter-width * .5 !default; +// scss-docs-end card-variables + +// Accordion + +// scss-docs-start accordion-variables +$accordion-padding-y: 1rem !default; +$accordion-padding-x: 1.25rem !default; +$accordion-color: var(--#{$prefix}body-color) !default; +$accordion-bg: var(--#{$prefix}body-bg) !default; +$accordion-border-width: var(--#{$prefix}border-width) !default; +$accordion-border-color: var(--#{$prefix}border-color) !default; +$accordion-border-radius: var(--#{$prefix}border-radius) !default; +$accordion-inner-border-radius: subtract($accordion-border-radius, $accordion-border-width) !default; + +$accordion-body-padding-y: $accordion-padding-y !default; +$accordion-body-padding-x: $accordion-padding-x !default; + +$accordion-button-padding-y: $accordion-padding-y !default; +$accordion-button-padding-x: $accordion-padding-x !default; +$accordion-button-color: var(--#{$prefix}body-color) !default; +$accordion-button-bg: var(--#{$prefix}accordion-bg) !default; +$accordion-transition: $btn-transition, border-radius .15s ease !default; +$accordion-button-active-bg: var(--#{$prefix}primary-bg-subtle) !default; +$accordion-button-active-color: var(--#{$prefix}primary-text-emphasis) !default; + +// fusv-disable +$accordion-button-focus-border-color: $input-focus-border-color !default; // Deprecated in v5.3.3 +// fusv-enable +$accordion-button-focus-box-shadow: $btn-focus-box-shadow !default; + +$accordion-icon-width: 1.25rem !default; +$accordion-icon-color: $body-color !default; +$accordion-icon-active-color: $primary-text-emphasis !default; +$accordion-icon-transition: transform .2s ease-in-out !default; +$accordion-icon-transform: rotate(-180deg) !default; + +$accordion-button-icon: url("data:image/svg+xml,") !default; +$accordion-button-active-icon: url("data:image/svg+xml,") !default; +// scss-docs-end accordion-variables + +// Tooltips + +// scss-docs-start tooltip-variables +$tooltip-font-size: $font-size-sm !default; +$tooltip-max-width: 200px !default; +$tooltip-color: var(--#{$prefix}body-bg) !default; +$tooltip-bg: var(--#{$prefix}emphasis-color) !default; +$tooltip-border-radius: var(--#{$prefix}border-radius) !default; +$tooltip-opacity: .9 !default; +$tooltip-padding-y: $spacer * .25 !default; +$tooltip-padding-x: $spacer * .5 !default; +$tooltip-margin: null !default; // TODO: remove this in v6 + +$tooltip-arrow-width: .8rem !default; +$tooltip-arrow-height: .4rem !default; +// fusv-disable +$tooltip-arrow-color: null !default; // Deprecated in Bootstrap 5.2.0 for CSS variables +// fusv-enable +// scss-docs-end tooltip-variables + +// Form tooltips must come after regular tooltips +// scss-docs-start tooltip-feedback-variables +$form-feedback-tooltip-padding-y: $tooltip-padding-y !default; +$form-feedback-tooltip-padding-x: $tooltip-padding-x !default; +$form-feedback-tooltip-font-size: $tooltip-font-size !default; +$form-feedback-tooltip-line-height: null !default; +$form-feedback-tooltip-opacity: $tooltip-opacity !default; +$form-feedback-tooltip-border-radius: $tooltip-border-radius !default; +// scss-docs-end tooltip-feedback-variables + + +// Popovers + +// scss-docs-start popover-variables +$popover-font-size: $font-size-sm !default; +$popover-bg: var(--#{$prefix}body-bg) !default; +$popover-max-width: 276px !default; +$popover-border-width: var(--#{$prefix}border-width) !default; +$popover-border-color: var(--#{$prefix}border-color-translucent) !default; +$popover-border-radius: var(--#{$prefix}border-radius-lg) !default; +$popover-inner-border-radius: calc(#{$popover-border-radius} - #{$popover-border-width}) !default; // stylelint-disable-line function-disallowed-list +$popover-box-shadow: var(--#{$prefix}box-shadow) !default; + +$popover-header-font-size: $font-size-base !default; +$popover-header-bg: var(--#{$prefix}secondary-bg) !default; +$popover-header-color: $headings-color !default; +$popover-header-padding-y: .5rem !default; +$popover-header-padding-x: $spacer !default; + +$popover-body-color: var(--#{$prefix}body-color) !default; +$popover-body-padding-y: $spacer !default; +$popover-body-padding-x: $spacer !default; + +$popover-arrow-width: 1rem !default; +$popover-arrow-height: .5rem !default; +// scss-docs-end popover-variables + +// fusv-disable +// Deprecated in Bootstrap 5.2.0 for CSS variables +$popover-arrow-color: $popover-bg !default; +$popover-arrow-outer-color: var(--#{$prefix}border-color-translucent) !default; +// fusv-enable + + +// Toasts + +// scss-docs-start toast-variables +$toast-max-width: 350px !default; +$toast-padding-x: .75rem !default; +$toast-padding-y: .5rem !default; +$toast-font-size: .875rem !default; +$toast-color: null !default; +$toast-background-color: rgba(var(--#{$prefix}body-bg-rgb), .85) !default; +$toast-border-width: var(--#{$prefix}border-width) !default; +$toast-border-color: var(--#{$prefix}border-color-translucent) !default; +$toast-border-radius: var(--#{$prefix}border-radius) !default; +$toast-box-shadow: var(--#{$prefix}box-shadow) !default; +$toast-spacing: $container-padding-x !default; + +$toast-header-color: var(--#{$prefix}secondary-color) !default; +$toast-header-background-color: rgba(var(--#{$prefix}body-bg-rgb), .85) !default; +$toast-header-border-color: $toast-border-color !default; +// scss-docs-end toast-variables + + +// Badges + +// scss-docs-start badge-variables +$badge-font-size: .75em !default; +$badge-font-weight: $font-weight-bold !default; +$badge-color: $white !default; +$badge-padding-y: .35em !default; +$badge-padding-x: .65em !default; +$badge-border-radius: var(--#{$prefix}border-radius) !default; +// scss-docs-end badge-variables + + +// Modals + +// scss-docs-start modal-variables +$modal-inner-padding: $spacer !default; + +$modal-footer-margin-between: .5rem !default; + +$modal-dialog-margin: .5rem !default; +$modal-dialog-margin-y-sm-up: 1.75rem !default; + +$modal-title-line-height: $line-height-base !default; + +$modal-content-color: null !default; +$modal-content-bg: var(--#{$prefix}body-bg) !default; +$modal-content-border-color: var(--#{$prefix}border-color-translucent) !default; +$modal-content-border-width: var(--#{$prefix}border-width) !default; +$modal-content-border-radius: var(--#{$prefix}border-radius-lg) !default; +$modal-content-inner-border-radius: subtract($modal-content-border-radius, $modal-content-border-width) !default; +$modal-content-box-shadow-xs: var(--#{$prefix}box-shadow-sm) !default; +$modal-content-box-shadow-sm-up: var(--#{$prefix}box-shadow) !default; + +$modal-backdrop-bg: $black !default; +$modal-backdrop-opacity: .5 !default; + +$modal-header-border-color: var(--#{$prefix}border-color) !default; +$modal-header-border-width: $modal-content-border-width !default; +$modal-header-padding-y: $modal-inner-padding !default; +$modal-header-padding-x: $modal-inner-padding !default; +$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility + +$modal-footer-bg: null !default; +$modal-footer-border-color: $modal-header-border-color !default; +$modal-footer-border-width: $modal-header-border-width !default; + +$modal-sm: 300px !default; +$modal-md: 500px !default; +$modal-lg: 800px !default; +$modal-xl: 1140px !default; + +$modal-fade-transform: translate(0, -50px) !default; +$modal-show-transform: none !default; +$modal-transition: transform .3s ease-out !default; +$modal-scale-transform: scale(1.02) !default; +// scss-docs-end modal-variables + + +// Alerts +// +// Define alert colors, border radius, and padding. + +// scss-docs-start alert-variables +$alert-padding-y: $spacer !default; +$alert-padding-x: $spacer !default; +$alert-margin-bottom: 1rem !default; +$alert-border-radius: var(--#{$prefix}border-radius) !default; +$alert-link-font-weight: $font-weight-bold !default; +$alert-border-width: var(--#{$prefix}border-width) !default; +$alert-dismissible-padding-r: $alert-padding-x * 3 !default; // 3x covers width of x plus default padding on either side +// scss-docs-end alert-variables + +// fusv-disable +$alert-bg-scale: -80% !default; // Deprecated in v5.2.0, to be removed in v6 +$alert-border-scale: -70% !default; // Deprecated in v5.2.0, to be removed in v6 +$alert-color-scale: 40% !default; // Deprecated in v5.2.0, to be removed in v6 +// fusv-enable + +// Progress bars + +// scss-docs-start progress-variables +$progress-height: 1rem !default; +$progress-font-size: $font-size-base * .75 !default; +$progress-bg: var(--#{$prefix}secondary-bg) !default; +$progress-border-radius: var(--#{$prefix}border-radius) !default; +$progress-box-shadow: var(--#{$prefix}box-shadow-inset) !default; +$progress-bar-color: $white !default; +$progress-bar-bg: $primary !default; +$progress-bar-animation-timing: 1s linear infinite !default; +$progress-bar-transition: width .6s ease !default; +// scss-docs-end progress-variables + + +// List group + +// scss-docs-start list-group-variables +$list-group-color: var(--#{$prefix}body-color) !default; +$list-group-bg: var(--#{$prefix}body-bg) !default; +$list-group-border-color: var(--#{$prefix}border-color) !default; +$list-group-border-width: var(--#{$prefix}border-width) !default; +$list-group-border-radius: var(--#{$prefix}border-radius) !default; + +$list-group-item-padding-y: $spacer * .5 !default; +$list-group-item-padding-x: $spacer !default; +// fusv-disable +$list-group-item-bg-scale: -80% !default; // Deprecated in v5.3.0 +$list-group-item-color-scale: 40% !default; // Deprecated in v5.3.0 +// fusv-enable + +$list-group-hover-bg: var(--#{$prefix}tertiary-bg) !default; +$list-group-active-color: $component-active-color !default; +$list-group-active-bg: $component-active-bg !default; +$list-group-active-border-color: $list-group-active-bg !default; + +$list-group-disabled-color: var(--#{$prefix}secondary-color) !default; +$list-group-disabled-bg: $list-group-bg !default; + +$list-group-action-color: var(--#{$prefix}secondary-color) !default; +$list-group-action-hover-color: var(--#{$prefix}emphasis-color) !default; + +$list-group-action-active-color: var(--#{$prefix}body-color) !default; +$list-group-action-active-bg: var(--#{$prefix}secondary-bg) !default; +// scss-docs-end list-group-variables + + +// Image thumbnails + +// scss-docs-start thumbnail-variables +$thumbnail-padding: .25rem !default; +$thumbnail-bg: var(--#{$prefix}body-bg) !default; +$thumbnail-border-width: var(--#{$prefix}border-width) !default; +$thumbnail-border-color: var(--#{$prefix}border-color) !default; +$thumbnail-border-radius: var(--#{$prefix}border-radius) !default; +$thumbnail-box-shadow: var(--#{$prefix}box-shadow-sm) !default; +// scss-docs-end thumbnail-variables + + +// Figures + +// scss-docs-start figure-variables +$figure-caption-font-size: $small-font-size !default; +$figure-caption-color: var(--#{$prefix}secondary-color) !default; +// scss-docs-end figure-variables + + +// Breadcrumbs + +// scss-docs-start breadcrumb-variables +$breadcrumb-font-size: null !default; +$breadcrumb-padding-y: 0 !default; +$breadcrumb-padding-x: 0 !default; +$breadcrumb-item-padding-x: .5rem !default; +$breadcrumb-margin-bottom: 1rem !default; +$breadcrumb-bg: null !default; +$breadcrumb-divider-color: var(--#{$prefix}secondary-color) !default; +$breadcrumb-active-color: var(--#{$prefix}secondary-color) !default; +$breadcrumb-divider: quote("/") !default; +$breadcrumb-divider-flipped: $breadcrumb-divider !default; +$breadcrumb-border-radius: null !default; +// scss-docs-end breadcrumb-variables + +// Carousel + +// scss-docs-start carousel-variables +$carousel-control-color: $white !default; +$carousel-control-width: 15% !default; +$carousel-control-opacity: .5 !default; +$carousel-control-hover-opacity: .9 !default; +$carousel-control-transition: opacity .15s ease !default; + +$carousel-indicator-width: 30px !default; +$carousel-indicator-height: 3px !default; +$carousel-indicator-hit-area-height: 10px !default; +$carousel-indicator-spacer: 3px !default; +$carousel-indicator-opacity: .5 !default; +$carousel-indicator-active-bg: $white !default; +$carousel-indicator-active-opacity: 1 !default; +$carousel-indicator-transition: opacity .6s ease !default; + +$carousel-caption-width: 70% !default; +$carousel-caption-color: $white !default; +$carousel-caption-padding-y: 1.25rem !default; +$carousel-caption-spacer: 1.25rem !default; + +$carousel-control-icon-width: 2rem !default; + +$carousel-control-prev-icon-bg: url("data:image/svg+xml,") !default; +$carousel-control-next-icon-bg: url("data:image/svg+xml,") !default; + +$carousel-transition-duration: .6s !default; +$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`) +// scss-docs-end carousel-variables + +// scss-docs-start carousel-dark-variables +$carousel-dark-indicator-active-bg: $black !default; +$carousel-dark-caption-color: $black !default; +$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default; +// scss-docs-end carousel-dark-variables + + +// Spinners + +// scss-docs-start spinner-variables +$spinner-width: 2rem !default; +$spinner-height: $spinner-width !default; +$spinner-vertical-align: -.125em !default; +$spinner-border-width: .25em !default; +$spinner-animation-speed: .75s !default; + +$spinner-width-sm: 1rem !default; +$spinner-height-sm: $spinner-width-sm !default; +$spinner-border-width-sm: .2em !default; +// scss-docs-end spinner-variables + + +// Close + +// scss-docs-start close-variables +$btn-close-width: 1em !default; +$btn-close-height: $btn-close-width !default; +$btn-close-padding-x: .25em !default; +$btn-close-padding-y: $btn-close-padding-x !default; +$btn-close-color: $black !default; +$btn-close-bg: url("data:image/svg+xml,") !default; +$btn-close-focus-shadow: $focus-ring-box-shadow !default; +$btn-close-opacity: .5 !default; +$btn-close-hover-opacity: .75 !default; +$btn-close-focus-opacity: 1 !default; +$btn-close-disabled-opacity: .25 !default; +$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default; +// scss-docs-end close-variables + + +// Offcanvas + +// scss-docs-start offcanvas-variables +$offcanvas-padding-y: $modal-inner-padding !default; +$offcanvas-padding-x: $modal-inner-padding !default; +$offcanvas-horizontal-width: 400px !default; +$offcanvas-vertical-height: 30vh !default; +$offcanvas-transition-duration: .3s !default; +$offcanvas-border-color: $modal-content-border-color !default; +$offcanvas-border-width: $modal-content-border-width !default; +$offcanvas-title-line-height: $modal-title-line-height !default; +$offcanvas-bg-color: var(--#{$prefix}body-bg) !default; +$offcanvas-color: var(--#{$prefix}body-color) !default; +$offcanvas-box-shadow: $modal-content-box-shadow-xs !default; +$offcanvas-backdrop-bg: $modal-backdrop-bg !default; +$offcanvas-backdrop-opacity: $modal-backdrop-opacity !default; +// scss-docs-end offcanvas-variables + +// Code + +$code-font-size: $small-font-size !default; +$code-color: $pink !default; + +$kbd-padding-y: .1875rem !default; +$kbd-padding-x: .375rem !default; +$kbd-font-size: $code-font-size !default; +$kbd-color: var(--#{$prefix}body-bg) !default; +$kbd-bg: var(--#{$prefix}body-color) !default; +$nested-kbd-font-weight: null !default; // Deprecated in v5.2.0, removing in v6 + +$pre-color: null !default; + +@import "variables-dark"; // TODO: can be removed safely in v6, only here to avoid breaking changes in v5.3 diff --git a/scss/bs5/mixins/_alert.scss b/scss/bs5/mixins/_alert.scss new file mode 100644 index 0000000..fb524af --- /dev/null +++ b/scss/bs5/mixins/_alert.scss @@ -0,0 +1,18 @@ +@include deprecate("`alert-variant()`", "v5.3.0", "v6.0.0"); + +// scss-docs-start alert-variant-mixin +@mixin alert-variant($background, $border, $color) { + --#{$prefix}alert-color: #{$color}; + --#{$prefix}alert-bg: #{$background}; + --#{$prefix}alert-border-color: #{$border}; + --#{$prefix}alert-link-color: #{shade-color($color, 20%)}; + + @if $enable-gradients { + background-image: var(--#{$prefix}gradient); + } + + .alert-link { + color: var(--#{$prefix}alert-link-color); + } +} +// scss-docs-end alert-variant-mixin diff --git a/scss/bs5/mixins/_backdrop.scss b/scss/bs5/mixins/_backdrop.scss new file mode 100644 index 0000000..9705ae9 --- /dev/null +++ b/scss/bs5/mixins/_backdrop.scss @@ -0,0 +1,14 @@ +// Shared between modals and offcanvases +@mixin overlay-backdrop($zindex, $backdrop-bg, $backdrop-opacity) { + position: fixed; + top: 0; + left: 0; + z-index: $zindex; + width: 100vw; + height: 100vh; + background-color: $backdrop-bg; + + // Fade for backdrop + &.fade { opacity: 0; } + &.show { opacity: $backdrop-opacity; } +} diff --git a/scss/bs5/mixins/_banner.scss b/scss/bs5/mixins/_banner.scss new file mode 100644 index 0000000..20c2fd1 --- /dev/null +++ b/scss/bs5/mixins/_banner.scss @@ -0,0 +1,7 @@ +@mixin bsBanner($file) { + /*! + * Bootstrap #{$file} v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +} diff --git a/scss/bs5/mixins/_border-radius.scss b/scss/bs5/mixins/_border-radius.scss new file mode 100644 index 0000000..616decb --- /dev/null +++ b/scss/bs5/mixins/_border-radius.scss @@ -0,0 +1,78 @@ +// stylelint-disable property-disallowed-list +// Single side border-radius + +// Helper function to replace negative values with 0 +@function valid-radius($radius) { + $return: (); + @each $value in $radius { + @if type-of($value) == number { + $return: append($return, max($value, 0)); + } @else { + $return: append($return, $value); + } + } + @return $return; +} + +// scss-docs-start border-radius-mixins +@mixin border-radius($radius: $border-radius, $fallback-border-radius: false) { + @if $enable-rounded { + border-radius: valid-radius($radius); + } + @else if $fallback-border-radius != false { + border-radius: $fallback-border-radius; + } +} + +@mixin border-top-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + border-top-right-radius: valid-radius($radius); + } +} + +@mixin border-end-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-right-radius: valid-radius($radius); + border-bottom-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-radius($radius: $border-radius) { + @if $enable-rounded { + border-bottom-right-radius: valid-radius($radius); + border-bottom-left-radius: valid-radius($radius); + } +} + +@mixin border-start-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + border-bottom-left-radius: valid-radius($radius); + } +} + +@mixin border-top-start-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + } +} + +@mixin border-top-end-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-end-radius($radius: $border-radius) { + @if $enable-rounded { + border-bottom-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-start-radius($radius: $border-radius) { + @if $enable-rounded { + border-bottom-left-radius: valid-radius($radius); + } +} +// scss-docs-end border-radius-mixins diff --git a/scss/bs5/mixins/_box-shadow.scss b/scss/bs5/mixins/_box-shadow.scss new file mode 100644 index 0000000..4172541 --- /dev/null +++ b/scss/bs5/mixins/_box-shadow.scss @@ -0,0 +1,18 @@ +@mixin box-shadow($shadow...) { + @if $enable-shadows { + $result: (); + + @each $value in $shadow { + @if $value != null { + $result: append($result, $value, "comma"); + } + @if $value == none and length($shadow) > 1 { + @warn "The keyword 'none' must be used as a single argument."; + } + } + + @if (length($result) > 0) { + box-shadow: $result; + } + } +} diff --git a/scss/bs5/mixins/_breakpoints.scss b/scss/bs5/mixins/_breakpoints.scss new file mode 100644 index 0000000..286be89 --- /dev/null +++ b/scss/bs5/mixins/_breakpoints.scss @@ -0,0 +1,127 @@ +// Breakpoint viewport sizes and media queries. +// +// Breakpoints are defined as a map of (name: minimum width), order from small to large: +// +// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px) +// +// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. + +// Name of the next breakpoint, or null for the last breakpoint. +// +// >> breakpoint-next(sm) +// md +// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// md +// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl)) +// md +@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { + $n: index($breakpoint-names, $name); + @if not $n { + @error "breakpoint `#{$name}` not found in `#{$breakpoints}`"; + } + @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); +} + +// Minimum breakpoint width. Null for the smallest (first) breakpoint. +// +// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// 576px +@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { + $min: map-get($breakpoints, $name); + @return if($min != 0, $min, null); +} + +// Maximum breakpoint width. +// The maximum value is reduced by 0.02px to work around the limitations of +// `min-` and `max-` prefixes and viewports with fractional widths. +// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max +// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari. +// See https://bugs.webkit.org/show_bug.cgi?id=178261 +// +// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// 767.98px +@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { + $max: map-get($breakpoints, $name); + @return if($max and $max > 0, $max - .02, null); +} + +// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front. +// Useful for making responsive utilities. +// +// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// "" (Returns a blank string) +// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// "-sm" +@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) { + @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}"); +} + +// Media of at least the minimum breakpoint width. No query for the smallest breakpoint. +// Makes the @content apply to the given breakpoint and wider. +@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + @if $min { + @media (min-width: $min) { + @content; + } + } @else { + @content; + } +} + +// Media of at most the maximum breakpoint width. No query for the largest breakpoint. +// Makes the @content apply to the given breakpoint and narrower. +@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) { + $max: breakpoint-max($name, $breakpoints); + @if $max { + @media (max-width: $max) { + @content; + } + } @else { + @content; + } +} + +// Media that spans multiple breakpoint widths. +// Makes the @content apply between the min and max breakpoints +@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($lower, $breakpoints); + $max: breakpoint-max($upper, $breakpoints); + + @if $min != null and $max != null { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else if $max == null { + @include media-breakpoint-up($lower, $breakpoints) { + @content; + } + } @else if $min == null { + @include media-breakpoint-down($upper, $breakpoints) { + @content; + } + } +} + +// Media between the breakpoint's minimum and maximum widths. +// No minimum for the smallest breakpoint, and no maximum for the largest one. +// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower. +@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + $next: breakpoint-next($name, $breakpoints); + $max: breakpoint-max($next, $breakpoints); + + @if $min != null and $max != null { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else if $max == null { + @include media-breakpoint-up($name, $breakpoints) { + @content; + } + } @else if $min == null { + @include media-breakpoint-down($next, $breakpoints) { + @content; + } + } +} diff --git a/scss/bs5/mixins/_buttons.scss b/scss/bs5/mixins/_buttons.scss new file mode 100644 index 0000000..cf087fd --- /dev/null +++ b/scss/bs5/mixins/_buttons.scss @@ -0,0 +1,70 @@ +// Button variants +// +// Easily pump out default styles, as well as :hover, :focus, :active, +// and disabled options for all buttons + +// scss-docs-start btn-variant-mixin +@mixin button-variant( + $background, + $border, + $color: color-contrast($background), + $hover-background: if($color == $color-contrast-light, shade-color($background, $btn-hover-bg-shade-amount), tint-color($background, $btn-hover-bg-tint-amount)), + $hover-border: if($color == $color-contrast-light, shade-color($border, $btn-hover-border-shade-amount), tint-color($border, $btn-hover-border-tint-amount)), + $hover-color: color-contrast($hover-background), + $active-background: if($color == $color-contrast-light, shade-color($background, $btn-active-bg-shade-amount), tint-color($background, $btn-active-bg-tint-amount)), + $active-border: if($color == $color-contrast-light, shade-color($border, $btn-active-border-shade-amount), tint-color($border, $btn-active-border-tint-amount)), + $active-color: color-contrast($active-background), + $disabled-background: $background, + $disabled-border: $border, + $disabled-color: color-contrast($disabled-background) +) { + --#{$prefix}btn-color: #{$color}; + --#{$prefix}btn-bg: #{$background}; + --#{$prefix}btn-border-color: #{$border}; + --#{$prefix}btn-hover-color: #{$hover-color}; + --#{$prefix}btn-hover-bg: #{$hover-background}; + --#{$prefix}btn-hover-border-color: #{$hover-border}; + --#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix($color, $border, 15%))}; + --#{$prefix}btn-active-color: #{$active-color}; + --#{$prefix}btn-active-bg: #{$active-background}; + --#{$prefix}btn-active-border-color: #{$active-border}; + --#{$prefix}btn-active-shadow: #{$btn-active-box-shadow}; + --#{$prefix}btn-disabled-color: #{$disabled-color}; + --#{$prefix}btn-disabled-bg: #{$disabled-background}; + --#{$prefix}btn-disabled-border-color: #{$disabled-border}; +} +// scss-docs-end btn-variant-mixin + +// scss-docs-start btn-outline-variant-mixin +@mixin button-outline-variant( + $color, + $color-hover: color-contrast($color), + $active-background: $color, + $active-border: $color, + $active-color: color-contrast($active-background) +) { + --#{$prefix}btn-color: #{$color}; + --#{$prefix}btn-border-color: #{$color}; + --#{$prefix}btn-hover-color: #{$color-hover}; + --#{$prefix}btn-hover-bg: #{$active-background}; + --#{$prefix}btn-hover-border-color: #{$active-border}; + --#{$prefix}btn-focus-shadow-rgb: #{to-rgb($color)}; + --#{$prefix}btn-active-color: #{$active-color}; + --#{$prefix}btn-active-bg: #{$active-background}; + --#{$prefix}btn-active-border-color: #{$active-border}; + --#{$prefix}btn-active-shadow: #{$btn-active-box-shadow}; + --#{$prefix}btn-disabled-color: #{$color}; + --#{$prefix}btn-disabled-bg: transparent; + --#{$prefix}btn-disabled-border-color: #{$color}; + --#{$prefix}gradient: none; +} +// scss-docs-end btn-outline-variant-mixin + +// scss-docs-start btn-size-mixin +@mixin button-size($padding-y, $padding-x, $font-size, $border-radius) { + --#{$prefix}btn-padding-y: #{$padding-y}; + --#{$prefix}btn-padding-x: #{$padding-x}; + @include rfs($font-size, --#{$prefix}btn-font-size); + --#{$prefix}btn-border-radius: #{$border-radius}; +} +// scss-docs-end btn-size-mixin diff --git a/scss/bs5/mixins/_caret.scss b/scss/bs5/mixins/_caret.scss new file mode 100644 index 0000000..be73116 --- /dev/null +++ b/scss/bs5/mixins/_caret.scss @@ -0,0 +1,69 @@ +// scss-docs-start caret-mixins +@mixin caret-down($width: $caret-width) { + border-top: $width solid; + border-right: $width solid transparent; + border-bottom: 0; + border-left: $width solid transparent; +} + +@mixin caret-up($width: $caret-width) { + border-top: 0; + border-right: $width solid transparent; + border-bottom: $width solid; + border-left: $width solid transparent; +} + +@mixin caret-end($width: $caret-width) { + border-top: $width solid transparent; + border-right: 0; + border-bottom: $width solid transparent; + border-left: $width solid; +} + +@mixin caret-start($width: $caret-width) { + border-top: $width solid transparent; + border-right: $width solid; + border-bottom: $width solid transparent; +} + +@mixin caret( + $direction: down, + $width: $caret-width, + $spacing: $caret-spacing, + $vertical-align: $caret-vertical-align +) { + @if $enable-caret { + &::after { + display: inline-block; + margin-left: $spacing; + vertical-align: $vertical-align; + content: ""; + @if $direction == down { + @include caret-down($width); + } @else if $direction == up { + @include caret-up($width); + } @else if $direction == end { + @include caret-end($width); + } + } + + @if $direction == start { + &::after { + display: none; + } + + &::before { + display: inline-block; + margin-right: $spacing; + vertical-align: $vertical-align; + content: ""; + @include caret-start($width); + } + } + + &:empty::after { + margin-left: 0; + } + } +} +// scss-docs-end caret-mixins diff --git a/scss/bs5/mixins/_clearfix.scss b/scss/bs5/mixins/_clearfix.scss new file mode 100644 index 0000000..ffc62bb --- /dev/null +++ b/scss/bs5/mixins/_clearfix.scss @@ -0,0 +1,9 @@ +// scss-docs-start clearfix +@mixin clearfix() { + &::after { + display: block; + clear: both; + content: ""; + } +} +// scss-docs-end clearfix diff --git a/scss/bs5/mixins/_color-mode.scss b/scss/bs5/mixins/_color-mode.scss new file mode 100644 index 0000000..03338b0 --- /dev/null +++ b/scss/bs5/mixins/_color-mode.scss @@ -0,0 +1,21 @@ +// scss-docs-start color-mode-mixin +@mixin color-mode($mode: light, $root: false) { + @if $color-mode-type == "media-query" { + @if $root == true { + @media (prefers-color-scheme: $mode) { + :root { + @content; + } + } + } @else { + @media (prefers-color-scheme: $mode) { + @content; + } + } + } @else { + [data-bs-theme="#{$mode}"] { + @content; + } + } +} +// scss-docs-end color-mode-mixin diff --git a/scss/bs5/mixins/_color-scheme.scss b/scss/bs5/mixins/_color-scheme.scss new file mode 100644 index 0000000..90497aa --- /dev/null +++ b/scss/bs5/mixins/_color-scheme.scss @@ -0,0 +1,7 @@ +// scss-docs-start mixin-color-scheme +@mixin color-scheme($name) { + @media (prefers-color-scheme: #{$name}) { + @content; + } +} +// scss-docs-end mixin-color-scheme diff --git a/scss/bs5/mixins/_container.scss b/scss/bs5/mixins/_container.scss new file mode 100644 index 0000000..b9f3351 --- /dev/null +++ b/scss/bs5/mixins/_container.scss @@ -0,0 +1,11 @@ +// Container mixins + +@mixin make-container($gutter: $container-padding-x) { + --#{$prefix}gutter-x: #{$gutter}; + --#{$prefix}gutter-y: 0; + width: 100%; + padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + margin-right: auto; + margin-left: auto; +} diff --git a/scss/bs5/mixins/_deprecate.scss b/scss/bs5/mixins/_deprecate.scss new file mode 100644 index 0000000..df070bc --- /dev/null +++ b/scss/bs5/mixins/_deprecate.scss @@ -0,0 +1,10 @@ +// Deprecate mixin +// +// This mixin can be used to deprecate mixins or functions. +// `$enable-deprecation-messages` is a global variable, `$ignore-warning` is a variable that can be passed to +// some deprecated mixins to suppress the warning (for example if the mixin is still be used in the current version of Bootstrap) +@mixin deprecate($name, $deprecate-version, $remove-version, $ignore-warning: false) { + @if ($enable-deprecation-messages != false and $ignore-warning != true) { + @warn "#{$name} has been deprecated as of #{$deprecate-version}. It will be removed entirely in #{$remove-version}."; + } +} diff --git a/scss/bs5/mixins/_forms.scss b/scss/bs5/mixins/_forms.scss new file mode 100644 index 0000000..00b4764 --- /dev/null +++ b/scss/bs5/mixins/_forms.scss @@ -0,0 +1,163 @@ +// This mixin uses an `if()` technique to be compatible with Dart Sass +// See https://github.com/sass/sass/issues/1873#issuecomment-152293725 for more details + +// scss-docs-start form-validation-mixins +@mixin form-validation-state-selector($state) { + @if ($state == "valid" or $state == "invalid") { + .was-validated #{if(&, "&", "")}:#{$state}, + #{if(&, "&", "")}.is-#{$state} { + @content; + } + } @else { + #{if(&, "&", "")}.is-#{$state} { + @content; + } + } +} + +@mixin form-validation-state( + $state, + $color, + $icon, + $tooltip-color: color-contrast($color), + $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity), + $focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity), + $border-color: $color +) { + .#{$state}-feedback { + display: none; + width: 100%; + margin-top: $form-feedback-margin-top; + @include font-size($form-feedback-font-size); + font-style: $form-feedback-font-style; + color: $color; + } + + .#{$state}-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; // Contain to parent when possible + padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x; + margin-top: .1rem; + @include font-size($form-feedback-tooltip-font-size); + line-height: $form-feedback-tooltip-line-height; + color: $tooltip-color; + background-color: $tooltip-bg-color; + @include border-radius($form-feedback-tooltip-border-radius); + } + + @include form-validation-state-selector($state) { + ~ .#{$state}-feedback, + ~ .#{$state}-tooltip { + display: block; + } + } + + .form-control { + @include form-validation-state-selector($state) { + border-color: $border-color; + + @if $enable-validation-icons { + padding-right: $input-height-inner; + background-image: escape-svg($icon); + background-repeat: no-repeat; + background-position: right $input-height-inner-quarter center; + background-size: $input-height-inner-half $input-height-inner-half; + } + + &:focus { + border-color: $border-color; + @if $enable-shadows { + @include box-shadow($input-box-shadow, $focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $focus-box-shadow; + } + } + } + } + + // stylelint-disable-next-line selector-no-qualifying-type + textarea.form-control { + @include form-validation-state-selector($state) { + @if $enable-validation-icons { + padding-right: $input-height-inner; + background-position: top $input-height-inner-quarter right $input-height-inner-quarter; + } + } + } + + .form-select { + @include form-validation-state-selector($state) { + border-color: $border-color; + + @if $enable-validation-icons { + &:not([multiple]):not([size]), + &:not([multiple])[size="1"] { + --#{$prefix}form-select-bg-icon: #{escape-svg($icon)}; + padding-right: $form-select-feedback-icon-padding-end; + background-position: $form-select-bg-position, $form-select-feedback-icon-position; + background-size: $form-select-bg-size, $form-select-feedback-icon-size; + } + } + + &:focus { + border-color: $border-color; + @if $enable-shadows { + @include box-shadow($form-select-box-shadow, $focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $focus-box-shadow; + } + } + } + } + + .form-control-color { + @include form-validation-state-selector($state) { + @if $enable-validation-icons { + width: add($form-color-width, $input-height-inner); + } + } + } + + .form-check-input { + @include form-validation-state-selector($state) { + border-color: $border-color; + + &:checked { + background-color: $color; + } + + &:focus { + box-shadow: $focus-box-shadow; + } + + ~ .form-check-label { + color: $color; + } + } + } + .form-check-inline .form-check-input { + ~ .#{$state}-feedback { + margin-left: .5em; + } + } + + .input-group { + > .form-control:not(:focus), + > .form-select:not(:focus), + > .form-floating:not(:focus-within) { + @include form-validation-state-selector($state) { + @if $state == "valid" { + z-index: 3; + } @else if $state == "invalid" { + z-index: 4; + } + } + } + } +} +// scss-docs-end form-validation-mixins diff --git a/scss/bs5/mixins/_gradients.scss b/scss/bs5/mixins/_gradients.scss new file mode 100644 index 0000000..608e18d --- /dev/null +++ b/scss/bs5/mixins/_gradients.scss @@ -0,0 +1,47 @@ +// Gradients + +// scss-docs-start gradient-bg-mixin +@mixin gradient-bg($color: null) { + background-color: $color; + + @if $enable-gradients { + background-image: var(--#{$prefix}gradient); + } +} +// scss-docs-end gradient-bg-mixin + +// scss-docs-start gradient-mixins +// Horizontal gradient, from left to right +// +// Creates two color stops, start and end, by specifying a color and position for each color stop. +@mixin gradient-x($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) { + background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent); +} + +// Vertical gradient, from top to bottom +// +// Creates two color stops, start and end, by specifying a color and position for each color stop. +@mixin gradient-y($start-color: $gray-700, $end-color: $gray-800, $start-percent: null, $end-percent: null) { + background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); +} + +@mixin gradient-directional($start-color: $gray-700, $end-color: $gray-800, $deg: 45deg) { + background-image: linear-gradient($deg, $start-color, $end-color); +} + +@mixin gradient-x-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { + background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color); +} + +@mixin gradient-y-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { + background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color); +} + +@mixin gradient-radial($inner-color: $gray-700, $outer-color: $gray-800) { + background-image: radial-gradient(circle, $inner-color, $outer-color); +} + +@mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) { + background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent); +} +// scss-docs-end gradient-mixins diff --git a/scss/bs5/mixins/_grid.scss b/scss/bs5/mixins/_grid.scss new file mode 100644 index 0000000..ea30739 --- /dev/null +++ b/scss/bs5/mixins/_grid.scss @@ -0,0 +1,151 @@ +// Grid system +// +// Generate semantic grid columns with these mixins. + +@mixin make-row($gutter: $grid-gutter-width) { + --#{$prefix}gutter-x: #{$gutter}; + --#{$prefix}gutter-y: 0; + display: flex; + flex-wrap: wrap; + // TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed + margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list + margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list + margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list +} + +@mixin make-col-ready() { + // Add box sizing if only the grid is loaded + box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null); + // Prevent columns from becoming too narrow when at smaller grid tiers by + // always setting `width: 100%;`. This works because we set the width + // later on to override this initial width. + flex-shrink: 0; + width: 100%; + max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid + padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + margin-top: var(--#{$prefix}gutter-y); +} + +@mixin make-col($size: false, $columns: $grid-columns) { + @if $size { + flex: 0 0 auto; + width: percentage(divide($size, $columns)); + + } @else { + flex: 1 1 0; + max-width: 100%; + } +} + +@mixin make-col-auto() { + flex: 0 0 auto; + width: auto; +} + +@mixin make-col-offset($size, $columns: $grid-columns) { + $num: divide($size, $columns); + margin-left: if($num == 0, 0, percentage($num)); +} + +// Row columns +// +// Specify on a parent element(e.g., .row) to force immediate children into NN +// number of columns. Supports wrapping to new lines, but does not do a Masonry +// style grid. +@mixin row-cols($count) { + > * { + flex: 0 0 auto; + width: percentage(divide(1, $count)); + } +} + +// Framework grid generation +// +// Used only by Bootstrap to generate the correct number of grid classes given +// any value of `$grid-columns`. + +@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) { + @each $breakpoint in map-keys($breakpoints) { + $infix: breakpoint-infix($breakpoint, $breakpoints); + + @include media-breakpoint-up($breakpoint, $breakpoints) { + // Provide basic `.col-{bp}` classes for equal-width flexbox columns + .col#{$infix} { + flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4 + } + + .row-cols#{$infix}-auto > * { + @include make-col-auto(); + } + + @if $grid-row-columns > 0 { + @for $i from 1 through $grid-row-columns { + .row-cols#{$infix}-#{$i} { + @include row-cols($i); + } + } + } + + .col#{$infix}-auto { + @include make-col-auto(); + } + + @if $columns > 0 { + @for $i from 1 through $columns { + .col#{$infix}-#{$i} { + @include make-col($i, $columns); + } + } + + // `$columns - 1` because offsetting by the width of an entire row isn't possible + @for $i from 0 through ($columns - 1) { + @if not ($infix == "" and $i == 0) { // Avoid emitting useless .offset-0 + .offset#{$infix}-#{$i} { + @include make-col-offset($i, $columns); + } + } + } + } + + // Gutters + // + // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns. + @each $key, $value in $gutters { + .g#{$infix}-#{$key}, + .gx#{$infix}-#{$key} { + --#{$prefix}gutter-x: #{$value}; + } + + .g#{$infix}-#{$key}, + .gy#{$infix}-#{$key} { + --#{$prefix}gutter-y: #{$value}; + } + } + } + } +} + +@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) { + @each $breakpoint in map-keys($breakpoints) { + $infix: breakpoint-infix($breakpoint, $breakpoints); + + @include media-breakpoint-up($breakpoint, $breakpoints) { + @if $columns > 0 { + @for $i from 1 through $columns { + .g-col#{$infix}-#{$i} { + grid-column: auto / span $i; + } + } + + // Start with `1` because `0` is an invalid value. + // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible. + @for $i from 1 through ($columns - 1) { + .g-start#{$infix}-#{$i} { + grid-column-start: $i; + } + } + } + } + } +} diff --git a/scss/bs5/mixins/_image.scss b/scss/bs5/mixins/_image.scss new file mode 100644 index 0000000..e1df779 --- /dev/null +++ b/scss/bs5/mixins/_image.scss @@ -0,0 +1,16 @@ +// Image Mixins +// - Responsive image +// - Retina image + + +// Responsive image +// +// Keep images from scaling beyond the width of their parents. + +@mixin img-fluid { + // Part 1: Set a maximum relative to the parent + max-width: 100%; + // Part 2: Override the height to auto, otherwise images will be stretched + // when setting a width and height attribute on the img element. + height: auto; +} diff --git a/scss/bs5/mixins/_list-group.scss b/scss/bs5/mixins/_list-group.scss new file mode 100644 index 0000000..6274f34 --- /dev/null +++ b/scss/bs5/mixins/_list-group.scss @@ -0,0 +1,26 @@ +@include deprecate("`list-group-item-variant()`", "v5.3.0", "v6.0.0"); + +// List Groups + +// scss-docs-start list-group-mixin +@mixin list-group-item-variant($state, $background, $color) { + .list-group-item-#{$state} { + color: $color; + background-color: $background; + + &.list-group-item-action { + &:hover, + &:focus { + color: $color; + background-color: shade-color($background, 10%); + } + + &.active { + color: $white; + background-color: $color; + border-color: $color; + } + } + } +} +// scss-docs-end list-group-mixin diff --git a/scss/bs5/mixins/_lists.scss b/scss/bs5/mixins/_lists.scss new file mode 100644 index 0000000..2518562 --- /dev/null +++ b/scss/bs5/mixins/_lists.scss @@ -0,0 +1,7 @@ +// Lists + +// Unstyled keeps list items block level, just removes default browser padding and list-style +@mixin list-unstyled { + padding-left: 0; + list-style: none; +} diff --git a/scss/bs5/mixins/_pagination.scss b/scss/bs5/mixins/_pagination.scss new file mode 100644 index 0000000..0d65796 --- /dev/null +++ b/scss/bs5/mixins/_pagination.scss @@ -0,0 +1,10 @@ +// Pagination + +// scss-docs-start pagination-mixin +@mixin pagination-size($padding-y, $padding-x, $font-size, $border-radius) { + --#{$prefix}pagination-padding-x: #{$padding-x}; + --#{$prefix}pagination-padding-y: #{$padding-y}; + @include rfs($font-size, --#{$prefix}pagination-font-size); + --#{$prefix}pagination-border-radius: #{$border-radius}; +} +// scss-docs-end pagination-mixin diff --git a/scss/bs5/mixins/_reset-text.scss b/scss/bs5/mixins/_reset-text.scss new file mode 100644 index 0000000..f5bd1af --- /dev/null +++ b/scss/bs5/mixins/_reset-text.scss @@ -0,0 +1,17 @@ +@mixin reset-text { + font-family: $font-family-base; + // We deliberately do NOT reset font-size or overflow-wrap / word-wrap. + font-style: normal; + font-weight: $font-weight-normal; + line-height: $line-height-base; + text-align: left; // Fallback for where `start` is not supported + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; +} diff --git a/scss/bs5/mixins/_resize.scss b/scss/bs5/mixins/_resize.scss new file mode 100644 index 0000000..66f233a --- /dev/null +++ b/scss/bs5/mixins/_resize.scss @@ -0,0 +1,6 @@ +// Resize anything + +@mixin resizable($direction) { + overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` + resize: $direction; // Options: horizontal, vertical, both +} diff --git a/scss/bs5/mixins/_table-variants.scss b/scss/bs5/mixins/_table-variants.scss new file mode 100644 index 0000000..5fe1b9b --- /dev/null +++ b/scss/bs5/mixins/_table-variants.scss @@ -0,0 +1,24 @@ +// scss-docs-start table-variant +@mixin table-variant($state, $background) { + .table-#{$state} { + $color: color-contrast(opaque($body-bg, $background)); + $hover-bg: mix($color, $background, percentage($table-hover-bg-factor)); + $striped-bg: mix($color, $background, percentage($table-striped-bg-factor)); + $active-bg: mix($color, $background, percentage($table-active-bg-factor)); + $table-border-color: mix($color, $background, percentage($table-border-factor)); + + --#{$prefix}table-color: #{$color}; + --#{$prefix}table-bg: #{$background}; + --#{$prefix}table-border-color: #{$table-border-color}; + --#{$prefix}table-striped-bg: #{$striped-bg}; + --#{$prefix}table-striped-color: #{color-contrast($striped-bg)}; + --#{$prefix}table-active-bg: #{$active-bg}; + --#{$prefix}table-active-color: #{color-contrast($active-bg)}; + --#{$prefix}table-hover-bg: #{$hover-bg}; + --#{$prefix}table-hover-color: #{color-contrast($hover-bg)}; + + color: var(--#{$prefix}table-color); + border-color: var(--#{$prefix}table-border-color); + } +} +// scss-docs-end table-variant diff --git a/scss/bs5/mixins/_text-truncate.scss b/scss/bs5/mixins/_text-truncate.scss new file mode 100644 index 0000000..3504bb1 --- /dev/null +++ b/scss/bs5/mixins/_text-truncate.scss @@ -0,0 +1,8 @@ +// Text truncate +// Requires inline-block or block for proper styling + +@mixin text-truncate() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/scss/bs5/mixins/_transition.scss b/scss/bs5/mixins/_transition.scss new file mode 100644 index 0000000..d437f6d --- /dev/null +++ b/scss/bs5/mixins/_transition.scss @@ -0,0 +1,26 @@ +// stylelint-disable property-disallowed-list +@mixin transition($transition...) { + @if length($transition) == 0 { + $transition: $transition-base; + } + + @if length($transition) > 1 { + @each $value in $transition { + @if $value == null or $value == none { + @warn "The keyword 'none' or 'null' must be used as a single argument."; + } + } + } + + @if $enable-transitions { + @if nth($transition, 1) != null { + transition: $transition; + } + + @if $enable-reduced-motion and nth($transition, 1) != null and nth($transition, 1) != none { + @media (prefers-reduced-motion: reduce) { + transition: none; + } + } + } +} diff --git a/scss/bs5/mixins/_utilities.scss b/scss/bs5/mixins/_utilities.scss new file mode 100644 index 0000000..4795e89 --- /dev/null +++ b/scss/bs5/mixins/_utilities.scss @@ -0,0 +1,97 @@ +// Utility generator +// Used to generate utilities & print utilities +@mixin generate-utility($utility, $infix: "", $is-rfs-media-query: false) { + $values: map-get($utility, values); + + // If the values are a list or string, convert it into a map + @if type-of($values) == "string" or type-of(nth($values, 1)) != "list" { + $values: zip($values, $values); + } + + @each $key, $value in $values { + $properties: map-get($utility, property); + + // Multiple properties are possible, for example with vertical or horizontal margins or paddings + @if type-of($properties) == "string" { + $properties: append((), $properties); + } + + // Use custom class if present + $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1)); + $property-class: if($property-class == null, "", $property-class); + + // Use custom CSS variable name if present, otherwise default to `class` + $css-variable-name: if(map-has-key($utility, css-variable-name), map-get($utility, css-variable-name), map-get($utility, class)); + + // State params to generate pseudo-classes + $state: if(map-has-key($utility, state), map-get($utility, state), ()); + + $infix: if($property-class == "" and str-slice($infix, 1, 1) == "-", str-slice($infix, 2), $infix); + + // Don't prefix if value key is null (e.g. with shadow class) + $property-class-modifier: if($key, if($property-class == "" and $infix == "", "", "-") + $key, ""); + + @if map-get($utility, rfs) { + // Inside the media query + @if $is-rfs-media-query { + $val: rfs-value($value); + + // Do not render anything if fluid and non fluid values are the same + $value: if($val == rfs-fluid-value($value), null, $val); + } + @else { + $value: rfs-fluid-value($value); + } + } + + $is-css-var: map-get($utility, css-var); + $is-local-vars: map-get($utility, local-vars); + $is-rtl: map-get($utility, rtl); + + @if $value != null { + @if $is-rtl == false { + /* rtl:begin:remove */ + } + + @if $is-css-var { + .#{$property-class + $infix + $property-class-modifier} { + --#{$prefix}#{$css-variable-name}: #{$value}; + } + + @each $pseudo in $state { + .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} { + --#{$prefix}#{$css-variable-name}: #{$value}; + } + } + } @else { + .#{$property-class + $infix + $property-class-modifier} { + @each $property in $properties { + @if $is-local-vars { + @each $local-var, $variable in $is-local-vars { + --#{$prefix}#{$local-var}: #{$variable}; + } + } + #{$property}: $value if($enable-important-utilities, !important, null); + } + } + + @each $pseudo in $state { + .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} { + @each $property in $properties { + @if $is-local-vars { + @each $local-var, $variable in $is-local-vars { + --#{$prefix}#{$local-var}: #{$variable}; + } + } + #{$property}: $value if($enable-important-utilities, !important, null); + } + } + } + } + + @if $is-rtl == false { + /* rtl:end:remove */ + } + } + } +} diff --git a/scss/bs5/mixins/_visually-hidden.scss b/scss/bs5/mixins/_visually-hidden.scss new file mode 100644 index 0000000..082aeec --- /dev/null +++ b/scss/bs5/mixins/_visually-hidden.scss @@ -0,0 +1,33 @@ +// stylelint-disable declaration-no-important + +// Hide content visually while keeping it accessible to assistive technologies +// +// See: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/ +// See: https://kittygiraudel.com/2016/10/13/css-hide-and-seek/ + +@mixin visually-hidden() { + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; // Fix for https://github.com/twbs/bootstrap/issues/25686 + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; + + // Fix for positioned table caption that could become anonymous cells + &:not(caption) { + position: absolute !important; + } +} + +// Use to only display content when it's focused, or one of its child elements is focused +// (i.e. when focus is within the element/container that the class was applied to) +// +// Useful for "Skip to main content" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 + +@mixin visually-hidden-focusable() { + &:not(:focus):not(:focus-within) { + @include visually-hidden(); + } +} diff --git a/scss/bs5/utilities/_api.scss b/scss/bs5/utilities/_api.scss new file mode 100644 index 0000000..62e1d39 --- /dev/null +++ b/scss/bs5/utilities/_api.scss @@ -0,0 +1,47 @@ +// Loop over each breakpoint +@each $breakpoint in map-keys($grid-breakpoints) { + + // Generate media query if needed + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + // Loop over each utility property + @each $key, $utility in $utilities { + // The utility can be disabled with `false`, thus check if the utility is a map first + // Only proceed if responsive media queries are enabled or if it's the base media query + @if type-of($utility) == "map" and (map-get($utility, responsive) or $infix == "") { + @include generate-utility($utility, $infix); + } + } + } +} + +// RFS rescaling +@media (min-width: $rfs-mq-value) { + @each $breakpoint in map-keys($grid-breakpoints) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + @if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) { + // Loop over each utility property + @each $key, $utility in $utilities { + // The utility can be disabled with `false`, thus check if the utility is a map first + // Only proceed if responsive media queries are enabled or if it's the base media query + @if type-of($utility) == "map" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == "") { + @include generate-utility($utility, $infix, true); + } + } + } + } +} + + +// Print utilities +@media print { + @each $key, $utility in $utilities { + // The utility can be disabled with `false`, thus check if the utility is a map first + // Then check if the utility needs print styles + @if type-of($utility) == "map" and map-get($utility, print) == true { + @include generate-utility($utility, "-print"); + } + } +} From 9762e290c64a40df7ab67555f319acd04f558bb8 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:54:47 +0000 Subject: [PATCH 18/82] 2.2.0 --- rules/compiler.php | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/rules/compiler.php b/rules/compiler.php index dc9818a..92dd248 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -102,9 +102,7 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input // get params $gplusProfile = htmlspecialchars($params->gplusProfile); -$twbs_version = htmlspecialchars($params->get(twbs_version, '5')); - - +$twbs_version = (empty($params->twbs_version)) ? '5' : htmlspecialchars($params->twbs_version); $itemVideoHeight= htmlspecialchars($params->itemVideoHeight); $itemLeadHeight = htmlspecialchars($params->itemLeadHeight); $itemLeadWidth = htmlspecialchars($params->itemLeadWidth); @@ -114,8 +112,7 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input $itemMargin = htmlspecialchars($params->itemMargin); $hlMarginTop = htmlspecialchars($params->hlMarginTop); -$hlMarginLeft = htmlspecialchars($params->hlMarginLeft); -if ($hlMarginLeft > " " ) {} else { $hlMarginLeft = 0; } +$hlMarginLeft = (empty($hlMarginLeft)) ? 0 : htmlspecialchars($params->hlMarginLeft); $hlWidth = htmlspecialchars($params->hlWidth); $hlHeight = htmlspecialchars($params->hlHeight); $hlMarginBottom = htmlspecialchars($params->hlMarginBottom); From fe221b58f5eaa7ea32390225fe399bc2ff3a0d64 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Sat, 5 Oct 2024 06:59:41 +0000 Subject: [PATCH 19/82] 2.2.0 temp bs3 vars in _template_variables.scss --- scss/_template_variables.scss | 52 ++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss index 6f0877e..0e1b369 100644 --- a/scss/_template_variables.scss +++ b/scss/_template_variables.scss @@ -1,4 +1,5 @@ /* template_variables.scss */ +// 20241005 use calc(@include media-breakpoint-up(lg)) in stead of $container-lg // standard variables for this template. // -------------------------20190202 // colors @@ -20,6 +21,38 @@ $activenavbarfg: #fff; $specialgreygradientstart: #ffffff; $specialgreygradientend: #e6e6e6; +//## temporary Define the maximum width of `.container` for different screen sizes with BS 3 variables + +// Small screen / tablet +$container-tablet: (720px + $grid-gutter-width); +//** For `$screen-sm-min` and up. +$container-sm: $container-tablet; + +// Medium screen / desktop +$container-desktop: (940px + $grid-gutter-width); +//** For `$screen-md-min` and up. +$container-md: $container-desktop; + +// Large screen / wide desktop +$container-large-desktop: (1140px + $grid-gutter-width); +//** For `$screen-lg-min` and up. +$container-lg: calc(@include media-breakpoint-up(lg)); // was $container-large-desktop; + +// Large screen / wide desktop tijdelijk bs3 type vaste breakpoints +$screen-xl-min: 1200px; +$screen-xxl-min: 1440px; +$screen-xxxl-min: 1600px; + +//** Deprecated `$screen-lg-desktop` as of v3.0.1 +$screen-lg-desktop: was $screen-lg-min; + +// So media queries don't overlap when required, provide a maximum +$screen-lg-max: ($screen-xl-min - 1); +$screen-xl-max: ($screen-xxl-min - 1); +$screen-xxl-max: ($screen-xxxl-min - 1); + + + // Typography @@ -55,7 +88,7 @@ $wsaNavbarRightWidth: auto; $wsaVideoHeight: 80%; // iets hoger dan 4x3 100 * 3 / 4% ; 100 * 9 / 16%; // 56.25% $wsaVideoHeightExtra: 25px; $wsaVideoItemWidth: 100%; -$wsaVideoAutoItemWidth: $container-lg; +$wsaVideoAutoItemWidth: $container-lg; $asModLangFloat: right; $bg0Z-index: auto; @@ -108,15 +141,8 @@ $wsa12Col : (100% - (13 * $wsaInnerMargin)) / 12 ; $span1 : $wsa12Col; -// Large screen / wide desktop tijdelijk bs3 type vaste breakpoints -$screen-xl-min: 1200px; -$screen-xxl-min: 1440px; -$screen-xxxl-min: 1600px; - -//** Deprecated `$screen-lg-desktop` as of v3.0.1 -$screen-lg-desktop: $screen-lg-min; - -// So media queries don't overlap when required, provide a maximum -$screen-lg-max: ($screen-xl-min - 1); -$screen-xl-max: ($screen-xxl-min - 1); -$screen-xxl-max: ($screen-xxxl-min - 1); +.test01 { + width:$wsaVideoAutoItemWidth; + height:$screen-lg-desktop; + +} From 2531847e1a4b6e53cee82b797614509a53910576 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Sat, 5 Oct 2024 07:17:08 +0000 Subject: [PATCH 20/82] 2.2.0 tv met v3 vars works temporary --- scss/_template_variables.scss | 45 +++++++++++++++++++++++++++++++---- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss index 0e1b369..2ed4f30 100644 --- a/scss/_template_variables.scss +++ b/scss/_template_variables.scss @@ -23,18 +23,55 @@ $specialgreygradientend: #e6e6e6; //## temporary Define the maximum width of `.container` for different screen sizes with BS 3 variables +// Extra small screen / phone +//** Deprecated `$screen-xs` as of v3.0.1 +$screen-xs: 480px; +//** Deprecated `$screen-xs-min` as of v3.2.0 +$screen-xs-min: $screen-xs; +//** Deprecated `$screen-phone` as of v3.0.1 +$screen-phone: $screen-xs-min; + +// Small screen / tablet +//** Deprecated `$screen-sm` as of v3.0.1 +$screen-sm: 768px; +$screen-sm-min: $screen-sm; +//** Deprecated `$screen-tablet` as of v3.0.1 +$screen-tablet: $screen-sm-min; + +// Medium screen / desktop +//** Deprecated `$screen-md` as of v3.0.1 +$screen-md: 992px; +$screen-md-min: $screen-md; +//** Deprecated `$screen-desktop` as of v3.0.1 +$screen-desktop: $screen-md-min; + +// Large screen / wide desktop +//** Deprecated `$screen-lg` as of v3.0.1 +$screen-lg: 1200px; +$screen-lg-min: $screen-lg; +//** Deprecated `$screen-lg-desktop` as of v3.0.1 +$screen-lg-desktop: $screen-lg-min; + +// So media queries don't overlap when required, provide a maximum +$screen-xs-max: ($screen-sm-min - 1); +$screen-sm-max: ($screen-md-min - 1); +$screen-md-max: ($screen-lg-min - 1); + + // Small screen / tablet -$container-tablet: (720px + $grid-gutter-width); +$grid-gutter-width: 1.5rem !default; // from _bs5 variabels. + +$container-tablet: calc(720px + $grid-gutter-width); //** For `$screen-sm-min` and up. $container-sm: $container-tablet; // Medium screen / desktop -$container-desktop: (940px + $grid-gutter-width); +$container-desktop: calc(940px + $grid-gutter-width); //** For `$screen-md-min` and up. $container-md: $container-desktop; // Large screen / wide desktop -$container-large-desktop: (1140px + $grid-gutter-width); +$container-large-desktop: calc(1140px + $grid-gutter-width); //** For `$screen-lg-min` and up. $container-lg: calc(@include media-breakpoint-up(lg)); // was $container-large-desktop; @@ -44,7 +81,7 @@ $screen-xxl-min: 1440px; $screen-xxxl-min: 1600px; //** Deprecated `$screen-lg-desktop` as of v3.0.1 -$screen-lg-desktop: was $screen-lg-min; +$screen-lg-desktop: $screen-lg-min; // So media queries don't overlap when required, provide a maximum $screen-lg-max: ($screen-xl-min - 1); From c054ec93b668b0521e63932176a4ead8f10e6e2b Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Sat, 5 Oct 2024 08:00:47 +0000 Subject: [PATCH 21/82] 2.2.0 compile succesfull with to many old vars --- scss/_template_variables.scss | 398 +++++++++++++++++++++++++++++++++- 1 file changed, 396 insertions(+), 2 deletions(-) diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss index 2ed4f30..3d82ced 100644 --- a/scss/_template_variables.scss +++ b/scss/_template_variables.scss @@ -22,6 +22,92 @@ $specialgreygradientstart: #ffffff; $specialgreygradientend: #e6e6e6; //## temporary Define the maximum width of `.container` for different screen sizes with BS 3 variables +//## Gray and brand colors for use across Bootstrap. + +$gray-base: #000; +$gray-darker: lighten($gray-base, 13.5%); // #222 +$gray-dark: lighten($gray-base, 20%); // #333 +$gray: lighten($gray-base, 33.5%); // #555 +$gray-light: lighten($gray-base, 46.7%); // #777 +$gray-lighter: lighten($gray-base, 93.5%); // #eee + +$brand-primary: darken(#428bca, 6.5%); // #337ab7 +$brand-success: #5cb85c; +$brand-info: #5bc0de; +$brand-warning: #f0ad4e; +$brand-danger: #d9534f; + + +//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start). + +$padding-base-vertical: 6px; +$padding-base-horizontal: 12px; + +$padding-large-vertical: 10px; +$padding-large-horizontal: 16px; + +$padding-small-vertical: 5px; +$padding-small-horizontal: 10px; + +$padding-xs-vertical: 1px; +$padding-xs-horizontal: 5px; + +$line-height-large: 1.3333333; // extra decimals for Win 8.1 Chrome +$line-height-small: 1.5; + +$border-radius-base: 4px; +$border-radius-large: 6px; +$border-radius-small: 3px; + +//** Global color for active items (e.g., navs or dropdowns). +$component-active-color: #fff; +//** Global background color for active items (e.g., navs or dropdowns). +$component-active-bg: $brand-primary; + +//** Width of the `border` for generating carets that indicator dropdowns. +$caret-width-base: 4px; +//** Carets increase slightly in size for larger components. +$caret-width-large: 5px; + +//** Background color for ``. +$body-bg: #fff; +//** Global text color on ``. +$text-color: $gray-dark; + +//** Global textual link color. +$link-color: $brand-primary; +//** Link hover color set via `darken()` function. +$link-hover-color: darken($link-color, 15%); +//** Link hover decoration. +$link-hover-decoration: underline; + + + +//## Font, line-height, and color for body text, headings, and more. + +$font-family-sans-serif: "Helvetica Neue", Helvetica, Arial, sans-serif; +$font-family-serif: Georgia, "Times New Roman", Times, serif; +//** Default monospace fonts for ``, ``, and `
`.
+$font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
+$font-family-base:        $font-family-sans-serif;
+
+$font-size-base:          14px;
+$font-size-large:         ceil(($font-size-base * 1.25)); // ~18px
+$font-size-small:         ceil(($font-size-base * 0.85)); // ~12px
+
+$font-size-h1:            floor(($font-size-base * 2.6)); // ~36px
+$font-size-h2:            floor(($font-size-base * 2.15)); // ~30px
+$font-size-h3:            ceil(($font-size-base * 1.7)); // ~24px
+$font-size-h4:            ceil(($font-size-base * 1.25)); // ~18px
+$font-size-h5:            $font-size-base;
+$font-size-h6:            ceil(($font-size-base * 0.85)); // ~12px
+
+
+//** Unit-less `line-height` for use in components like buttons.
+$line-height-base:        1.428571429; // 20/14
+//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+$line-height-computed:    floor(($font-size-base * $line-height-base)); // ~20px
+
 
 // Extra small screen / phone
 //** Deprecated `$screen-xs` as of v3.0.1
@@ -88,9 +174,317 @@ $screen-lg-max:              ($screen-xl-min - 1);
 $screen-xl-max:              ($screen-xxl-min - 1);
 $screen-xxl-max:             ($screen-xxxl-min - 1);
 
+//== Navbar
+//
+//##
 
-
-
+// Basics of a navbar
+$navbar-height:                    50px;
+$navbar-margin-bottom:             $line-height-computed;
+$navbar-border-radius:             $border-radius-base;
+$navbar-padding-horizontal:        floor(($grid-gutter-width / 2));
+$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2);
+$navbar-collapse-max-height:       340px;
+
+$navbar-default-color:             #777;
+$navbar-default-bg:                #f8f8f8;
+$navbar-default-border:            darken($navbar-default-bg, 6.5%);
+
+// Navbar links
+$navbar-default-link-color:                #777;
+$navbar-default-link-hover-color:          #333;
+$navbar-default-link-hover-bg:             transparent;
+$navbar-default-link-active-color:         #555;
+$navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%);
+$navbar-default-link-disabled-color:       #ccc;
+$navbar-default-link-disabled-bg:          transparent;
+
+// Navbar brand label
+$navbar-default-brand-color:               $navbar-default-link-color;
+$navbar-default-brand-hover-color:         darken($navbar-default-brand-color, 10%);
+$navbar-default-brand-hover-bg:            transparent;
+
+// Navbar toggle
+$navbar-default-toggle-hover-bg:           #ddd;
+$navbar-default-toggle-icon-bar-bg:        #888;
+$navbar-default-toggle-border-color:       #ddd;
+
+//=== Shared nav styles
+$nav-link-padding:                          10px 15px;
+$nav-link-hover-bg:                         $gray-lighter;
+
+$nav-disabled-link-color:                   $gray-light;
+$nav-disabled-link-hover-color:             $gray-light;
+
+//== Tabs
+$nav-tabs-border-color:                     #ddd;
+
+$nav-tabs-link-hover-border-color:          $gray-lighter;
+
+$nav-tabs-active-link-hover-bg:             $body-bg;
+$nav-tabs-active-link-hover-color:          $gray;
+$nav-tabs-active-link-hover-border-color:   #ddd;
+
+$nav-tabs-justified-link-border-color:            #ddd;
+$nav-tabs-justified-active-link-border-color:     $body-bg;
+
+//== Pills
+$nav-pills-border-radius:                   $border-radius-base;
+$nav-pills-active-link-hover-bg:            $component-active-bg;
+$nav-pills-active-link-hover-color:         $component-active-color;
+
+//** Disabled cursor for form controls and buttons.
+$cursor-disabled:                not-allowed;
+
+
+//== Dropdowns
+//
+//## Dropdown menu container and contents.
+
+//** Background for the dropdown menu.
+$dropdown-bg:                    #fff;
+//** Dropdown menu `border-color`.
+$dropdown-border:                rgba(0,0,0,.15);
+//** Dropdown menu `border-color` **for IE8**.
+$dropdown-fallback-border:       #ccc;
+//** Divider color for between dropdown items.
+$dropdown-divider-bg:            #e5e5e5;
+
+//** Dropdown link text color.
+$dropdown-link-color:            $gray-dark;
+//** Hover color for dropdown links.
+$dropdown-link-hover-color:      darken($gray-dark, 5%);
+//** Hover background for dropdown links.
+$dropdown-link-hover-bg:         #f5f5f5;
+
+//** Active dropdown menu item text color.
+$dropdown-link-active-color:     $component-active-color;
+//** Active dropdown menu item background color.
+$dropdown-link-active-bg:        $component-active-bg;
+
+//** Disabled dropdown menu item background color.
+$dropdown-link-disabled-color:   $gray-light;
+
+//** Text color for headers within dropdown menus.
+$dropdown-header-color:          $gray-light;
+
+//** Deprecated `$dropdown-caret-color` as of v3.1.0
+$dropdown-caret-color:           #000;
+
+
+
+// end BS3 temporary variables
+// bs4 temp vars
+// Color system
+
+$white:    #fff !default;
+$gray-100: #f8f9fa !default;
+$gray-200: #e9ecef !default;
+$gray-300: #dee2e6 !default;
+$gray-400: #ced4da !default;
+$gray-500: #adb5bd !default;
+$gray-600: #6c757d !default;
+$gray-700: #495057 !default;
+$gray-800: #343a40 !default;
+$gray-900: #212529 !default;
+$black:    #000 !default;
+
+$grays: () !default;
+$grays: map-merge(
+  (
+    "100": $gray-100,
+    "200": $gray-200,
+    "300": $gray-300,
+    "400": $gray-400,
+    "500": $gray-500,
+    "600": $gray-600,
+    "700": $gray-700,
+    "800": $gray-800,
+    "900": $gray-900
+  ),
+  $grays
+);
+
+$blue:    #007bff !default;
+$indigo:  #6610f2 !default;
+$purple:  #6f42c1 !default;
+$pink:    #e83e8c !default;
+$red:     #dc3545 !default;
+$orange:  #fd7e14 !default;
+$yellow:  #ffc107 !default;
+$green:   #28a745 !default;
+$teal:    #20c997 !default;
+$cyan:    #17a2b8 !default;
+
+$colors: () !default;
+$colors: map-merge(
+  (
+    "blue":       $blue,
+    "indigo":     $indigo,
+    "purple":     $purple,
+    "pink":       $pink,
+    "red":        $red,
+    "orange":     $orange,
+    "yellow":     $yellow,
+    "green":      $green,
+    "teal":       $teal,
+    "cyan":       $cyan,
+    "white":      $white,
+    "gray":       $gray-600,
+    "gray-dark":  $gray-800
+  ),
+  $colors
+);
+
+$primary:       $blue !default;
+$secondary:     $gray-600 !default;
+$success:       $green !default;
+$info:          $cyan !default;
+$warning:       $yellow !default;
+$danger:        $red !default;
+$light:         $gray-100 !default;
+$dark:          $gray-800 !default;
+
+$theme-colors: () !default;
+$theme-colors: map-merge(
+  (
+    "primary":    $primary,
+    "secondary":  $secondary,
+    "success":    $success,
+    "info":       $info,
+    "warning":    $warning,
+    "danger":     $danger,
+    "light":      $light,
+    "dark":       $dark
+  ),
+  $theme-colors
+);
+// Components
+//
+// Define common padding and border radius sizes and more.
+
+$line-height-lg:              1.5 !default;
+$line-height-sm:              1.5 !default;
+
+$border-width:                1px !default;
+$border-color:                $gray-300 !default;
+
+$border-radius:               .25rem !default;
+$border-radius-lg:            .3rem !default;
+$border-radius-sm:            .2rem !default;
+
+$rounded-pill:                50rem !default;
+
+$box-shadow-sm:               0 .125rem .25rem rgba($black, .075) !default;
+$box-shadow:                  0 .5rem 1rem rgba($black, .15) !default;
+$box-shadow-lg:               0 1rem 3rem rgba($black, .175) !default;
+
+$component-active-color:      $white !default;
+$component-active-bg:         theme-color("primary") !default;
+
+$caret-width:                 .3em !default;
+$caret-vertical-align:        $caret-width * .85 !default;
+$caret-spacing:               $caret-width * .85 !default;
+
+$transition-base:             all .2s ease-in-out !default;
+$transition-fade:             opacity .15s linear !default;
+$transition-collapse:         height .35s ease !default;
+$transition-collapse-width:   width .35s ease !default;
+
+$embed-responsive-aspect-ratios: () !default;
+$embed-responsive-aspect-ratios: join(
+  (
+    (21 9),
+    (16 9),
+    (4 3),
+    (1 1),
+  ),
+  $embed-responsive-aspect-ratios
+);
+
+$spacer: 1rem !default;
+$spacers: () !default;
+$spacers: map-merge(
+  (
+    0: 0,
+    1: ($spacer * .25),
+    2: ($spacer * .5),
+    3: $spacer,
+    4: ($spacer * 1.5),
+    5: ($spacer * 3)
+  ),
+  $spacers
+);
+
+
+// Body
+//
+// Settings for the `` element.
+
+$body-bg:                   $white !default;
+$body-color:                $gray-900 !default;
+
+$nav-divider-color:                 $gray-200 !default;
+$nav-divider-margin-y:              $spacer * .5 !default;
+
+
+
+$navbar-dark-color:                 rgba($white, .5) !default;
+$navbar-dark-hover-color:           rgba($white, .75) !default;
+$navbar-dark-active-color:          $white !default;
+$navbar-dark-disabled-color:        rgba($white, .25) !default;
+$navbar-dark-toggler-icon-bg:       url("data:image/svg+xml,") !default;
+$navbar-dark-toggler-border-color:  rgba($white, .1) !default;
+
+$navbar-light-color:                rgba($black, .5) !default;
+$navbar-light-hover-color:          rgba($black, .7) !default;
+$navbar-light-active-color:         rgba($black, .9) !default;
+$navbar-light-disabled-color:       rgba($black, .3) !default;
+$navbar-light-toggler-icon-bg:      url("data:image/svg+xml,") !default;
+$navbar-light-toggler-border-color: rgba($black, .1) !default;
+
+$navbar-light-brand-color:                $navbar-light-active-color !default;
+$navbar-light-brand-hover-color:          $navbar-light-active-color !default;
+$navbar-dark-brand-color:                 $navbar-dark-active-color !default;
+$navbar-dark-brand-hover-color:           $navbar-dark-active-color !default;
+
+// Dropdowns
+//
+// Dropdown menu container and contents.
+
+$dropdown-min-width:                10rem !default;
+$dropdown-padding-x:                0 !default;
+$dropdown-padding-y:                .5rem !default;
+$dropdown-spacer:                   .125rem !default;
+$dropdown-font-size:                $font-size-base !default;
+$dropdown-color:                    $body-color !default;
+$dropdown-bg:                       $white !default;
+$dropdown-border-color:             rgba($black, .15) !default;
+$dropdown-border-radius:            $border-radius !default;
+$dropdown-border-width:             $border-width !default;
+$dropdown-inner-border-radius:      subtract($dropdown-border-radius, $dropdown-border-width) !default;
+$dropdown-divider-bg:               $gray-200 !default;
+$dropdown-divider-margin-y:         $nav-divider-margin-y !default;
+$dropdown-box-shadow:               0 .5rem 1rem rgba($black, .175) !default;
+
+$dropdown-link-color:               $gray-900 !default;
+$dropdown-link-hover-color:         darken($gray-900, 5%) !default;
+$dropdown-link-hover-bg:            $gray-200 !default;
+
+$dropdown-link-active-color:        $component-active-color !default;
+$dropdown-link-active-bg:           $component-active-bg !default;
+
+$dropdown-link-disabled-color:      $gray-500 !default;
+
+$dropdown-item-padding-y:           .25rem !default;
+$dropdown-item-padding-x:           1.5rem !default;
+
+$dropdown-header-color:             $gray-600 !default;
+$dropdown-header-padding:           $dropdown-padding-y $dropdown-item-padding-x !default;
+
+
+
+// end bs4 temp vars
 
 // Typography
 // -------------------------

From 126591c0f19d3acf87af5040a99484e40472ed40 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sat, 5 Oct 2024 09:18:09 +0000
Subject: [PATCH 22/82] 2.2.0

add bs5 vendor
---
 rules/compiler.php        |   9 +-
 scss/bs5/vendor/_rfs.scss | 348 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 353 insertions(+), 4 deletions(-)
 create mode 100644 scss/bs5/vendor/_rfs.scss

diff --git a/rules/compiler.php b/rules/compiler.php
index 92dd248..8f6eef3 100644
--- a/rules/compiler.php
+++ b/rules/compiler.php
@@ -366,9 +366,9 @@ public function test(\SimpleXMLElement $element, $value, $group = null,  $input
 // Custom.scss
 // Option B: Include parts of Bootstrap
 // Required
-fwrite($st_file, '@import bs"' .  $twbs_version . 'functions";' . "\n");
-fwrite($st_file, '@import bs"' .  $twbs_version . 'variables";' . "\n");
-fwrite($st_file, '@import bs"' .  $twbs_version . 'mixins";' . "\n");
+fwrite($st_file, '@import "bs' .  $twbs_version . '/functions.scss";' . "\n");
+fwrite($st_file, '@import "bs' .  $twbs_version . '/variables.scss";' . "\n");
+fwrite($st_file, '@import "bs' .  $twbs_version . '/mixins.scss";' . "\n");
 
 // Optional
 fwrite($st_file, "//\n// optional bootstrap includes and override v" . $twbs_version . "\n//\n");
@@ -443,7 +443,8 @@ public function test(\SimpleXMLElement $element, $value, $group = null,  $input
 //fwrite($st_file, '@import "node_modules/bootstrap/scss/type";' . "\n");
 //fwrite($st_file, '@import "node_modules/bootstrap/scss/images";' . "\n");
 //fwrite($st_file, '@import "node_modules/bootstrap/scss/code";' . "\n");
-fwrite($st_file, '@import bs"' .  $twbs_version . '/grid";' . "\n");
+fwrite($st_file, '@import "bs' .  $twbs_version . '/grid.scss";' . "\n");
+
 }
 
 // standaard bootstrap variables mixins etc. einde
diff --git a/scss/bs5/vendor/_rfs.scss b/scss/bs5/vendor/_rfs.scss
new file mode 100644
index 0000000..aa1f82b
--- /dev/null
+++ b/scss/bs5/vendor/_rfs.scss
@@ -0,0 +1,348 @@
+// stylelint-disable scss/dimension-no-non-numeric-values
+
+// SCSS RFS mixin
+//
+// Automated responsive values for font sizes, paddings, margins and much more
+//
+// Licensed under MIT (https://github.com/twbs/rfs/blob/main/LICENSE)
+
+// Configuration
+
+// Base value
+$rfs-base-value: 1.25rem !default;
+$rfs-unit: rem !default;
+
+@if $rfs-unit != rem and $rfs-unit != px {
+  @error "`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`.";
+}
+
+// Breakpoint at where values start decreasing if screen width is smaller
+$rfs-breakpoint: 1200px !default;
+$rfs-breakpoint-unit: px !default;
+
+@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem {
+  @error "`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`.";
+}
+
+// Resize values based on screen height and width
+$rfs-two-dimensional: false !default;
+
+// Factor of decrease
+$rfs-factor: 10 !default;
+
+@if type-of($rfs-factor) != number or $rfs-factor <= 1 {
+  @error "`#{$rfs-factor}` is not a valid  $rfs-factor, it must be greater than 1.";
+}
+
+// Mode. Possibilities: "min-media-query", "max-media-query"
+$rfs-mode: min-media-query !default;
+
+// Generate enable or disable classes. Possibilities: false, "enable" or "disable"
+$rfs-class: false !default;
+
+// 1 rem = $rfs-rem-value px
+$rfs-rem-value: 16 !default;
+
+// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14
+$rfs-safari-iframe-resize-bug-fix: false !default;
+
+// Disable RFS by setting $enable-rfs to false
+$enable-rfs: true !default;
+
+// Cache $rfs-base-value unit
+$rfs-base-value-unit: unit($rfs-base-value);
+
+@function divide($dividend, $divisor, $precision: 10) {
+  $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);
+  $dividend: abs($dividend);
+  $divisor: abs($divisor);
+  @if $dividend == 0 {
+    @return 0;
+  }
+  @if $divisor == 0 {
+    @error "Cannot divide by 0";
+  }
+  $remainder: $dividend;
+  $result: 0;
+  $factor: 10;
+  @while ($remainder > 0 and $precision >= 0) {
+    $quotient: 0;
+    @while ($remainder >= $divisor) {
+      $remainder: $remainder - $divisor;
+      $quotient: $quotient + 1;
+    }
+    $result: $result * 10 + $quotient;
+    $factor: $factor * .1;
+    $remainder: $remainder * 10;
+    $precision: $precision - 1;
+    @if ($precision < 0 and $remainder >= $divisor * 5) {
+      $result: $result + 1;
+    }
+  }
+  $result: $result * $factor * $sign;
+  $dividend-unit: unit($dividend);
+  $divisor-unit: unit($divisor);
+  $unit-map: (
+    "px": 1px,
+    "rem": 1rem,
+    "em": 1em,
+    "%": 1%
+  );
+  @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {
+    $result: $result * map-get($unit-map, $dividend-unit);
+  }
+  @return $result;
+}
+
+// Remove px-unit from $rfs-base-value for calculations
+@if $rfs-base-value-unit == px {
+  $rfs-base-value: divide($rfs-base-value, $rfs-base-value * 0 + 1);
+}
+@else if $rfs-base-value-unit == rem {
+  $rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value));
+}
+
+// Cache $rfs-breakpoint unit to prevent multiple calls
+$rfs-breakpoint-unit-cache: unit($rfs-breakpoint);
+
+// Remove unit from $rfs-breakpoint for calculations
+@if $rfs-breakpoint-unit-cache == px {
+  $rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1);
+}
+@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == "em" {
+  $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value));
+}
+
+// Calculate the media query value
+$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit});
+$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width);
+$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height);
+
+// Internal mixin used to determine which media query needs to be used
+@mixin _rfs-media-query {
+  @if $rfs-two-dimensional {
+    @if $rfs-mode == max-media-query {
+      @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {
+        @content;
+      }
+    }
+    @else {
+      @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {
+        @content;
+      }
+    }
+  }
+  @else {
+    @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) {
+      @content;
+    }
+  }
+}
+
+// Internal mixin that adds disable classes to the selector if needed.
+@mixin _rfs-rule {
+  @if $rfs-class == disable and $rfs-mode == max-media-query {
+    // Adding an extra class increases specificity, which prevents the media query to override the property
+    &,
+    .disable-rfs &,
+    &.disable-rfs {
+      @content;
+    }
+  }
+  @else if $rfs-class == enable and $rfs-mode == min-media-query {
+    .enable-rfs &,
+    &.enable-rfs {
+      @content;
+    }
+  } @else {
+    @content;
+  }
+}
+
+// Internal mixin that adds enable classes to the selector if needed.
+@mixin _rfs-media-query-rule {
+
+  @if $rfs-class == enable {
+    @if $rfs-mode == min-media-query {
+      @content;
+    }
+
+    @include _rfs-media-query () {
+      .enable-rfs &,
+      &.enable-rfs {
+        @content;
+      }
+    }
+  }
+  @else {
+    @if $rfs-class == disable and $rfs-mode == min-media-query {
+      .disable-rfs &,
+      &.disable-rfs {
+        @content;
+      }
+    }
+    @include _rfs-media-query () {
+      @content;
+    }
+  }
+}
+
+// Helper function to get the formatted non-responsive value
+@function rfs-value($values) {
+  // Convert to list
+  $values: if(type-of($values) != list, ($values,), $values);
+
+  $val: "";
+
+  // Loop over each value and calculate value
+  @each $value in $values {
+    @if $value == 0 {
+      $val: $val + " 0";
+    }
+    @else {
+      // Cache $value unit
+      $unit: if(type-of($value) == "number", unit($value), false);
+
+      @if $unit == px {
+        // Convert to rem if needed
+        $val: $val + " " + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value);
+      }
+      @else if $unit == rem {
+        // Convert to px if needed
+        $val: $val + " " + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value);
+      } @else {
+        // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value
+        $val: $val + " " + $value;
+      }
+    }
+  }
+
+  // Remove first space
+  @return unquote(str-slice($val, 2));
+}
+
+// Helper function to get the responsive value calculated by RFS
+@function rfs-fluid-value($values) {
+  // Convert to list
+  $values: if(type-of($values) != list, ($values,), $values);
+
+  $val: "";
+
+  // Loop over each value and calculate value
+  @each $value in $values {
+    @if $value == 0 {
+      $val: $val + " 0";
+    } @else {
+      // Cache $value unit
+      $unit: if(type-of($value) == "number", unit($value), false);
+
+      // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value
+      @if not $unit or $unit != px and $unit != rem {
+        $val: $val + " " + $value;
+      } @else {
+        // Remove unit from $value for calculations
+        $value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value)));
+
+        // Only add the media query if the value is greater than the minimum value
+        @if abs($value) <= $rfs-base-value or not $enable-rfs {
+          $val: $val + " " + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px);
+        }
+        @else {
+          // Calculate the minimum value
+          $value-min: $rfs-base-value + divide(abs($value) - $rfs-base-value, $rfs-factor);
+
+          // Calculate difference between $value and the minimum value
+          $value-diff: abs($value) - $value-min;
+
+          // Base value formatting
+          $min-width: if($rfs-unit == rem, #{divide($value-min, $rfs-rem-value)}rem, #{$value-min}px);
+
+          // Use negative value if needed
+          $min-width: if($value < 0, -$min-width, $min-width);
+
+          // Use `vmin` if two-dimensional is enabled
+          $variable-unit: if($rfs-two-dimensional, vmin, vw);
+
+          // Calculate the variable width between 0 and $rfs-breakpoint
+          $variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit};
+
+          // Return the calculated value
+          $val: $val + " calc(" + $min-width + if($value < 0, " - ", " + ") + $variable-width + ")";
+        }
+      }
+    }
+  }
+
+  // Remove first space
+  @return unquote(str-slice($val, 2));
+}
+
+// RFS mixin
+@mixin rfs($values, $property: font-size) {
+  @if $values != null {
+    $val: rfs-value($values);
+    $fluid-val: rfs-fluid-value($values);
+
+    // Do not print the media query if responsive & non-responsive values are the same
+    @if $val == $fluid-val {
+      #{$property}: $val;
+    }
+    @else {
+      @include _rfs-rule () {
+        #{$property}: if($rfs-mode == max-media-query, $val, $fluid-val);
+
+        // Include safari iframe resize fix if needed
+        min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null);
+      }
+
+      @include _rfs-media-query-rule () {
+        #{$property}: if($rfs-mode == max-media-query, $fluid-val, $val);
+      }
+    }
+  }
+}
+
+// Shorthand helper mixins
+@mixin font-size($value) {
+  @include rfs($value);
+}
+
+@mixin padding($value) {
+  @include rfs($value, padding);
+}
+
+@mixin padding-top($value) {
+  @include rfs($value, padding-top);
+}
+
+@mixin padding-right($value) {
+  @include rfs($value, padding-right);
+}
+
+@mixin padding-bottom($value) {
+  @include rfs($value, padding-bottom);
+}
+
+@mixin padding-left($value) {
+  @include rfs($value, padding-left);
+}
+
+@mixin margin($value) {
+  @include rfs($value, margin);
+}
+
+@mixin margin-top($value) {
+  @include rfs($value, margin-top);
+}
+
+@mixin margin-right($value) {
+  @include rfs($value, margin-right);
+}
+
+@mixin margin-bottom($value) {
+  @include rfs($value, margin-bottom);
+}
+
+@mixin margin-left($value) {
+  @include rfs($value, margin-left);
+}

From 5922fac4b19e7386a41662c57cbeaf2b96592c75 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sat, 5 Oct 2024 09:39:25 +0000
Subject: [PATCH 23/82] 2.2.0

breakpont large from map
---
 language/en-GB/en-GB.tpl_wsa_bootstrap.ini | 2 +-
 language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini | 2 +-
 scss/_template_variables.scss              | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/language/en-GB/en-GB.tpl_wsa_bootstrap.ini b/language/en-GB/en-GB.tpl_wsa_bootstrap.ini
index 347e995..5d50bee 100644
--- a/language/en-GB/en-GB.tpl_wsa_bootstrap.ini
+++ b/language/en-GB/en-GB.tpl_wsa_bootstrap.ini
@@ -9,7 +9,7 @@ COM_TEMPLATES_NAVBAR_FIELDSET_LABEL="Navbar"
 COM_TEMPLATES_DOCUMENTATION_FIELDSET_LABEL="Documentation"
 COMPRESS_CSS_LABEL="Compress Css"
 COMPRESS_CSS_DESCRIPTION="Compress Css"
-TPL_WSA_BOOTSTRAP_DESCRIPTION="Basic Template with bootstrap 5 or 4 Joomla 4 and 3"
+TPL_WSA_BOOTSTRAP_DESCRIPTION="Basic Template with bootstrap 5 or 4 Joomla 5 and 4"
 EXPLANATION0="First layer backgound (browserbackground)"
 EXPLANATION1="Second layer backgound (containerbackground)"
 EXPLANATION2="Third layer backgound (eg. logo)"
diff --git a/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini b/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini
index ab68dbe..d51ab1f 100644
--- a/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini
+++ b/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini
@@ -9,7 +9,7 @@ COM_TEMPLATES_NAVBAR_FIELDSET_LABEL="Navbar"
 COM_TEMPLATES_DOCUMENTATION_FIELDSET_LABEL="Documentatie"
 COMPRESS_CSS_LABEL="Comprimeer Css"
 COMPRESS_CSS_DESCRIPTION="Comprimeer Css"
-TPL_WSA_BOOTSTRAP_DESCRIPTION="Basis Template met bootstrap 5 of 4 Joomla 3 of 4"
+TPL_WSA_BOOTSTRAP_DESCRIPTION="Basis Template met bootstrap 5 of 4 Joomla 5 of 4"
 EXPLANATION0="Onderste laag achtergrond (browserachtergrond)."
 EXPLANATION1="Tweede laag achtergrond (container achtergrond)"
 EXPLANATION2="Derde laag achtergrond (bv. logo)"
diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 3d82ced..c22fabc 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -159,7 +159,8 @@ $container-md:                 $container-desktop;
 // Large screen / wide desktop
 $container-large-desktop:      calc(1140px + $grid-gutter-width);
 //** For `$screen-lg-min` and up.
-$container-lg:                calc(@include media-breakpoint-up(lg)); // was  $container-large-desktop;
+$container-lg:                map-get($grid-breakpoints, "xl"); // was  $container-large-desktop;
+//$container-lg:                @include media-breakpoint-up("lg"); // was  $container-large-desktop;
 
 // Large screen / wide desktop   tijdelijk bs3 type vaste breakpoints
 $screen-xl-min:              1200px;

From 0ac0bf38f03d8a1ac459e2a6e29fc98045f010ab Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sat, 5 Oct 2024 11:13:36 +0000
Subject: [PATCH 24/82] 2.2.0

screen-.. and container .. from map (1 bigger)
---
 scss/_template_variables.scss | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index c22fabc..70f89ae 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -111,7 +111,7 @@ $line-height-computed:    floor(($font-size-base * $line-height-base)); // ~20px
 
 // Extra small screen / phone
 //** Deprecated `$screen-xs` as of v3.0.1
-$screen-xs:                  480px;
+$screen-xs:                  map-get($grid-breakpoints, "sm"); // was  480px;
 //** Deprecated `$screen-xs-min` as of v3.2.0
 $screen-xs-min:              $screen-xs;
 //** Deprecated `$screen-phone` as of v3.0.1
@@ -119,21 +119,21 @@ $screen-phone:               $screen-xs-min;
 
 // Small screen / tablet
 //** Deprecated `$screen-sm` as of v3.0.1
-$screen-sm:                  768px;
+$screen-sm:                  map-get($grid-breakpoints, "md"); // was  768px;
 $screen-sm-min:              $screen-sm;
 //** Deprecated `$screen-tablet` as of v3.0.1
 $screen-tablet:              $screen-sm-min;
 
 // Medium screen / desktop
 //** Deprecated `$screen-md` as of v3.0.1
-$screen-md:                  992px;
+$screen-md:                  map-get($grid-breakpoints, "lg"); // was  992px;
 $screen-md-min:              $screen-md;
 //** Deprecated `$screen-desktop` as of v3.0.1
 $screen-desktop:             $screen-md-min;
 
 // Large screen / wide desktop
 //** Deprecated `$screen-lg` as of v3.0.1
-$screen-lg:                  1200px;
+$screen-lg:                  map-get($grid-breakpoints, "xl"); // was  1200px;
 $screen-lg-min:              $screen-lg;
 //** Deprecated `$screen-lg-desktop` as of v3.0.1
 $screen-lg-desktop:          $screen-lg-min;
@@ -149,12 +149,12 @@ $grid-gutter-width:           1.5rem !default; // from _bs5 variabels.
 
 $container-tablet:             calc(720px + $grid-gutter-width); 
 //** For `$screen-sm-min` and up.
-$container-sm:                 $container-tablet;
+$container-sm:                 map-get($grid-breakpoints, "md"); // was  $container-tablet;
 
 // Medium screen / desktop
 $container-desktop:            calc(940px + $grid-gutter-width);
 //** For `$screen-md-min` and up.
-$container-md:                 $container-desktop;
+$container-md:                 map-get($grid-breakpoints, "lg"); // was  $container-desktop;
 
 // Large screen / wide desktop
 $container-large-desktop:      calc(1140px + $grid-gutter-width);

From 8aa3f5baf639363ba2c2f4f59361debdc4f12f6a Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sat, 5 Oct 2024 11:13:47 +0000
Subject: [PATCH 25/82] 2.2.0

---
 scss/_template_variables.scss | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 70f89ae..e37255e 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -574,7 +574,15 @@ $span1 : $wsa12Col;
 
 
 .test01 {
-	width:$wsaVideoAutoItemWidth;
-	height:$screen-lg-desktop;
+	width:$screen-xs;
+	height: $screen-sm;
+	padding-top: $screen-md;
+	padding-right: $screen-lg;
+	padding-left: $screen-xl-min;
+	padding-bottom: $screen-xll-min    ;
+	
+	@debug "$screen-md-min: #{$screen-md-min}";
+
+	
 	
 }

From 2a0462c35b0ce7276b64c9bbaa310aef17e1eeb4 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sat, 5 Oct 2024 11:14:59 +0000
Subject: [PATCH 26/82] 2.2.0

---
 scss/_template_variables.scss | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index e37255e..0788ab5 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -579,7 +579,7 @@ $span1 : $wsa12Col;
 	padding-top: $screen-md;
 	padding-right: $screen-lg;
 	padding-left: $screen-xl-min;
-	padding-bottom: $screen-xll-min    ;
+	padding-bottom: $screen-xxl-min    ;
 	
 	@debug "$screen-md-min: #{$screen-md-min}";
 

From 0d7d75cff87e94b0573ab50f3f764c02bff57d29 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sat, 5 Oct 2024 11:22:52 +0000
Subject: [PATCH 27/82] 2.2.0

---
 scss/_template_variables.scss | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 0788ab5..54dc697 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -163,8 +163,8 @@ $container-lg:                map-get($grid-breakpoints, "xl"); // was  $contain
 //$container-lg:                @include media-breakpoint-up("lg"); // was  $container-large-desktop;
 
 // Large screen / wide desktop   tijdelijk bs3 type vaste breakpoints
-$screen-xl-min:              1200px;
-$screen-xxl-min:             1440px;
+$screen-xl-min:              map-get($grid-breakpoints, "xl"); // was  1200px;
+$screen-xxl-min:             map-get($grid-breakpoints, "xxl"); // was  1440px;
 $screen-xxxl-min:            1600px;
 
 //** Deprecated `$screen-lg-desktop` as of v3.0.1

From 880914bc5426a245d23253d2d510d062ab5c1b2e Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sat, 5 Oct 2024 20:44:53 +0000
Subject: [PATCH 28/82] 2.2.0

breakpoint-min( "sm"); // for $screen-xs-min
etc.
---
 scss/_template_variables.scss | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 54dc697..c772be7 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -1,5 +1,5 @@
 /* template_variables.scss */
-// 20241005 use calc(@include media-breakpoint-up(lg)) in stead of $container-lg
+// 20241005 use breakpoint-min("lg")) in stead of $container-lg
 // standard variables for this template.
 // -------------------------20190202
 // colors
@@ -113,28 +113,28 @@ $line-height-computed:    floor(($font-size-base * $line-height-base)); // ~20px
 //** Deprecated `$screen-xs` as of v3.0.1
 $screen-xs:                  map-get($grid-breakpoints, "sm"); // was  480px;
 //** Deprecated `$screen-xs-min` as of v3.2.0
-$screen-xs-min:              $screen-xs;
+$screen-xs-min:              breakpoint-min( "sm"); // was $screen-xs;
 //** Deprecated `$screen-phone` as of v3.0.1
 $screen-phone:               $screen-xs-min;
 
 // Small screen / tablet
 //** Deprecated `$screen-sm` as of v3.0.1
 $screen-sm:                  map-get($grid-breakpoints, "md"); // was  768px;
-$screen-sm-min:              $screen-sm;
+$screen-sm-min:              breakpoint-min( "md"); // was $screen-sm;
 //** Deprecated `$screen-tablet` as of v3.0.1
 $screen-tablet:              $screen-sm-min;
 
 // Medium screen / desktop
 //** Deprecated `$screen-md` as of v3.0.1
 $screen-md:                  map-get($grid-breakpoints, "lg"); // was  992px;
-$screen-md-min:              $screen-md;
+$screen-md-min:              breakpoint-min( "lg"); // was $screen-md;
 //** Deprecated `$screen-desktop` as of v3.0.1
 $screen-desktop:             $screen-md-min;
 
 // Large screen / wide desktop
 //** Deprecated `$screen-lg` as of v3.0.1
 $screen-lg:                  map-get($grid-breakpoints, "xl"); // was  1200px;
-$screen-lg-min:              $screen-lg;
+$screen-lg-min:              breakpoint-min( "xl"); // was $screen-lg;
 //** Deprecated `$screen-lg-desktop` as of v3.0.1
 $screen-lg-desktop:          $screen-lg-min;
 
@@ -149,22 +149,22 @@ $grid-gutter-width:           1.5rem !default; // from _bs5 variabels.
 
 $container-tablet:             calc(720px + $grid-gutter-width); 
 //** For `$screen-sm-min` and up.
-$container-sm:                 map-get($grid-breakpoints, "md"); // was  $container-tablet;
+$container-sm:                 breakpoint-min( "md"); // was  $container-tablet;
 
 // Medium screen / desktop
 $container-desktop:            calc(940px + $grid-gutter-width);
 //** For `$screen-md-min` and up.
-$container-md:                 map-get($grid-breakpoints, "lg"); // was  $container-desktop;
+$container-md:                 breakpoint-min( "lg"); // was $container-desktop;
 
 // Large screen / wide desktop
 $container-large-desktop:      calc(1140px + $grid-gutter-width);
 //** For `$screen-lg-min` and up.
-$container-lg:                map-get($grid-breakpoints, "xl"); // was  $container-large-desktop;
+$container-lg:                breakpoint-min( "xl"); // was $container-large-desktop;
 //$container-lg:                @include media-breakpoint-up("lg"); // was  $container-large-desktop;
 
 // Large screen / wide desktop   tijdelijk bs3 type vaste breakpoints
-$screen-xl-min:              map-get($grid-breakpoints, "xl"); // was  1200px;
-$screen-xxl-min:             map-get($grid-breakpoints, "xxl"); // was  1440px;
+$screen-xl-min:              breakpoint-min( "xl"); // was 1200px;
+$screen-xxl-min:             breakpoint-min( "xxl"); // was 1440px;
 $screen-xxxl-min:            1600px;
 
 //** Deprecated `$screen-lg-desktop` as of v3.0.1
@@ -574,11 +574,11 @@ $span1 : $wsa12Col;
 
 
 .test01 {
-	width:$screen-xs;
-	height: $screen-sm;
-	padding-top: $screen-md;
-	padding-right: $screen-lg;
-	padding-left: $screen-xl-min;
+	width:$screen-xs-min;
+	height: $screen-sm-min;
+	padding-top: $screen-md-min;
+	padding-right: $screen-lg-min;
+	padding-left: $screen-xl-min-min;
 	padding-bottom: $screen-xxl-min    ;
 	
 	@debug "$screen-md-min: #{$screen-md-min}";

From ba972166ba2cbfacd0e3f5ba5067033d968f32f0 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sat, 5 Oct 2024 20:47:07 +0000
Subject: [PATCH 29/82] 2.2.0

---
 scss/_template_variables.scss | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index c772be7..2694edc 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -578,7 +578,7 @@ $span1 : $wsa12Col;
 	height: $screen-sm-min;
 	padding-top: $screen-md-min;
 	padding-right: $screen-lg-min;
-	padding-left: $screen-xl-min-min;
+	padding-left: $screen-xl-min;
 	padding-bottom: $screen-xxl-min    ;
 	
 	@debug "$screen-md-min: #{$screen-md-min}";

From 698e86478d7994ea4f44aa92b5412c8bd83eaaca Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 06:39:01 +0000
Subject: [PATCH 30/82] 2.2.0

removed bs4 copies from tv.scss
---
 scss/_template_variables.scss | 214 ----------------------------------
 1 file changed, 214 deletions(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 2694edc..9c4cbb9 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -275,217 +275,6 @@ $dropdown-caret-color:           #000;
 
 
 // end BS3 temporary variables
-// bs4 temp vars
-// Color system
-
-$white:    #fff !default;
-$gray-100: #f8f9fa !default;
-$gray-200: #e9ecef !default;
-$gray-300: #dee2e6 !default;
-$gray-400: #ced4da !default;
-$gray-500: #adb5bd !default;
-$gray-600: #6c757d !default;
-$gray-700: #495057 !default;
-$gray-800: #343a40 !default;
-$gray-900: #212529 !default;
-$black:    #000 !default;
-
-$grays: () !default;
-$grays: map-merge(
-  (
-    "100": $gray-100,
-    "200": $gray-200,
-    "300": $gray-300,
-    "400": $gray-400,
-    "500": $gray-500,
-    "600": $gray-600,
-    "700": $gray-700,
-    "800": $gray-800,
-    "900": $gray-900
-  ),
-  $grays
-);
-
-$blue:    #007bff !default;
-$indigo:  #6610f2 !default;
-$purple:  #6f42c1 !default;
-$pink:    #e83e8c !default;
-$red:     #dc3545 !default;
-$orange:  #fd7e14 !default;
-$yellow:  #ffc107 !default;
-$green:   #28a745 !default;
-$teal:    #20c997 !default;
-$cyan:    #17a2b8 !default;
-
-$colors: () !default;
-$colors: map-merge(
-  (
-    "blue":       $blue,
-    "indigo":     $indigo,
-    "purple":     $purple,
-    "pink":       $pink,
-    "red":        $red,
-    "orange":     $orange,
-    "yellow":     $yellow,
-    "green":      $green,
-    "teal":       $teal,
-    "cyan":       $cyan,
-    "white":      $white,
-    "gray":       $gray-600,
-    "gray-dark":  $gray-800
-  ),
-  $colors
-);
-
-$primary:       $blue !default;
-$secondary:     $gray-600 !default;
-$success:       $green !default;
-$info:          $cyan !default;
-$warning:       $yellow !default;
-$danger:        $red !default;
-$light:         $gray-100 !default;
-$dark:          $gray-800 !default;
-
-$theme-colors: () !default;
-$theme-colors: map-merge(
-  (
-    "primary":    $primary,
-    "secondary":  $secondary,
-    "success":    $success,
-    "info":       $info,
-    "warning":    $warning,
-    "danger":     $danger,
-    "light":      $light,
-    "dark":       $dark
-  ),
-  $theme-colors
-);
-// Components
-//
-// Define common padding and border radius sizes and more.
-
-$line-height-lg:              1.5 !default;
-$line-height-sm:              1.5 !default;
-
-$border-width:                1px !default;
-$border-color:                $gray-300 !default;
-
-$border-radius:               .25rem !default;
-$border-radius-lg:            .3rem !default;
-$border-radius-sm:            .2rem !default;
-
-$rounded-pill:                50rem !default;
-
-$box-shadow-sm:               0 .125rem .25rem rgba($black, .075) !default;
-$box-shadow:                  0 .5rem 1rem rgba($black, .15) !default;
-$box-shadow-lg:               0 1rem 3rem rgba($black, .175) !default;
-
-$component-active-color:      $white !default;
-$component-active-bg:         theme-color("primary") !default;
-
-$caret-width:                 .3em !default;
-$caret-vertical-align:        $caret-width * .85 !default;
-$caret-spacing:               $caret-width * .85 !default;
-
-$transition-base:             all .2s ease-in-out !default;
-$transition-fade:             opacity .15s linear !default;
-$transition-collapse:         height .35s ease !default;
-$transition-collapse-width:   width .35s ease !default;
-
-$embed-responsive-aspect-ratios: () !default;
-$embed-responsive-aspect-ratios: join(
-  (
-    (21 9),
-    (16 9),
-    (4 3),
-    (1 1),
-  ),
-  $embed-responsive-aspect-ratios
-);
-
-$spacer: 1rem !default;
-$spacers: () !default;
-$spacers: map-merge(
-  (
-    0: 0,
-    1: ($spacer * .25),
-    2: ($spacer * .5),
-    3: $spacer,
-    4: ($spacer * 1.5),
-    5: ($spacer * 3)
-  ),
-  $spacers
-);
-
-
-// Body
-//
-// Settings for the `` element.
-
-$body-bg:                   $white !default;
-$body-color:                $gray-900 !default;
-
-$nav-divider-color:                 $gray-200 !default;
-$nav-divider-margin-y:              $spacer * .5 !default;
-
-
-
-$navbar-dark-color:                 rgba($white, .5) !default;
-$navbar-dark-hover-color:           rgba($white, .75) !default;
-$navbar-dark-active-color:          $white !default;
-$navbar-dark-disabled-color:        rgba($white, .25) !default;
-$navbar-dark-toggler-icon-bg:       url("data:image/svg+xml,") !default;
-$navbar-dark-toggler-border-color:  rgba($white, .1) !default;
-
-$navbar-light-color:                rgba($black, .5) !default;
-$navbar-light-hover-color:          rgba($black, .7) !default;
-$navbar-light-active-color:         rgba($black, .9) !default;
-$navbar-light-disabled-color:       rgba($black, .3) !default;
-$navbar-light-toggler-icon-bg:      url("data:image/svg+xml,") !default;
-$navbar-light-toggler-border-color: rgba($black, .1) !default;
-
-$navbar-light-brand-color:                $navbar-light-active-color !default;
-$navbar-light-brand-hover-color:          $navbar-light-active-color !default;
-$navbar-dark-brand-color:                 $navbar-dark-active-color !default;
-$navbar-dark-brand-hover-color:           $navbar-dark-active-color !default;
-
-// Dropdowns
-//
-// Dropdown menu container and contents.
-
-$dropdown-min-width:                10rem !default;
-$dropdown-padding-x:                0 !default;
-$dropdown-padding-y:                .5rem !default;
-$dropdown-spacer:                   .125rem !default;
-$dropdown-font-size:                $font-size-base !default;
-$dropdown-color:                    $body-color !default;
-$dropdown-bg:                       $white !default;
-$dropdown-border-color:             rgba($black, .15) !default;
-$dropdown-border-radius:            $border-radius !default;
-$dropdown-border-width:             $border-width !default;
-$dropdown-inner-border-radius:      subtract($dropdown-border-radius, $dropdown-border-width) !default;
-$dropdown-divider-bg:               $gray-200 !default;
-$dropdown-divider-margin-y:         $nav-divider-margin-y !default;
-$dropdown-box-shadow:               0 .5rem 1rem rgba($black, .175) !default;
-
-$dropdown-link-color:               $gray-900 !default;
-$dropdown-link-hover-color:         darken($gray-900, 5%) !default;
-$dropdown-link-hover-bg:            $gray-200 !default;
-
-$dropdown-link-active-color:        $component-active-color !default;
-$dropdown-link-active-bg:           $component-active-bg !default;
-
-$dropdown-link-disabled-color:      $gray-500 !default;
-
-$dropdown-item-padding-y:           .25rem !default;
-$dropdown-item-padding-x:           1.5rem !default;
-
-$dropdown-header-color:             $gray-600 !default;
-$dropdown-header-padding:           $dropdown-padding-y $dropdown-item-padding-x !default;
-
-
-
-// end bs4 temp vars
 
 // Typography
 // -------------------------
@@ -528,9 +317,6 @@ $bg1Z-index:		  auto;
 $bg2Z-index:		  auto;
 /* uit asha-s */
 
-
-
-
 // $asBlogLeadingWidth:      75%;
 // $asBlogItemWidth:         23.5%;
 $tagListItemWidth:        75%;

From cd5aa2f4aaa72c418891be32222aef032f5771ee Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 09:51:46 +0000
Subject: [PATCH 31/82] 2.2.0

template dropdown temporary cleaned
---
 .settings/org.eclipse.core.resources.prefs |   2 +
 scss/_template_dropdown.scss               | 175 +---------
 scss/_template_variables.scss              | 354 ++++++++++-----------
 3 files changed, 190 insertions(+), 341 deletions(-)
 create mode 100644 .settings/org.eclipse.core.resources.prefs

diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..c773cd6
--- /dev/null
+++ b/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding//scss/_template_dropdown.scss=UTF-8
diff --git a/scss/_template_dropdown.scss b/scss/_template_dropdown.scss
index 4d45001..f5821ba 100644
--- a/scss/_template_dropdown.scss
+++ b/scss/_template_dropdown.scss
@@ -9,6 +9,7 @@
 11-2-2019 brandwith relatief tov lg
 28-12-2021 .dropdown-menu > li > a replaced by .dropdown-menu > .nav-item > .nav-link to give it higher priority in BS4 and BS5
  and padding and line-height px value changed to rem value
+06-10-2024 2.2.0 remove bs3, use more bs4, bs5 variables, make bs5 the default 
 
 -----------------------------------------*/
 #img_brandImage
@@ -20,161 +21,8 @@ width: $brandWidth * 300 / 960; // < es = 375
 // --------------------------------------------------
 
 
-@if $twbs_version == 3
-{
-// Default navbar 
-.navbar-default {
-  background-color: $navbar-default-bg;
-  border-color: $navbar-default-border;
-
-  .navbar-brand {
-    color: $navbar-default-brand-color;
-    &:hover,
-    &:focus {
-      color: $navbar-default-brand-hover-color;
-      background-color: $navbar-default-brand-hover-bg;
-    }
-  }
-
-  .navbar-text {
-    color: $navbar-default-color;
-  }
-
-  .navbar-nav {
-    > li > a {
-      color: $navbar-default-link-color;
-
-      &:hover,
-      &:focus {
-        color: $navbar-default-link-hover-color;
-        background-color: $navbar-default-link-hover-bg;
-      }
-    }
-    > .active > a {
-      &,
-      &:hover,
-      &:focus {
-        color: $navbar-default-link-active-color;
-        background-color: $navbar-default-link-active-bg;
-      }
-    }
-    > .disabled > a {
-      &,
-      &:hover,
-      &:focus {
-        color: $navbar-default-link-disabled-color;
-        background-color: $navbar-default-link-disabled-bg;
-      }
-    }
-  }
-
-  .navbar-toggle {
-    border-color: $navbar-default-toggle-border-color;
-    .icon-bar {
-      background-color: $navbar-default-link-color;
-    }
-    &:hover,
-    &:focus {
-      background-color: $navbar-default-toggle-hover-bg;
-    }
-    .icon-bar {
-      background-color: $navbar-default-toggle-icon-bar-bg;
-    }
-  }
-
-  .navbar-collapse,
-  .navbar-form {
-    border-color: $navbar-default-border;
-  }
-
-  // Dropdown menu items
-  .navbar-nav {
-    // Remove background color from open dropdown
-    > .open > a {
-      &,
-      &:hover,
-      &:focus {
-        background-color: $navbar-default-link-active-bg;
-        color: $navbar-default-link-active-color;
-      }
-    }
-
-    @media (max-width: $grid-float-breakpoint-max) {
-      // Dropdowns get custom display when collapsed
-      .open .dropdown-menu {
-        > li > a {
-          color: $navbar-default-link-color;
-          &:hover,
-          &:focus {
-            color: $navbar-default-link-hover-color;
-            background-color: $navbar-default-link-hover-bg;
-          }
-        }
-        > .active > a {
-          &,
-          &:hover,
-          &:focus {
-            color: $navbar-default-link-active-color;
-            background-color: $navbar-default-link-active-bg;
-          }
-        }
-        > .disabled > a {
-          &,
-          &:hover,
-          &:focus {
-            color: $navbar-default-link-disabled-color;
-            background-color: $navbar-default-link-disabled-bg;
-          }
-        }
-      }
-    }
-  }
-
-
-  // Links in navbars
-  //
-  // Add a class to ensure links outside the navbar nav are colored correctly.
-
-  .navbar-link {
-    color: $navbar-default-link-color;
-    &:hover {
-      color: $navbar-default-link-hover-color;
-    }
-  }
-
-  .btn-link {
-    color: $navbar-default-link-color;
-    &:hover,
-    &:focus {
-      color: $navbar-default-link-hover-color;
-    }
-    &[disabled],
-    fieldset[disabled] & {
-      &:hover,
-      &:focus {
-        color: $navbar-default-link-disabled-color;
-      }
-    }
-  }
-
-  @include gradient-vertical($start-color: lighten($navbar-default-bg, 10%), $end-color: $navbar-default-bg);
-  @include reset-filter(); /* Remove gradient in IE<10 to fix bug where dropdowns don't get triggered  */
-  border-radius: $navbar-border-radius;
-  $shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);
-  @include box-shadow($shadow);  
-
-  .navbar-nav > .open > a,
-  .navbar-nav > .active > a {
-  @include gradient-vertical($start-color: darken($navbar-default-link-active-bg, 5%), $end-color: darken($navbar-default-link-active-bg, 2%));
-    @include box-shadow(inset 0 3px 9px rgba(0,0,0,.075)); 
-  }
-
-}
-// einde .twbs 3 navbar-default 
-
-}
-@else if 1 == 1 /* $navbar-theme == navbar-dark */
-{/* bs4 navbar-dark */
+@if $twbs_version == 4
+{// bs4 
 .navbar-dark {
   .navbar-brand {
     color: $navbar-default-brand-color;
@@ -227,14 +75,14 @@ width: $brandWidth * 300 / 960; // < es = 375
       }
     }
   }
-}
-
 // einde bs4 navbar-dark
 }
-@else 
-{// bs4 navbar-light
-// einde bs4 navbar-light
+// einde bs4
 } 
+@else // bs5
+{
+}
+
 
 .navbar-brand,
 .navbar-nav > li > a {
@@ -248,8 +96,7 @@ width: $brandWidth * 300 / 960; // < es = 375
 	===================== */
 .dropdown-menu {
   background-color: $dropdown-bg;
-  border: 1px solid $dropdown-fallback-border; // IE8 fallback
-  border: 1px solid $dropdown-border;
+  border: 1px solid $dropdown-border-color;
 
   > .nav-item > .nav-link {
     clear: both;
@@ -334,7 +181,7 @@ width: $brandWidth * 300 / 960; // < es = 375
    }
 
    &:hover>a:after {
-    border-left-color:$navbar-default-link-active-color;
+    border-left-color: $navbar-light-active-color;
    }
 
    &.pull-left { 
@@ -423,7 +270,7 @@ color: #333;
       margin-right: 2px;
       line-height: $line-height-base;
       border: 1px solid transparent;
-      border-radius: $border-radius-base $border-radius-base 0 0;
+      border-radius: $nav-tabs-border-radius $nav-tabs-border-radius 0 0; // was $border-radius-base $border-radius-base 0 0;
       &:hover {
         border-color: $nav-tabs-link-hover-border-color $nav-tabs-link-hover-border-color $nav-tabs-border-color;
       }
diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 9c4cbb9..113f9e9 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -20,123 +20,123 @@ $activenavbarbg: 	#999;
 $activenavbarfg: 	#fff;
 $specialgreygradientstart: #ffffff;
 $specialgreygradientend: #e6e6e6;
-
+// BS3 temporary variables
 //## temporary Define the maximum width of `.container` for different screen sizes with BS 3 variables
 //## Gray and brand colors for use across Bootstrap.
 
-$gray-base:              #000;
-$gray-darker:            lighten($gray-base, 13.5%); // #222
-$gray-dark:              lighten($gray-base, 20%);   // #333
-$gray:                   lighten($gray-base, 33.5%); // #555
-$gray-light:             lighten($gray-base, 46.7%); // #777
-$gray-lighter:           lighten($gray-base, 93.5%); // #eee
-
-$brand-primary:         darken(#428bca, 6.5%); // #337ab7
-$brand-success:         #5cb85c;
-$brand-info:            #5bc0de;
-$brand-warning:         #f0ad4e;
-$brand-danger:          #d9534f;
+//$gray-base:              #000;
+//$gray-darker:            lighten($gray-base, 13.5%); // #222
+//$gray-dark:              lighten($gray-base, 20%);   // #333
+//$gray:                   lighten($gray-base, 33.5%); // #555
+//$gray-light:             lighten($gray-base, 46.7%); // #777
+//$gray-lighter:           lighten($gray-base, 93.5%); // #eee
+//
+//$brand-primary:         darken(#428bca, 6.5%); // #337ab7
+//$brand-success:         #5cb85c;
+//$brand-info:            #5bc0de;
+//$brand-warning:         #f0ad4e;
+//$brand-danger:          #d9534f;
 
 
 //## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
 
-$padding-base-vertical:     6px;
-$padding-base-horizontal:   12px;
-
-$padding-large-vertical:    10px;
-$padding-large-horizontal:  16px;
-
-$padding-small-vertical:    5px;
-$padding-small-horizontal:  10px;
-
-$padding-xs-vertical:       1px;
-$padding-xs-horizontal:     5px;
-
-$line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome
-$line-height-small:         1.5;
-
-$border-radius-base:        4px;
-$border-radius-large:       6px;
-$border-radius-small:       3px;
-
-//** Global color for active items (e.g., navs or dropdowns).
-$component-active-color:    #fff;
-//** Global background color for active items (e.g., navs or dropdowns).
-$component-active-bg:       $brand-primary;
-
-//** Width of the `border` for generating carets that indicator dropdowns.
-$caret-width-base:          4px;
-//** Carets increase slightly in size for larger components.
-$caret-width-large:         5px;
-
-//** Background color for ``.
-$body-bg:               #fff;
-//** Global text color on ``.
-$text-color:            $gray-dark;
-
-//** Global textual link color.
-$link-color:            $brand-primary;
-//** Link hover color set via `darken()` function.
-$link-hover-color:      darken($link-color, 15%);
-//** Link hover decoration.
-$link-hover-decoration: underline;
-
-
-
-//## Font, line-height, and color for body text, headings, and more.
-
-$font-family-sans-serif:  "Helvetica Neue", Helvetica, Arial, sans-serif;
-$font-family-serif:       Georgia, "Times New Roman", Times, serif;
-//** Default monospace fonts for ``, ``, and `
`.
-$font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
-$font-family-base:        $font-family-sans-serif;
-
-$font-size-base:          14px;
-$font-size-large:         ceil(($font-size-base * 1.25)); // ~18px
-$font-size-small:         ceil(($font-size-base * 0.85)); // ~12px
-
-$font-size-h1:            floor(($font-size-base * 2.6)); // ~36px
-$font-size-h2:            floor(($font-size-base * 2.15)); // ~30px
-$font-size-h3:            ceil(($font-size-base * 1.7)); // ~24px
-$font-size-h4:            ceil(($font-size-base * 1.25)); // ~18px
-$font-size-h5:            $font-size-base;
-$font-size-h6:            ceil(($font-size-base * 0.85)); // ~12px
-
-
-//** Unit-less `line-height` for use in components like buttons.
-$line-height-base:        1.428571429; // 20/14
-//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
-$line-height-computed:    floor(($font-size-base * $line-height-base)); // ~20px
+//$padding-base-vertical:     6px;
+//$padding-base-horizontal:   12px;
+//
+//$padding-large-vertical:    10px;
+//$padding-large-horizontal:  16px;
+//
+//$padding-small-vertical:    5px;
+//$padding-small-horizontal:  10px;
+//
+//$padding-xs-vertical:       1px;
+//$padding-xs-horizontal:     5px;
+//
+//$line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome
+//$line-height-small:         1.5;
+//
+//$border-radius-base:        4px;
+//$border-radius-large:       6px;
+//$border-radius-small:       3px;
+
+////** Global color for active items (e.g., navs or dropdowns).
+//$component-active-color:    #fff;
+////** Global background color for active items (e.g., navs or dropdowns).
+//$component-active-bg:       $brand-primary;
+//
+////** Width of the `border` for generating carets that indicator dropdowns.
+//$caret-width-base:          4px;
+////** Carets increase slightly in size for larger components.
+//$caret-width-large:         5px;
+//
+////** Background color for ``.
+//$body-bg:               #fff;
+////** Global text color on ``.
+//$text-color:            $gray-dark;
+//
+////** Global textual link color.
+//$link-color:            $brand-primary;
+////** Link hover color set via `darken()` function.
+//$link-hover-color:      darken($link-color, 15%);
+////** Link hover decoration.
+//$link-hover-decoration: underline;
+//
+//
+//
+////## Font, line-height, and color for body text, headings, and more.
+//
+//$font-family-sans-serif:  "Helvetica Neue", Helvetica, Arial, sans-serif;
+//$font-family-serif:       Georgia, "Times New Roman", Times, serif;
+////** Default monospace fonts for ``, ``, and `
`.
+//$font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
+//$font-family-base:        $font-family-sans-serif;
+//
+//$font-size-base:          14px;
+//$font-size-large:         ceil(($font-size-base * 1.25)); // ~18px
+//$font-size-small:         ceil(($font-size-base * 0.85)); // ~12px
+//
+//$font-size-h1:            floor(($font-size-base * 2.6)); // ~36px
+//$font-size-h2:            floor(($font-size-base * 2.15)); // ~30px
+//$font-size-h3:            ceil(($font-size-base * 1.7)); // ~24px
+//$font-size-h4:            ceil(($font-size-base * 1.25)); // ~18px
+//$font-size-h5:            $font-size-base;
+//$font-size-h6:            ceil(($font-size-base * 0.85)); // ~12px
+//
+//
+////** Unit-less `line-height` for use in components like buttons.
+//$line-height-base:        1.428571429; // 20/14
+////** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
+//$line-height-computed:    floor(($font-size-base * $line-height-base)); // ~20px
 
 
 // Extra small screen / phone
 //** Deprecated `$screen-xs` as of v3.0.1
-$screen-xs:                  map-get($grid-breakpoints, "sm"); // was  480px;
+//$screen-xs:                  map-get($grid-breakpoints, "sm"); // was  480px;
 //** Deprecated `$screen-xs-min` as of v3.2.0
 $screen-xs-min:              breakpoint-min( "sm"); // was $screen-xs;
 //** Deprecated `$screen-phone` as of v3.0.1
-$screen-phone:               $screen-xs-min;
+//$screen-phone:               $screen-xs-min;
 
 // Small screen / tablet
 //** Deprecated `$screen-sm` as of v3.0.1
-$screen-sm:                  map-get($grid-breakpoints, "md"); // was  768px;
+//$screen-sm:                  map-get($grid-breakpoints, "md"); // was  768px;
 $screen-sm-min:              breakpoint-min( "md"); // was $screen-sm;
 //** Deprecated `$screen-tablet` as of v3.0.1
 $screen-tablet:              $screen-sm-min;
 
 // Medium screen / desktop
 //** Deprecated `$screen-md` as of v3.0.1
-$screen-md:                  map-get($grid-breakpoints, "lg"); // was  992px;
+//$screen-md:                  map-get($grid-breakpoints, "lg"); // was  992px;
 $screen-md-min:              breakpoint-min( "lg"); // was $screen-md;
 //** Deprecated `$screen-desktop` as of v3.0.1
-$screen-desktop:             $screen-md-min;
+//$screen-desktop:             $screen-md-min;
 
 // Large screen / wide desktop
 //** Deprecated `$screen-lg` as of v3.0.1
-$screen-lg:                  map-get($grid-breakpoints, "xl"); // was  1200px;
+//$screen-lg:                  map-get($grid-breakpoints, "xl"); // was  1200px;
 $screen-lg-min:              breakpoint-min( "xl"); // was $screen-lg;
 //** Deprecated `$screen-lg-desktop` as of v3.0.1
-$screen-lg-desktop:          $screen-lg-min;
+//$screen-lg-desktop:          $screen-lg-min;
 
 // So media queries don't overlap when required, provide a maximum
 $screen-xs-max:              ($screen-sm-min - 1);
@@ -175,104 +175,104 @@ $screen-lg-max:              ($screen-xl-min - 1);
 $screen-xl-max:              ($screen-xxl-min - 1);
 $screen-xxl-max:             ($screen-xxxl-min - 1);
 
-//== Navbar
+////== Navbar
+////
+////##
+//
+//// Basics of a navbar
+//$navbar-height:                    50px;
+//$navbar-margin-bottom:             $line-height-computed;
+//$navbar-border-radius:             $border-radius-base;
+//$navbar-padding-horizontal:        floor(($grid-gutter-width / 2));
+//$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2);
+//$navbar-collapse-max-height:       340px;
+//
+//$navbar-default-color:             #777;
+//$navbar-default-bg:                #f8f8f8;
+//$navbar-default-border:            darken($navbar-default-bg, 6.5%);
+//
+//// Navbar links
+//$navbar-default-link-color:                #777;
+//$navbar-default-link-hover-color:          #333;
+//$navbar-default-link-hover-bg:             transparent;
+//$navbar-default-link-active-color:         #555;
+//$navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%);
+//$navbar-default-link-disabled-color:       #ccc;
+//$navbar-default-link-disabled-bg:          transparent;
+//
+//// Navbar brand label
+//$navbar-default-brand-color:               $navbar-default-link-color;
+//$navbar-default-brand-hover-color:         darken($navbar-default-brand-color, 10%);
+//$navbar-default-brand-hover-bg:            transparent;
+//
+//// Navbar toggle
+$navbar-default-toggle-hover-bg:           $component-active-bg; // #ddd;
+$navbar-default-toggle-icon-bar-bg:        $navbar-light-toggler-icon-bg; // #888;
+$navbar-default-toggle-border-color:       $navbar-light-toggler-border-color; // was #ddd;
+//
+////=== Shared nav styles
+//$nav-link-padding:                          10px 15px;
+$nav-link-hover-bg:                         $gray-200; // $gray-lighter;
+//
+$nav-disabled-link-color:                   $gray-500; // $gray-light;
+$nav-disabled-link-hover-color:             $gray-500;  // $gray-light;
+//
+////== Tabs
+//$nav-tabs-border-color:                     #ddd;
+//
+//$nav-tabs-link-hover-border-color:          $gray-lighter;
 //
-//##
-
-// Basics of a navbar
-$navbar-height:                    50px;
-$navbar-margin-bottom:             $line-height-computed;
-$navbar-border-radius:             $border-radius-base;
-$navbar-padding-horizontal:        floor(($grid-gutter-width / 2));
-$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2);
-$navbar-collapse-max-height:       340px;
-
-$navbar-default-color:             #777;
-$navbar-default-bg:                #f8f8f8;
-$navbar-default-border:            darken($navbar-default-bg, 6.5%);
-
-// Navbar links
-$navbar-default-link-color:                #777;
-$navbar-default-link-hover-color:          #333;
-$navbar-default-link-hover-bg:             transparent;
-$navbar-default-link-active-color:         #555;
-$navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%);
-$navbar-default-link-disabled-color:       #ccc;
-$navbar-default-link-disabled-bg:          transparent;
-
-// Navbar brand label
-$navbar-default-brand-color:               $navbar-default-link-color;
-$navbar-default-brand-hover-color:         darken($navbar-default-brand-color, 10%);
-$navbar-default-brand-hover-bg:            transparent;
-
-// Navbar toggle
-$navbar-default-toggle-hover-bg:           #ddd;
-$navbar-default-toggle-icon-bar-bg:        #888;
-$navbar-default-toggle-border-color:       #ddd;
-
-//=== Shared nav styles
-$nav-link-padding:                          10px 15px;
-$nav-link-hover-bg:                         $gray-lighter;
-
-$nav-disabled-link-color:                   $gray-light;
-$nav-disabled-link-hover-color:             $gray-light;
-
-//== Tabs
-$nav-tabs-border-color:                     #ddd;
-
-$nav-tabs-link-hover-border-color:          $gray-lighter;
-
 $nav-tabs-active-link-hover-bg:             $body-bg;
 $nav-tabs-active-link-hover-color:          $gray;
 $nav-tabs-active-link-hover-border-color:   #ddd;
-
-$nav-tabs-justified-link-border-color:            #ddd;
-$nav-tabs-justified-active-link-border-color:     $body-bg;
-
-//== Pills
-$nav-pills-border-radius:                   $border-radius-base;
+//
+//$nav-tabs-justified-link-border-color:            #ddd;
+//$nav-tabs-justified-active-link-border-color:     $body-bg;
+//
+////== Pills
+//$nav-pills-border-radius:                   $border-radius-base;
 $nav-pills-active-link-hover-bg:            $component-active-bg;
 $nav-pills-active-link-hover-color:         $component-active-color;
-
-//** Disabled cursor for form controls and buttons.
+//
+//// ** Disabled cursor for form controls and buttons.
 $cursor-disabled:                not-allowed;
-
-
-//== Dropdowns
 //
-//## Dropdown menu container and contents.
-
-//** Background for the dropdown menu.
-$dropdown-bg:                    #fff;
-//** Dropdown menu `border-color`.
-$dropdown-border:                rgba(0,0,0,.15);
-//** Dropdown menu `border-color` **for IE8**.
-$dropdown-fallback-border:       #ccc;
-//** Divider color for between dropdown items.
-$dropdown-divider-bg:            #e5e5e5;
-
-//** Dropdown link text color.
-$dropdown-link-color:            $gray-dark;
-//** Hover color for dropdown links.
-$dropdown-link-hover-color:      darken($gray-dark, 5%);
-//** Hover background for dropdown links.
-$dropdown-link-hover-bg:         #f5f5f5;
-
-//** Active dropdown menu item text color.
-$dropdown-link-active-color:     $component-active-color;
-//** Active dropdown menu item background color.
-$dropdown-link-active-bg:        $component-active-bg;
-
-//** Disabled dropdown menu item background color.
-$dropdown-link-disabled-color:   $gray-light;
-
-//** Text color for headers within dropdown menus.
-$dropdown-header-color:          $gray-light;
-
-//** Deprecated `$dropdown-caret-color` as of v3.1.0
-$dropdown-caret-color:           #000;
-
-
+//
+////== Dropdowns
+////
+////## Dropdown menu container and contents.
+//
+////** Background for the dropdown menu.
+//$dropdown-bg:                    #fff;
+////** Dropdown menu `border-color`.
+//$dropdown-border:                rgba(0,0,0,.15);
+////** Dropdown menu `border-color` **for IE8**.
+//$dropdown-fallback-border:       #ccc;
+////** Divider color for between dropdown items.
+//$dropdown-divider-bg:            #e5e5e5;
+//
+////** Dropdown link text color.
+//$dropdown-link-color:            $gray-dark;
+////** Hover color for dropdown links.
+//$dropdown-link-hover-color:      darken($gray-dark, 5%);
+////** Hover background for dropdown links.
+//$dropdown-link-hover-bg:         #f5f5f5;
+//
+////** Active dropdown menu item text color.
+//$dropdown-link-active-color:     $component-active-color;
+////** Active dropdown menu item background color.
+//$dropdown-link-active-bg:        $component-active-bg;
+//
+////** Disabled dropdown menu item background color.
+//$dropdown-link-disabled-color:   $gray-light;
+//
+////** Text color for headers within dropdown menus.
+//$dropdown-header-color:          $gray-light;
+//
+////** Deprecated `$dropdown-caret-color` as of v3.1.0
+//$dropdown-caret-color:           #000;
+//
+//
 
 // end BS3 temporary variables
 

From d9aa562b139ae3f1c6fd5a1e8c5820b8629e5957 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 11:30:14 +0000
Subject: [PATCH 32/82] 2.2.0

added vendor scss bs4
---
 scss/bs4/vendor/_rfs.scss | 228 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 228 insertions(+)
 create mode 100644 scss/bs4/vendor/_rfs.scss

diff --git a/scss/bs4/vendor/_rfs.scss b/scss/bs4/vendor/_rfs.scss
new file mode 100644
index 0000000..e453f44
--- /dev/null
+++ b/scss/bs4/vendor/_rfs.scss
@@ -0,0 +1,228 @@
+// stylelint-disable property-blacklist, scss/dollar-variable-default
+
+// SCSS RFS mixin
+//
+// Automated responsive font sizes
+//
+// Licensed under MIT (https://github.com/twbs/rfs/blob/v8.x/LICENSE)
+
+// Configuration
+
+// Base font size
+$rfs-base-font-size: 1.25rem !default;
+$rfs-font-size-unit: rem !default;
+
+@if $rfs-font-size-unit != rem and $rfs-font-size-unit != px {
+  @error "`#{$rfs-font-size-unit}` is not a valid unit for $rfs-font-size-unit. Use `px` or `rem`.";
+}
+
+// Breakpoint at where font-size starts decreasing if screen width is smaller
+$rfs-breakpoint: 1200px !default;
+$rfs-breakpoint-unit: px !default;
+
+@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem {
+  @error "`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`.";
+}
+
+// Resize font size based on screen height and width
+$rfs-two-dimensional: false !default;
+
+// Factor of decrease
+$rfs-factor: 10 !default;
+
+@if type-of($rfs-factor) != "number" or $rfs-factor <= 1 {
+  @error "`#{$rfs-factor}` is not a valid  $rfs-factor, it must be greater than 1.";
+}
+
+// Generate enable or disable classes. Possibilities: false, "enable" or "disable"
+$rfs-class: false !default;
+
+// 1 rem = $rfs-rem-value px
+$rfs-rem-value: 16 !default;
+
+// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14
+$rfs-safari-iframe-resize-bug-fix: false !default;
+
+// Disable RFS by setting $enable-responsive-font-sizes to false
+$enable-responsive-font-sizes: true !default;
+
+// Cache $rfs-base-font-size unit
+$rfs-base-font-size-unit: unit($rfs-base-font-size);
+
+@function divide($dividend, $divisor, $precision: 10) {
+  $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);
+  $dividend: abs($dividend);
+  $divisor: abs($divisor);
+  @if $dividend == 0 {
+    @return 0;
+  }
+  @if $divisor == 0 {
+    @error "Cannot divide by 0";
+  }
+  $remainder: $dividend;
+  $result: 0;
+  $factor: 10;
+  @while ($remainder > 0 and $precision >= 0) {
+    $quotient: 0;
+    @while ($remainder >= $divisor) {
+      $remainder: $remainder - $divisor;
+      $quotient: $quotient + 1;
+    }
+    $result: $result * 10 + $quotient;
+    $factor: $factor * .1;
+    $remainder: $remainder * 10;
+    $precision: $precision - 1;
+    @if ($precision < 0 and $remainder >= $divisor * 5) {
+      $result: $result + 1;
+    }
+  }
+  $result: $result * $factor * $sign;
+  $dividend-unit: unit($dividend);
+  $divisor-unit: unit($divisor);
+  $unit-map: (
+    "px": 1px,
+    "rem": 1rem,
+    "em": 1em,
+    "%": 1%
+  );
+  @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {
+    $result: $result * map-get($unit-map, $dividend-unit);
+  }
+  @return $result;
+}
+
+// Remove px-unit from $rfs-base-font-size for calculations
+@if $rfs-base-font-size-unit == "px" {
+  $rfs-base-font-size: divide($rfs-base-font-size, $rfs-base-font-size * 0 + 1);
+}
+@else if $rfs-base-font-size-unit == "rem" {
+  $rfs-base-font-size: divide($rfs-base-font-size, divide($rfs-base-font-size * 0 + 1, $rfs-rem-value));
+}
+
+// Cache $rfs-breakpoint unit to prevent multiple calls
+$rfs-breakpoint-unit-cache: unit($rfs-breakpoint);
+
+// Remove unit from $rfs-breakpoint for calculations
+@if $rfs-breakpoint-unit-cache == "px" {
+  $rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1);
+}
+@else if $rfs-breakpoint-unit-cache == "rem" or $rfs-breakpoint-unit-cache == "em" {
+  $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value));
+}
+
+// Internal mixin that adds disable classes to the selector if needed.
+@mixin _rfs-disable-class {
+  @if $rfs-class == "disable" {
+    // Adding an extra class increases specificity, which prevents the media query to override the font size
+    &,
+    .disable-responsive-font-size &,
+    &.disable-responsive-font-size {
+      @content;
+    }
+  }
+  @else {
+    @content;
+  }
+}
+
+// Internal mixin that adds enable classes to the selector if needed.
+@mixin _rfs-enable-class {
+  @if $rfs-class == "enable" {
+    .enable-responsive-font-size &,
+    &.enable-responsive-font-size {
+      @content;
+    }
+  }
+  @else {
+    @content;
+  }
+}
+
+// Internal mixin used to determine which media query needs to be used
+@mixin _rfs-media-query($mq-value) {
+  @if $rfs-two-dimensional {
+    @media (max-width: #{$mq-value}), (max-height: #{$mq-value}) {
+      @content;
+    }
+  }
+  @else {
+    @media (max-width: #{$mq-value}) {
+      @content;
+    }
+  }
+}
+
+// Responsive font size mixin
+@mixin rfs($fs, $important: false) {
+  // Cache $fs unit
+  $fs-unit: if(type-of($fs) == "number", unit($fs), false);
+
+  // Add !important suffix if needed
+  $rfs-suffix: if($important, " !important", "");
+
+  // If $fs isn't a number (like inherit) or $fs has a unit (not px or rem, like 1.5em) or $ is 0, just print the value
+  @if not $fs-unit or $fs-unit != "" and $fs-unit != "px" and $fs-unit != "rem" or $fs == 0 {
+    font-size: #{$fs}#{$rfs-suffix};
+  }
+  @else {
+    // Remove unit from $fs for calculations
+    @if $fs-unit == "px" {
+      $fs: divide($fs, $fs * 0 + 1);
+    }
+    @else if $fs-unit == "rem" {
+      $fs: divide($fs, divide($fs * 0 + 1, $rfs-rem-value));
+    }
+
+    // Set default font size
+    $rfs-static: if($rfs-font-size-unit == rem, #{divide($fs, $rfs-rem-value)}rem, #{$fs}px);
+
+    // Only add the media query if the font size is bigger than the minimum font size
+    @if $fs <= $rfs-base-font-size or not $enable-responsive-font-sizes {
+      font-size: #{$rfs-static}#{$rfs-suffix};
+    }
+    @else {
+      // Calculate the minimum font size for $fs
+      $fs-min: $rfs-base-font-size + divide($fs - $rfs-base-font-size, $rfs-factor);
+
+      // Calculate difference between $fs and the minimum font size
+      $fs-diff: $fs - $fs-min;
+
+      // Base font-size formatting
+      $min-width: if($rfs-font-size-unit == rem, #{divide($fs-min, $rfs-rem-value)}rem, #{$fs-min}px);
+
+      // Use `vmin` if two-dimensional is enabled
+      $variable-unit: if($rfs-two-dimensional, vmin, vw);
+
+      // Calculate the variable width between 0 and $rfs-breakpoint
+      $variable-width: #{divide($fs-diff * 100, $rfs-breakpoint)}#{$variable-unit};
+
+      // Set the calculated font-size
+      $rfs-fluid: calc(#{$min-width} + #{$variable-width}) #{$rfs-suffix};
+
+      // Breakpoint formatting
+      $mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit});
+
+      @include _rfs-disable-class {
+        font-size: #{$rfs-static}#{$rfs-suffix};
+      }
+
+      @include _rfs-media-query($mq-value) {
+        @include _rfs-enable-class {
+          font-size: $rfs-fluid;
+        }
+
+        // Include safari iframe resize fix if needed
+        min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null);
+      }
+    }
+  }
+}
+
+// The font-size & responsive-font-size mixins use RFS to rescale the font size
+@mixin font-size($fs, $important: false) {
+  @include rfs($fs, $important);
+}
+
+@mixin responsive-font-size($fs, $important: false) {
+  @include rfs($fs, $important);
+}

From b0a2b2aae1544384ac017ff76b11d9088d384cb1 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 11:45:29 +0000
Subject: [PATCH 33/82] 2.2.0

---
 scss/_template_variables.scss | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 113f9e9..873503d 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -4,21 +4,21 @@
 // -------------------------20190202
 // colors
 // -------------------------
-$black:                 #000;
+//$black:                 #000;
 $grayDarker:            #222;
 $grayDark:              #333;
 $gray:                  #555;
 $grayLight:             #999;
 $grayLighter:           #F5F5F5;
-$white:                 #fff;
-
-$graynavbarbg: 		#e5e5e5;
-$graynavbarfg: 		#555;
-$graynavbarlighter: 	#777;
-$graynavbardarker: 	#333;
-$activenavbarbg: 	#999;
-$activenavbarfg: 	#fff;
-$specialgreygradientstart: #ffffff;
+//$white:                   #fff
+
+$graynavbarbg: 		$gray-200; // was #e5e5e5;
+$graynavbarfg: 	    $gray-700; // was #555;
+$graynavbarlighter: $gray-600; // was #777;
+$graynavbardarker:  $gray-800; // was	#333;
+$activenavbarbg:    $gray-500; // was	#999;
+$activenavbarfg:    $gray-600; // was 	#fff;
+$specialgreygradientstart: $white; // was #ffffff;
 $specialgreygradientend: #e6e6e6;
 // BS3 temporary variables
 //## temporary Define the maximum width of `.container` for different screen sizes with BS 3 variables

From 8d92ae53ebd0000e10dfee43316b3e9c33d2c6f9 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 11:51:16 +0000
Subject: [PATCH 34/82] 2.2.0

---
 scss/_template_dropdown.scss | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/scss/_template_dropdown.scss b/scss/_template_dropdown.scss
index f5821ba..2334473 100644
--- a/scss/_template_dropdown.scss
+++ b/scss/_template_dropdown.scss
@@ -25,25 +25,25 @@ width: $brandWidth * 300 / 960; // < es = 375
 {// bs4 
 .navbar-dark {
   .navbar-brand {
-    color: $navbar-default-brand-color;
+    color: $navbar-light-brand-color;
 
    &:hover,
    &:focus  {
-      color: $navbar-default-brand-hover-color;
+      color: $navbar-light-brand-hover-color;
     }
   }
 
   .navbar-nav {
     .nav-link {
-      color: $navbar-default-color;
+      color: $navbar-light-color;
 
       &:hover,
       &:focus  {
-        color: $navbar-default-link-hover-color;
+        color: $navbar-light-link-hover-color;
       }
 
       &.disabled {
-        color: $navbar-default-link-disabled-color;
+        color: $navbar-light-link-disabled-color;
       }
     }
 
@@ -51,13 +51,13 @@ width: $brandWidth * 300 / 960; // < es = 375
     .active > .nav-link,
     .nav-link.show,
     .nav-link.active {
-      color: $navbar-default-link-active-color;
+      color: $navbar-light-link-active-color;
     }
   }
 
   .navbar-toggler {
-    color: $navbar-default-link-color;
-    border-color: $navbar-default-toggle-border-color;
+    color: $navbar-light-link-color;
+    border-color: $navbar-light-toggle-border-color;
   }
 
   .navbar-toggler-icon {
@@ -65,13 +65,13 @@ width: $brandWidth * 300 / 960; // < es = 375
   }
 
   .navbar-text {
-    color: $navbar-default-color;
+    color: $navbar-light-color;
     a {
-      color: $navbar-default-link-active-color;
+      color: $navbar-light-link-active-color;
 
       &:hover,
   &:focus  {
-        color: $navbar-default-link-active-color;
+        color: $navbar-light-link-active-color;
       }
     }
   }

From 6ec0ef860fd885ceee08b3e06920a7672ad9b45c Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 12:05:06 +0000
Subject: [PATCH 35/82] 2.2.0

---
 scss/_template_dropdown.scss | 22 +++++++++++-----------
 1 file changed, 11 insertions(+), 11 deletions(-)

diff --git a/scss/_template_dropdown.scss b/scss/_template_dropdown.scss
index 2334473..a9c4120 100644
--- a/scss/_template_dropdown.scss
+++ b/scss/_template_dropdown.scss
@@ -25,25 +25,25 @@ width: $brandWidth * 300 / 960; // < es = 375
 {// bs4 
 .navbar-dark {
   .navbar-brand {
-    color: $navbar-light-brand-color;
+    color: $navbar-dark-brand-color;
 
    &:hover,
    &:focus  {
-      color: $navbar-light-brand-hover-color;
+      color: $navbar-dark-brand-hover-color;
     }
   }
 
   .navbar-nav {
     .nav-link {
-      color: $navbar-light-color;
+      color: $navbar-dark-color;
 
       &:hover,
       &:focus  {
-        color: $navbar-light-link-hover-color;
+        color: $navbar-dark-hover-color; // $navbar-light-link-hover-color;
       }
 
       &.disabled {
-        color: $navbar-light-link-disabled-color;
+        color: $navbar-dark-link-disabled-color;
       }
     }
 
@@ -51,13 +51,13 @@ width: $brandWidth * 300 / 960; // < es = 375
     .active > .nav-link,
     .nav-link.show,
     .nav-link.active {
-      color: $navbar-light-link-active-color;
+      color: $navbar-dark-active-color; // $navbar-light-link-active-color;
     }
   }
 
   .navbar-toggler {
-    color: $navbar-light-link-color;
-    border-color: $navbar-light-toggle-border-color;
+    color: $navbar-dark-color;
+    border-color: $navbar-dark-toggle-border-color;
   }
 
   .navbar-toggler-icon {
@@ -65,13 +65,13 @@ width: $brandWidth * 300 / 960; // < es = 375
   }
 
   .navbar-text {
-    color: $navbar-light-color;
+    color: $navbar-dark-color;
     a {
-      color: $navbar-light-link-active-color;
+      color: $navbar-dark-active-color;
 
       &:hover,
   &:focus  {
-        color: $navbar-light-link-active-color;
+        color: $navbar-dark-active-color;
       }
     }
   }

From fbe6c5090c7574b7e789fe296b075c3c0ded9946 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 12:08:05 +0000
Subject: [PATCH 36/82] 2.2.0

---
 scss/_template_dropdown.scss | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scss/_template_dropdown.scss b/scss/_template_dropdown.scss
index a9c4120..86fe908 100644
--- a/scss/_template_dropdown.scss
+++ b/scss/_template_dropdown.scss
@@ -43,7 +43,7 @@ width: $brandWidth * 300 / 960; // < es = 375
       }
 
       &.disabled {
-        color: $navbar-dark-link-disabled-color;
+        color: $navbar-dark-disabled-color;
       }
     }
 

From 7378b896943f0c2c8fb2dabecb5d53279845a81f Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 12:11:26 +0000
Subject: [PATCH 37/82] 2.2.0

---
 scss/_template_dropdown.scss | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/scss/_template_dropdown.scss b/scss/_template_dropdown.scss
index 86fe908..c15793c 100644
--- a/scss/_template_dropdown.scss
+++ b/scss/_template_dropdown.scss
@@ -57,7 +57,7 @@ width: $brandWidth * 300 / 960; // < es = 375
 
   .navbar-toggler {
     color: $navbar-dark-color;
-    border-color: $navbar-dark-toggle-border-color;
+    border-color: $navbar-dark-toggler-border-color;
   }
 
   .navbar-toggler-icon {
@@ -71,7 +71,7 @@ width: $brandWidth * 300 / 960; // < es = 375
 
       &:hover,
   &:focus  {
-        color: $navbar-dark-active-color;
+        color: $navbar-dark-hover-color;
       }
     }
   }

From 15141345637c85a176619a57c8c920b300a56477 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 16:47:57 +0000
Subject: [PATCH 38/82] 2.2.0

---
 scss/_template_dropdown.scss  | 136 +++++++++----------
 scss/_template_variables.scss | 245 ++--------------------------------
 2 files changed, 79 insertions(+), 302 deletions(-)

diff --git a/scss/_template_dropdown.scss b/scss/_template_dropdown.scss
index c15793c..4cff763 100644
--- a/scss/_template_dropdown.scss
+++ b/scss/_template_dropdown.scss
@@ -9,7 +9,7 @@
 11-2-2019 brandwith relatief tov lg
 28-12-2021 .dropdown-menu > li > a replaced by .dropdown-menu > .nav-item > .nav-link to give it higher priority in BS4 and BS5
  and padding and line-height px value changed to rem value
-06-10-2024 2.2.0 remove bs3, use more bs4, bs5 variables, make bs5 the default 
+06-10-2024 2.2.0 remove bs3 and alternative old navbars, use more bs4, bs5 variables, make bs5 the default 
 
 -----------------------------------------*/
 #img_brandImage
@@ -21,73 +21,73 @@ width: $brandWidth * 300 / 960; // < es = 375
 // --------------------------------------------------
 
 
-@if $twbs_version == 4
-{// bs4 
-.navbar-dark {
-  .navbar-brand {
-    color: $navbar-dark-brand-color;
-
-   &:hover,
-   &:focus  {
-      color: $navbar-dark-brand-hover-color;
-    }
-  }
-
-  .navbar-nav {
-    .nav-link {
-      color: $navbar-dark-color;
-
-      &:hover,
-      &:focus  {
-        color: $navbar-dark-hover-color; // $navbar-light-link-hover-color;
-      }
-
-      &.disabled {
-        color: $navbar-dark-disabled-color;
-      }
-    }
-
-    .show > .nav-link,
-    .active > .nav-link,
-    .nav-link.show,
-    .nav-link.active {
-      color: $navbar-dark-active-color; // $navbar-light-link-active-color;
-    }
-  }
-
-  .navbar-toggler {
-    color: $navbar-dark-color;
-    border-color: $navbar-dark-toggler-border-color;
-  }
-
-  .navbar-toggler-icon {
-    background-image: $navbar-dark-toggler-icon-bg;
-  }
-
-  .navbar-text {
-    color: $navbar-dark-color;
-    a {
-      color: $navbar-dark-active-color;
-
-      &:hover,
-  &:focus  {
-        color: $navbar-dark-hover-color;
-      }
-    }
-  }
-// einde bs4 navbar-dark
-}
-// einde bs4
-} 
-@else // bs5
-{
-}
-
-
-.navbar-brand,
-.navbar-nav > li > a {
-  text-shadow: 0 1px 0 rgba(255,255,255,.25);
-} 
+//@if $twbs_version == 4
+//{// bs4 
+//.navbar-dark {
+//  .navbar-brand {
+//    color: $navbar-dark-brand-color;
+//
+//   &:hover,
+//   &:focus  {
+//      color: $navbar-dark-brand-hover-color;
+//    }
+//  }
+//
+//  .navbar-nav {
+//    .nav-link {
+//      color: $navbar-dark-color;
+//
+//      &:hover,
+//      &:focus  {
+//        color: $navbar-dark-hover-color; // $navbar-light-link-hover-color;
+//      }
+//
+//      &.disabled {
+//        color: $navbar-dark-disabled-color;
+//      }
+//    }
+//
+//    .show > .nav-link,
+//    .active > .nav-link,
+//    .nav-link.show,
+//    .nav-link.active {
+//      color: $navbar-dark-active-color; // $navbar-light-link-active-color;
+//    }
+//  }
+//
+//  .navbar-toggler {
+//    color: $navbar-dark-color;
+//    border-color: $navbar-dark-toggler-border-color;
+//  }
+//
+//  .navbar-toggler-icon {
+//    background-image: $navbar-dark-toggler-icon-bg;
+//  }
+//
+//  .navbar-text {
+//    color: $navbar-dark-color;
+//    a {
+//      color: $navbar-dark-active-color;
+//
+//      &:hover,
+//  &:focus  {
+//        color: $navbar-dark-hover-color;
+//      }
+//    }
+//  }
+//// einde bs4 navbar-dark
+//}
+//// einde bs4
+//} 
+//@else // bs5
+//{
+//}
+//
+//
+//.navbar-brand,
+//.navbar-nav > li > a {
+//  text-shadow: 0 1px 0 rgba(255,255,255,.25);
+//} 
 
 
 
diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 873503d..34faf73 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -20,259 +20,36 @@ $activenavbarbg:    $gray-500; // was	#999;
 $activenavbarfg:    $gray-600; // was 	#fff;
 $specialgreygradientstart: $white; // was #ffffff;
 $specialgreygradientend: #e6e6e6;
-// BS3 temporary variables
-//## temporary Define the maximum width of `.container` for different screen sizes with BS 3 variables
-//## Gray and brand colors for use across Bootstrap.
-
-//$gray-base:              #000;
-//$gray-darker:            lighten($gray-base, 13.5%); // #222
-//$gray-dark:              lighten($gray-base, 20%);   // #333
-//$gray:                   lighten($gray-base, 33.5%); // #555
-//$gray-light:             lighten($gray-base, 46.7%); // #777
-//$gray-lighter:           lighten($gray-base, 93.5%); // #eee
-//
-//$brand-primary:         darken(#428bca, 6.5%); // #337ab7
-//$brand-success:         #5cb85c;
-//$brand-info:            #5bc0de;
-//$brand-warning:         #f0ad4e;
-//$brand-danger:          #d9534f;
-
-
-//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
-
-//$padding-base-vertical:     6px;
-//$padding-base-horizontal:   12px;
-//
-//$padding-large-vertical:    10px;
-//$padding-large-horizontal:  16px;
-//
-//$padding-small-vertical:    5px;
-//$padding-small-horizontal:  10px;
-//
-//$padding-xs-vertical:       1px;
-//$padding-xs-horizontal:     5px;
-//
-//$line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome
-//$line-height-small:         1.5;
-//
-//$border-radius-base:        4px;
-//$border-radius-large:       6px;
-//$border-radius-small:       3px;
 
-////** Global color for active items (e.g., navs or dropdowns).
-//$component-active-color:    #fff;
-////** Global background color for active items (e.g., navs or dropdowns).
-//$component-active-bg:       $brand-primary;
-//
-////** Width of the `border` for generating carets that indicator dropdowns.
-//$caret-width-base:          4px;
-////** Carets increase slightly in size for larger components.
-//$caret-width-large:         5px;
-//
-////** Background color for ``.
-//$body-bg:               #fff;
-////** Global text color on ``.
-//$text-color:            $gray-dark;
-//
-////** Global textual link color.
-//$link-color:            $brand-primary;
-////** Link hover color set via `darken()` function.
-//$link-hover-color:      darken($link-color, 15%);
-////** Link hover decoration.
-//$link-hover-decoration: underline;
-//
-//
-//
-////## Font, line-height, and color for body text, headings, and more.
-//
-//$font-family-sans-serif:  "Helvetica Neue", Helvetica, Arial, sans-serif;
-//$font-family-serif:       Georgia, "Times New Roman", Times, serif;
-////** Default monospace fonts for ``, ``, and `
`.
-//$font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
-//$font-family-base:        $font-family-sans-serif;
-//
-//$font-size-base:          14px;
-//$font-size-large:         ceil(($font-size-base * 1.25)); // ~18px
-//$font-size-small:         ceil(($font-size-base * 0.85)); // ~12px
-//
-//$font-size-h1:            floor(($font-size-base * 2.6)); // ~36px
-//$font-size-h2:            floor(($font-size-base * 2.15)); // ~30px
-//$font-size-h3:            ceil(($font-size-base * 1.7)); // ~24px
-//$font-size-h4:            ceil(($font-size-base * 1.25)); // ~18px
-//$font-size-h5:            $font-size-base;
-//$font-size-h6:            ceil(($font-size-base * 0.85)); // ~12px
-//
-//
-////** Unit-less `line-height` for use in components like buttons.
-//$line-height-base:        1.428571429; // 20/14
-////** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
-//$line-height-computed:    floor(($font-size-base * $line-height-base)); // ~20px
-
-
-// Extra small screen / phone
-//** Deprecated `$screen-xs` as of v3.0.1
-//$screen-xs:                  map-get($grid-breakpoints, "sm"); // was  480px;
-//** Deprecated `$screen-xs-min` as of v3.2.0
+// BS3 temporary variables
 $screen-xs-min:              breakpoint-min( "sm"); // was $screen-xs;
-//** Deprecated `$screen-phone` as of v3.0.1
-//$screen-phone:               $screen-xs-min;
-
-// Small screen / tablet
-//** Deprecated `$screen-sm` as of v3.0.1
-//$screen-sm:                  map-get($grid-breakpoints, "md"); // was  768px;
 $screen-sm-min:              breakpoint-min( "md"); // was $screen-sm;
-//** Deprecated `$screen-tablet` as of v3.0.1
-$screen-tablet:              $screen-sm-min;
-
-// Medium screen / desktop
-//** Deprecated `$screen-md` as of v3.0.1
-//$screen-md:                  map-get($grid-breakpoints, "lg"); // was  992px;
 $screen-md-min:              breakpoint-min( "lg"); // was $screen-md;
-//** Deprecated `$screen-desktop` as of v3.0.1
-//$screen-desktop:             $screen-md-min;
-
-// Large screen / wide desktop
-//** Deprecated `$screen-lg` as of v3.0.1
-//$screen-lg:                  map-get($grid-breakpoints, "xl"); // was  1200px;
 $screen-lg-min:              breakpoint-min( "xl"); // was $screen-lg;
-//** Deprecated `$screen-lg-desktop` as of v3.0.1
-//$screen-lg-desktop:          $screen-lg-min;
+// Large screen / wide desktop   tijdelijk bs3 type vaste breakpoints
+$screen-xl-min:              breakpoint-min( "xxl"); // was 1200px;
+//$screen-xxl-min:             breakpoint-min( "xxl"); // was 1440px;
+//$screen-xxxl-min:            1600px;
 
+$screen-xs-max:              breakpoint-max( "md"); // was($screen-sm-min - 1);
+$screen-sm-max:              breakpoint-max( "lg"); // was($screen-md-min - 1);
+$screen-md-max:              breakpoint-max( "xl"); // was($screen-lg-min - 1);
 // So media queries don't overlap when required, provide a maximum
-$screen-xs-max:              ($screen-sm-min - 1);
-$screen-sm-max:              ($screen-md-min - 1);
-$screen-md-max:              ($screen-lg-min - 1);
+$screen-lg-max:              breakpoint-max( "xxl"); // was($screen-xl-min - 1);
+//$screen-xl-max:              ($screen-xxl-min - 1);
+//$screen-xxl-max:             ($screen-xxxl-min - 1);
 
 
 // Small screen / tablet
 $grid-gutter-width:           1.5rem !default; // from _bs5 variabels.
 
-$container-tablet:             calc(720px + $grid-gutter-width); 
-//** For `$screen-sm-min` and up.
 $container-sm:                 breakpoint-min( "md"); // was  $container-tablet;
-
-// Medium screen / desktop
-$container-desktop:            calc(940px + $grid-gutter-width);
 //** For `$screen-md-min` and up.
 $container-md:                 breakpoint-min( "lg"); // was $container-desktop;
-
-// Large screen / wide desktop
-$container-large-desktop:      calc(1140px + $grid-gutter-width);
 //** For `$screen-lg-min` and up.
 $container-lg:                breakpoint-min( "xl"); // was $container-large-desktop;
 //$container-lg:                @include media-breakpoint-up("lg"); // was  $container-large-desktop;
 
-// Large screen / wide desktop   tijdelijk bs3 type vaste breakpoints
-$screen-xl-min:              breakpoint-min( "xl"); // was 1200px;
-$screen-xxl-min:             breakpoint-min( "xxl"); // was 1440px;
-$screen-xxxl-min:            1600px;
-
-//** Deprecated `$screen-lg-desktop` as of v3.0.1
-$screen-lg-desktop:           $screen-lg-min;
-
-// So media queries don't overlap when required, provide a maximum
-$screen-lg-max:              ($screen-xl-min - 1);
-$screen-xl-max:              ($screen-xxl-min - 1);
-$screen-xxl-max:             ($screen-xxxl-min - 1);
-
-////== Navbar
-////
-////##
-//
-//// Basics of a navbar
-//$navbar-height:                    50px;
-//$navbar-margin-bottom:             $line-height-computed;
-//$navbar-border-radius:             $border-radius-base;
-//$navbar-padding-horizontal:        floor(($grid-gutter-width / 2));
-//$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2);
-//$navbar-collapse-max-height:       340px;
-//
-//$navbar-default-color:             #777;
-//$navbar-default-bg:                #f8f8f8;
-//$navbar-default-border:            darken($navbar-default-bg, 6.5%);
-//
-//// Navbar links
-//$navbar-default-link-color:                #777;
-//$navbar-default-link-hover-color:          #333;
-//$navbar-default-link-hover-bg:             transparent;
-//$navbar-default-link-active-color:         #555;
-//$navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%);
-//$navbar-default-link-disabled-color:       #ccc;
-//$navbar-default-link-disabled-bg:          transparent;
-//
-//// Navbar brand label
-//$navbar-default-brand-color:               $navbar-default-link-color;
-//$navbar-default-brand-hover-color:         darken($navbar-default-brand-color, 10%);
-//$navbar-default-brand-hover-bg:            transparent;
-//
-//// Navbar toggle
-$navbar-default-toggle-hover-bg:           $component-active-bg; // #ddd;
-$navbar-default-toggle-icon-bar-bg:        $navbar-light-toggler-icon-bg; // #888;
-$navbar-default-toggle-border-color:       $navbar-light-toggler-border-color; // was #ddd;
-//
-////=== Shared nav styles
-//$nav-link-padding:                          10px 15px;
-$nav-link-hover-bg:                         $gray-200; // $gray-lighter;
-//
-$nav-disabled-link-color:                   $gray-500; // $gray-light;
-$nav-disabled-link-hover-color:             $gray-500;  // $gray-light;
-//
-////== Tabs
-//$nav-tabs-border-color:                     #ddd;
-//
-//$nav-tabs-link-hover-border-color:          $gray-lighter;
-//
-$nav-tabs-active-link-hover-bg:             $body-bg;
-$nav-tabs-active-link-hover-color:          $gray;
-$nav-tabs-active-link-hover-border-color:   #ddd;
-//
-//$nav-tabs-justified-link-border-color:            #ddd;
-//$nav-tabs-justified-active-link-border-color:     $body-bg;
-//
-////== Pills
-//$nav-pills-border-radius:                   $border-radius-base;
-$nav-pills-active-link-hover-bg:            $component-active-bg;
-$nav-pills-active-link-hover-color:         $component-active-color;
-//
-//// ** Disabled cursor for form controls and buttons.
-$cursor-disabled:                not-allowed;
-//
-//
-////== Dropdowns
-////
-////## Dropdown menu container and contents.
-//
-////** Background for the dropdown menu.
-//$dropdown-bg:                    #fff;
-////** Dropdown menu `border-color`.
-//$dropdown-border:                rgba(0,0,0,.15);
-////** Dropdown menu `border-color` **for IE8**.
-//$dropdown-fallback-border:       #ccc;
-////** Divider color for between dropdown items.
-//$dropdown-divider-bg:            #e5e5e5;
-//
-////** Dropdown link text color.
-//$dropdown-link-color:            $gray-dark;
-////** Hover color for dropdown links.
-//$dropdown-link-hover-color:      darken($gray-dark, 5%);
-////** Hover background for dropdown links.
-//$dropdown-link-hover-bg:         #f5f5f5;
-//
-////** Active dropdown menu item text color.
-//$dropdown-link-active-color:     $component-active-color;
-////** Active dropdown menu item background color.
-//$dropdown-link-active-bg:        $component-active-bg;
-//
-////** Disabled dropdown menu item background color.
-//$dropdown-link-disabled-color:   $gray-light;
-//
-////** Text color for headers within dropdown menus.
-//$dropdown-header-color:          $gray-light;
-//
-////** Deprecated `$dropdown-caret-color` as of v3.1.0
-//$dropdown-caret-color:           #000;
-//
-//
 
 // end BS3 temporary variables
 

From 0078c525b6ee63594a851e1535011d9a3426fb98 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 16:50:07 +0000
Subject: [PATCH 39/82] 2.2.0

---
 scss/_template_variables.scss | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 34faf73..f9913a7 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -142,9 +142,8 @@ $span1 : $wsa12Col;
 	padding-top: $screen-md-min;
 	padding-right: $screen-lg-min;
 	padding-left: $screen-xl-min;
-	padding-bottom: $screen-xxl-min    ;
+//	padding-bottom: $screen-xxl-min    ;
 	
-	@debug "$screen-md-min: #{$screen-md-min}";
 
 	
 	

From e167462a9d00ecdd94ea0330c011df00ea3ec064 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 18:04:14 +0000
Subject: [PATCH 40/82] 2.2.0

---
 scss/_template_variables.scss | 38 ++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index f9913a7..0b1acb7 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -49,7 +49,43 @@ $container-md:                 breakpoint-min( "lg"); // was $container-desktop;
 //** For `$screen-lg-min` and up.
 $container-lg:                breakpoint-min( "xl"); // was $container-large-desktop;
 //$container-lg:                @include media-breakpoint-up("lg"); // was  $container-large-desktop;
-
+////== Navbar
+////
+////##
+//
+//// Basics of a navbar
+//// Navbar toggle
+$navbar-default-toggle-hover-bg:           $component-active-bg; // #ddd;
+$navbar-default-toggle-icon-bar-bg:        $navbar-light-toggler-icon-bg; // #888;
+$navbar-default-toggle-border-color:       $navbar-light-toggler-border-color; // was #ddd;
+//
+////=== Shared nav styles
+//$nav-link-padding:                          10px 15px;
+$nav-link-hover-bg:                         $gray-200; // $gray-lighter;
+//
+$nav-disabled-link-color:                   $gray-500; // $gray-light;
+$nav-disabled-link-hover-color:             $gray-500;  // $gray-light;
+//
+////== Tabs
+//$nav-tabs-border-color:                     #ddd;
+//
+//$nav-tabs-link-hover-border-color:          $gray-lighter;
+//
+$nav-tabs-active-link-hover-bg:             $body-bg;
+$nav-tabs-active-link-hover-color:          $gray;
+$nav-tabs-active-link-hover-border-color:   #ddd;
+//
+//$nav-tabs-justified-link-border-color:            #ddd;
+//$nav-tabs-justified-active-link-border-color:     $body-bg;
+//
+////== Pills
+//$nav-pills-border-radius:                   $border-radius-base;
+$nav-pills-active-link-hover-bg:            $component-active-bg;
+$nav-pills-active-link-hover-color:         $component-active-color;
+//
+//// ** Disabled cursor for form controls and buttons.
+$cursor-disabled:                not-allowed;
+//
 
 // end BS3 temporary variables
 

From 33a17b78d6fc3cf2064c7492c429081451bebbe0 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Sun, 6 Oct 2024 22:32:59 +0000
Subject: [PATCH 41/82] 2.2.0

---
 scss/_template_dropdown.scss  | 24 ++++++++++++------------
 scss/_template_variables.scss | 24 ++++++++++++------------
 2 files changed, 24 insertions(+), 24 deletions(-)

diff --git a/scss/_template_dropdown.scss b/scss/_template_dropdown.scss
index 4cff763..2928b47 100644
--- a/scss/_template_dropdown.scss
+++ b/scss/_template_dropdown.scss
@@ -228,18 +228,18 @@ color: #333;
       &:hover,
       &:focus {
         text-decoration: none;
-        background-color: $nav-link-hover-bg;
+        background-color: $nav-tabs-link-active-bg; // was $nav-link-hover-bg;
       }
     }
     // Disabled state sets text to gray and nukes hover/tab effects
     &.disabled > a {
-      color: $nav-disabled-link-color;
+      color: $nav-link-disabled-color; // was $nav-disabled-link-color;
       &:hover,
       &:focus {
-        color: $nav-disabled-link-hover-color;
+        color: $nav-link-disabled-color; // was $nav-disabled-link-hover-color;
         text-decoration: none;
         background-color: transparent;
-        cursor: $cursor-disabled;
+        cursor: not-allowed; // was $cursor-disabled;
       }
     }
   }
@@ -249,8 +249,8 @@ color: #333;
     &,
     &:hover,
     &:focus {
-      background-color: $nav-link-hover-bg;
-      border-color: $link-color;
+      background-color: gray; // was $nav-link-hover-bg;
+      border-color: $nav-tabs-link-hover-border-color; // was $link-color;
     }
   }
  } 
@@ -272,7 +272,7 @@ color: #333;
       border: 1px solid transparent;
       border-radius: $nav-tabs-border-radius $nav-tabs-border-radius 0 0; // was $border-radius-base $border-radius-base 0 0;
       &:hover {
-        border-color: $nav-tabs-link-hover-border-color $nav-tabs-link-hover-border-color $nav-tabs-border-color;
+        border-color: $nav-tabs-link-hover-border-color;
       }
     }
 
@@ -281,9 +281,9 @@ color: #333;
       &,
       &:hover,
       &:focus {
-        color: $nav-tabs-active-link-hover-color;
-        background-color: $nav-tabs-active-link-hover-bg;
-        border: 1px solid $nav-tabs-active-link-hover-border-color;
+        color: $nav-tabs-link-hover-color;
+        background-color: $body-bg; // was $nav-tabs-active-link-hover-bg;
+        border: 1px solid #ddd; // was $nav-tabs-active-link-hover-border-color;
         border-bottom-color: transparent;
         cursor: default;
       }
@@ -312,8 +312,8 @@ color: #333;
       &,
       &:hover,
       &:focus {
-        color: $nav-pills-active-link-hover-color;
-        background-color: $nav-pills-active-link-hover-bg;
+        color: $nav-pills-link-active-color; // was $nav-pills-active-link-hover-color;
+        background-color: $nav-pills-link-active-bg; // was $nav-pills-active-link-hover-bg;
       }
     }
   }
diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 0b1acb7..e73fd5a 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -55,36 +55,36 @@ $container-lg:                breakpoint-min( "xl"); // was $container-large-des
 //
 //// Basics of a navbar
 //// Navbar toggle
-$navbar-default-toggle-hover-bg:           $component-active-bg; // #ddd;
-$navbar-default-toggle-icon-bar-bg:        $navbar-light-toggler-icon-bg; // #888;
-$navbar-default-toggle-border-color:       $navbar-light-toggler-border-color; // was #ddd;
+//$navbar-default-toggle-hover-bg:           $component-active-bg; // #ddd;
+//$navbar-default-toggle-icon-bar-bg:        $navbar-light-toggler-icon-bg; // #888;
+//$navbar-default-toggle-border-color:       $navbar-light-toggler-border-color; // was #ddd;
 //
 ////=== Shared nav styles
 //$nav-link-padding:                          10px 15px;
-$nav-link-hover-bg:                         $gray-200; // $gray-lighter;
+// $nav-link-hover-bg:                         $gray-200; // $gray-lighter;
 //
-$nav-disabled-link-color:                   $gray-500; // $gray-light;
-$nav-disabled-link-hover-color:             $gray-500;  // $gray-light;
+//$nav-disabled-link-color:                   $nav-link-disabled-color; // $gray-500; // $gray-light;
+//$nav-disabled-link-hover-color:             $nav-link-disabled-color; // $gray-500;  // $gray-light;
 //
 ////== Tabs
 //$nav-tabs-border-color:                     #ddd;
 //
 //$nav-tabs-link-hover-border-color:          $gray-lighter;
 //
-$nav-tabs-active-link-hover-bg:             $body-bg;
-$nav-tabs-active-link-hover-color:          $gray;
-$nav-tabs-active-link-hover-border-color:   #ddd;
+//$nav-tabs-active-link-hover-bg:             $body-bg;
+//$nav-tabs-active-link-hover-color:          $gray;
+//$nav-tabs-active-link-hover-border-color:   #ddd;
 //
 //$nav-tabs-justified-link-border-color:            #ddd;
 //$nav-tabs-justified-active-link-border-color:     $body-bg;
 //
 ////== Pills
 //$nav-pills-border-radius:                   $border-radius-base;
-$nav-pills-active-link-hover-bg:            $component-active-bg;
-$nav-pills-active-link-hover-color:         $component-active-color;
+//$nav-pills-active-link-hover-bg:            $component-active-bg;
+//$nav-pills-active-link-hover-color:         $component-active-color;
 //
 //// ** Disabled cursor for form controls and buttons.
-$cursor-disabled:                not-allowed;
+// $cursor-disabled:                not-allowed;
 //
 
 // end BS3 temporary variables

From 1122f07e2951a784bf0bc9c01d1ef8356e00c40a Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Mon, 7 Oct 2024 09:31:55 +0000
Subject: [PATCH 42/82] 2.2.0

unnecessary rules commented out
---
 scss/_template_dropdown.scss | 84 ++++++++++++++----------------------
 1 file changed, 33 insertions(+), 51 deletions(-)

diff --git a/scss/_template_dropdown.scss b/scss/_template_dropdown.scss
index 2928b47..29529f1 100644
--- a/scss/_template_dropdown.scss
+++ b/scss/_template_dropdown.scss
@@ -260,28 +260,28 @@ color: #333;
 // Give the tabs something to sit on
 .nav-tabs {
   border-bottom: 1px solid $nav-tabs-border-color;
-  > li {
+  > li {    // keep 7/24
     float: left;
     // Make the list-items overlay the bottom border
     margin-bottom: -1px;
 
     // Actual tabs (as links)
-    > a {
+    > a { // keep 7/24
       margin-right: 2px;
       line-height: $line-height-base;
-      border: 1px solid transparent;
-      border-radius: $nav-tabs-border-radius $nav-tabs-border-radius 0 0; // was $border-radius-base $border-radius-base 0 0;
-      &:hover {
-        border-color: $nav-tabs-link-hover-border-color;
-      }
+//      border: 1px solid transparent;
+//      border-radius: $nav-tabs-border-radius $nav-tabs-border-radius 0 0; // was $border-radius-base $border-radius-base 0 0;
+//      &:hover {
+//        border-color: $nav-tabs-link-hover-border-color;
+//      }
     }
 
     // Active state, and its :hover to override normal :hover
-    &.active > a {
+    &.active > a { // keep 7/24
       &,
       &:hover,
       &:focus {
-        color: $nav-tabs-link-hover-color;
+//        color: $nav-tabs-link-hover-color;
         background-color: $body-bg; // was $nav-tabs-active-link-hover-bg;
         border: 1px solid #ddd; // was $nav-tabs-active-link-hover-border-color;
         border-bottom-color: transparent;
@@ -295,29 +295,29 @@ color: #333;
 
 // Pills
 // -------------------------
-.nav-pills {
-  > li {
-    float: left;
-
-    // Links rendered as pills
-    > a {
-      border-radius: $nav-pills-border-radius;
-    }
-    + li {
-      margin-left: 2px;
-    }
-
-    // Active state
-    &.active > a {
-      &,
-      &:hover,
-      &:focus {
-        color: $nav-pills-link-active-color; // was $nav-pills-active-link-hover-color;
-        background-color: $nav-pills-link-active-bg; // was $nav-pills-active-link-hover-bg;
-      }
-    }
-  }
-}
+//.nav-pills {
+//  > li {
+//    float: left;
+//
+//    // Links rendered as pills
+//    > a {
+//      border-radius: $nav-pills-border-radius;
+//    }
+//    + li {
+//      margin-left: 2px;
+//    }
+//
+//    // Active state
+//    &.active > a {
+//      &,
+//      &:hover,
+//      &:focus {
+//        color: $nav-pills-link-active-color; // was $nav-pills-active-link-hover-color;
+//        background-color: $nav-pills-link-active-bg; // was $nav-pills-active-link-hover-bg;
+//      }
+//    }
+//  }
+//}
 // uit nav.less einde 
 /* ===================================================================================
 	BOOTSTRAP MEDIA QUERIES OVERRIDES
@@ -434,7 +434,7 @@ I only made one small addition to the standard HTML – I added a container
 
 }
 
-@if $twbs_version == 4 {
+
 @include media-breakpoint-up(sm)
 {  // min 576
 #img_brandImage
@@ -456,23 +456,5 @@ width: $brandWidth * 720 / 960; // md cont = 720
 width: $brandWidth ; // lg 100%
 }
 }/* einde up(lg) */
-} // end twbs 4
-@else { // bs3
-// @include media-breakpoint-up(md) { bs4
-@media (min-width: $screen-sm-min){
-#img_brandImage
-{ 
-width: $brandWidth * 720 / 960; // md cont = 720
-}
-}
-// @include media-breakpoint-up(lg) { bs4
-@media (min-width: $screen-md-min )  { /* desktop (width >= 992px) */
-#img_brandImage
-{ 
-width: $brandWidth ; // lg 100%
-}
-}
-
-} // end twbs 3
 
 

From 123fa004db7f89c40e5b26e61de71cdbac7bde8d Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Mon, 7 Oct 2024 09:40:38 +0000
Subject: [PATCH 43/82] 2.2.0

---
 scss/_template_css.scss | 32 ++------------------------------
 1 file changed, 2 insertions(+), 30 deletions(-)

diff --git a/scss/_template_css.scss b/scss/_template_css.scss
index dad71d9..29e189b 100644
--- a/scss/_template_css.scss
+++ b/scss/_template_css.scss
@@ -27,7 +27,7 @@
 //     but an extra class in the page header,  ul may be used in stead of ol and Pias is stopped. So .newsfeed_rssfoto is approximately 
 //     replaced by by ._rssfoto .newsfeed. At the same time make more use of scss possibillities use css attribute match selectors and
 //     remove unnecessary selectors.
-
+//  20241007 2.2.0 remove BS3 and replace some variables with BS4 BS5 standard 
 /* ===========================
 	alle schermbreedtes
 	Write your general styles eerst voor alle schermbreedtes, 
@@ -79,34 +79,6 @@
 }
 .visually-hidden {display:none;} // header language selector joomla 4 use this bs5 selector
 } // einde bs4
-@if $twbs_version == 3 { // bs3
-#headerleft {
-  position: relative;
-  float:left;
-  width:$asHeadLeftWidth;
-  height: 0px;
-  margin-top: $hlMarginTop;
-  margin-left:$hlMarginLeft;
-  margin-bottom: $hlMarginBottom; 	
-  padding-top:0;
-  padding-bottom: $hlHeight;
-      div.inner {
-	position: absolute;
-	top: 0;
-	left: 0;
-	width: 100%;
-	height: 100%;
-	}
-}
-.header-inner .navbar
- {padding:0;}
-.span12
-{ //padding span12 extra voor BS3 in BS4/5 wordt col12 gebruikt en staan deze paddings al voor alle col-deimensies.
-padding-right: 15px;
-padding-left: 15px;	
-}
-.visually-hidden {display:none;} // header language selector joomla 4 use this bs5 selector
-} // einde bs3
 #navbar-right-mod
 {
 	display: inline-block;
@@ -241,7 +213,7 @@ order: -1;
 	display:block;  // bs 4 voorlopig
 }
 .navbar-toggle .icon-bar {
-    background-color: $navbar-default-toggle-icon-bar-bg;
+    background-color: $navbar-light-toggle-icon-bar-bg;
 }
 /* transparent navbar */
 .navbar.navbar-default.transparent,

From 3f427d917c0bdd7003a82983126a9b3c65bcbd9d Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Mon, 7 Oct 2024 09:46:02 +0000
Subject: [PATCH 44/82] 2.2.0

---
 scss/_template_css.scss | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/scss/_template_css.scss b/scss/_template_css.scss
index 29e189b..78594cb 100644
--- a/scss/_template_css.scss
+++ b/scss/_template_css.scss
@@ -212,9 +212,9 @@ order: -1;
     overflow-y: visible;
 	display:block;  // bs 4 voorlopig
 }
-.navbar-toggle .icon-bar {
-    background-color: $navbar-light-toggle-icon-bar-bg;
-}
+//.navbar-toggle .icon-bar {  probably not used in BS4 + 10/2024
+//    background-color: $navbar-light-toggle-icon-bar-bg;
+//}
 /* transparent navbar */
 .navbar.navbar-default.transparent,
 .navbar.navbar-inverse.transparent{ 

From 65bed4d2734064e3e5a0aaac47bbb65dddc95638 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Mon, 7 Oct 2024 09:58:09 +0000
Subject: [PATCH 45/82] 2.2.0 removed outcommented sources

---
 scss/_template_css.scss       |   5 +-
 scss/_template_dropdown.scss  | 105 ----------------------------------
 scss/_template_variables.scss |  58 +++----------------
 3 files changed, 9 insertions(+), 159 deletions(-)

diff --git a/scss/_template_css.scss b/scss/_template_css.scss
index 78594cb..ee218c0 100644
--- a/scss/_template_css.scss
+++ b/scss/_template_css.scss
@@ -212,10 +212,7 @@ order: -1;
     overflow-y: visible;
 	display:block;  // bs 4 voorlopig
 }
-//.navbar-toggle .icon-bar {  probably not used in BS4 + 10/2024
-//    background-color: $navbar-light-toggle-icon-bar-bg;
-//}
-/* transparent navbar */
+// * transparent navbar * /
 .navbar.navbar-default.transparent,
 .navbar.navbar-inverse.transparent{ 
 
diff --git a/scss/_template_dropdown.scss b/scss/_template_dropdown.scss
index 29529f1..501d46a 100644
--- a/scss/_template_dropdown.scss
+++ b/scss/_template_dropdown.scss
@@ -17,80 +17,6 @@
 width: $brandWidth * 300 / 960; // < es = 375
 }
 
-// Alternate navbars uit navbar.less
-// --------------------------------------------------
-
-
-//@if $twbs_version == 4
-//{// bs4 
-//.navbar-dark {
-//  .navbar-brand {
-//    color: $navbar-dark-brand-color;
-//
-//   &:hover,
-//   &:focus  {
-//      color: $navbar-dark-brand-hover-color;
-//    }
-//  }
-//
-//  .navbar-nav {
-//    .nav-link {
-//      color: $navbar-dark-color;
-//
-//      &:hover,
-//      &:focus  {
-//        color: $navbar-dark-hover-color; // $navbar-light-link-hover-color;
-//      }
-//
-//      &.disabled {
-//        color: $navbar-dark-disabled-color;
-//      }
-//    }
-//
-//    .show > .nav-link,
-//    .active > .nav-link,
-//    .nav-link.show,
-//    .nav-link.active {
-//      color: $navbar-dark-active-color; // $navbar-light-link-active-color;
-//    }
-//  }
-//
-//  .navbar-toggler {
-//    color: $navbar-dark-color;
-//    border-color: $navbar-dark-toggler-border-color;
-//  }
-//
-//  .navbar-toggler-icon {
-//    background-image: $navbar-dark-toggler-icon-bg;
-//  }
-//
-//  .navbar-text {
-//    color: $navbar-dark-color;
-//    a {
-//      color: $navbar-dark-active-color;
-//
-//      &:hover,
-//  &:focus  {
-//        color: $navbar-dark-hover-color;
-//      }
-//    }
-//  }
-//// einde bs4 navbar-dark
-//}
-//// einde bs4
-//} 
-//@else // bs5
-//{
-//}
-//
-//
-//.navbar-brand,
-//.navbar-nav > li > a {
-//  text-shadow: 0 1px 0 rgba(255,255,255,.25);
-//} 
-
-
-
 /* ======================
 	GENERAL STYLES
 	===================== */
@@ -269,11 +195,6 @@ color: #333;
     > a { // keep 7/24
       margin-right: 2px;
       line-height: $line-height-base;
-//      border: 1px solid transparent;
-//      border-radius: $nav-tabs-border-radius $nav-tabs-border-radius 0 0; // was $border-radius-base $border-radius-base 0 0;
-//      &:hover {
-//        border-color: $nav-tabs-link-hover-border-color;
-//      }
     }
 
     // Active state, and its :hover to override normal :hover
@@ -281,7 +202,6 @@ color: #333;
       &,
       &:hover,
       &:focus {
-//        color: $nav-tabs-link-hover-color;
         background-color: $body-bg; // was $nav-tabs-active-link-hover-bg;
         border: 1px solid #ddd; // was $nav-tabs-active-link-hover-border-color;
         border-bottom-color: transparent;
@@ -293,31 +213,6 @@ color: #333;
 }
 
 
-// Pills
-// -------------------------
-//.nav-pills {
-//  > li {
-//    float: left;
-//
-//    // Links rendered as pills
-//    > a {
-//      border-radius: $nav-pills-border-radius;
-//    }
-//    + li {
-//      margin-left: 2px;
-//    }
-//
-//    // Active state
-//    &.active > a {
-//      &,
-//      &:hover,
-//      &:focus {
-//        color: $nav-pills-link-active-color; // was $nav-pills-active-link-hover-color;
-//        background-color: $nav-pills-link-active-bg; // was $nav-pills-active-link-hover-bg;
-//      }
-//    }
-//  }
-//}
 // uit nav.less einde 
 /* ===================================================================================
 	BOOTSTRAP MEDIA QUERIES OVERRIDES
diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index e73fd5a..ff6009a 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -8,6 +8,7 @@
 $grayDarker:            #222;
 $grayDark:              #333;
 $gray:                  #555;
+// css gray == #808080
 $grayLight:             #999;
 $grayLighter:           #F5F5F5;
 //$white:                   #fff
@@ -26,7 +27,6 @@ $screen-xs-min:              breakpoint-min( "sm"); // was $screen-xs;
 $screen-sm-min:              breakpoint-min( "md"); // was $screen-sm;
 $screen-md-min:              breakpoint-min( "lg"); // was $screen-md;
 $screen-lg-min:              breakpoint-min( "xl"); // was $screen-lg;
-// Large screen / wide desktop   tijdelijk bs3 type vaste breakpoints
 $screen-xl-min:              breakpoint-min( "xxl"); // was 1200px;
 //$screen-xxl-min:             breakpoint-min( "xxl"); // was 1440px;
 //$screen-xxxl-min:            1600px;
@@ -39,7 +39,6 @@ $screen-lg-max:              breakpoint-max( "xxl"); // was($screen-xl-min - 1);
 //$screen-xl-max:              ($screen-xxl-min - 1);
 //$screen-xxl-max:             ($screen-xxxl-min - 1);
 
-
 // Small screen / tablet
 $grid-gutter-width:           1.5rem !default; // from _bs5 variabels.
 
@@ -48,44 +47,6 @@ $container-sm:                 breakpoint-min( "md"); // was  $container-tablet;
 $container-md:                 breakpoint-min( "lg"); // was $container-desktop;
 //** For `$screen-lg-min` and up.
 $container-lg:                breakpoint-min( "xl"); // was $container-large-desktop;
-//$container-lg:                @include media-breakpoint-up("lg"); // was  $container-large-desktop;
-////== Navbar
-////
-////##
-//
-//// Basics of a navbar
-//// Navbar toggle
-//$navbar-default-toggle-hover-bg:           $component-active-bg; // #ddd;
-//$navbar-default-toggle-icon-bar-bg:        $navbar-light-toggler-icon-bg; // #888;
-//$navbar-default-toggle-border-color:       $navbar-light-toggler-border-color; // was #ddd;
-//
-////=== Shared nav styles
-//$nav-link-padding:                          10px 15px;
-// $nav-link-hover-bg:                         $gray-200; // $gray-lighter;
-//
-//$nav-disabled-link-color:                   $nav-link-disabled-color; // $gray-500; // $gray-light;
-//$nav-disabled-link-hover-color:             $nav-link-disabled-color; // $gray-500;  // $gray-light;
-//
-////== Tabs
-//$nav-tabs-border-color:                     #ddd;
-//
-//$nav-tabs-link-hover-border-color:          $gray-lighter;
-//
-//$nav-tabs-active-link-hover-bg:             $body-bg;
-//$nav-tabs-active-link-hover-color:          $gray;
-//$nav-tabs-active-link-hover-border-color:   #ddd;
-//
-//$nav-tabs-justified-link-border-color:            #ddd;
-//$nav-tabs-justified-active-link-border-color:     $body-bg;
-//
-////== Pills
-//$nav-pills-border-radius:                   $border-radius-base;
-//$nav-pills-active-link-hover-bg:            $component-active-bg;
-//$nav-pills-active-link-hover-color:         $component-active-color;
-//
-//// ** Disabled cursor for form controls and buttons.
-// $cursor-disabled:                not-allowed;
-//
 
 // end BS3 temporary variables
 
@@ -172,15 +133,12 @@ $wsa12Col : (100% - (13 * $wsaInnerMargin)) / 12 ;
 $span1 : $wsa12Col;
 
 
-.test01 {
-	width:$screen-xs-min;
-	height: $screen-sm-min;
-	padding-top: $screen-md-min;
-	padding-right: $screen-lg-min;
-	padding-left: $screen-xl-min;
+//.test01 {
+//	width:$screen-xs-min;
+//	height: $screen-sm-min;
+//	padding-top: $screen-md-min;
+//	padding-right: $screen-lg-min;
+//	padding-left: $screen-xl-min;
 //	padding-bottom: $screen-xxl-min    ;
-	
 
-	
-	
-}
+//}

From cee16678e821e08e2bd6fc15fbb0b4188ab434de Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Tue, 8 Oct 2024 13:13:20 +0000
Subject: [PATCH 46/82] 2.2.0

---
 scss/_template_variables.scss | 16 ++++++----------
 1 file changed, 6 insertions(+), 10 deletions(-)

diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index ff6009a..63918fc 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -31,21 +31,17 @@ $screen-xl-min:              breakpoint-min( "xxl"); // was 1200px;
 //$screen-xxl-min:             breakpoint-min( "xxl"); // was 1440px;
 //$screen-xxxl-min:            1600px;
 
-$screen-xs-max:              breakpoint-max( "md"); // was($screen-sm-min - 1);
-$screen-sm-max:              breakpoint-max( "lg"); // was($screen-md-min - 1);
-$screen-md-max:              breakpoint-max( "xl"); // was($screen-lg-min - 1);
-// So media queries don't overlap when required, provide a maximum
-$screen-lg-max:              breakpoint-max( "xxl"); // was($screen-xl-min - 1);
-//$screen-xl-max:              ($screen-xxl-min - 1);
+$screen-xs-max:              breakpoint-max( "sm"); // was($screen-sm-min - 1);
+$screen-sm-max:              breakpoint-max( "md"); // was($screen-md-min - 1);
+$screen-md-max:              breakpoint-max( "lg"); // was($screen-lg-min - 1);
+$screen-lg-max:              breakpoint-max( "xl"); // was($screen-xl-min - 1);
+$screen-xl-max:              breakpoint-max( "xxl"); // was($screen-xxl-min - 1);
 //$screen-xxl-max:             ($screen-xxxl-min - 1);
 
-// Small screen / tablet
-$grid-gutter-width:           1.5rem !default; // from _bs5 variabels.
+//$grid-gutter-width:           1.5rem !default; // from _bs5 variabels.
 
 $container-sm:                 breakpoint-min( "md"); // was  $container-tablet;
-//** For `$screen-md-min` and up.
 $container-md:                 breakpoint-min( "lg"); // was $container-desktop;
-//** For `$screen-lg-min` and up.
 $container-lg:                breakpoint-min( "xl"); // was $container-large-desktop;
 
 // end BS3 temporary variables

From 9b9e349bb71bcfa7e94f4d4969c1fbfb97ef5026 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Tue, 8 Oct 2024 14:06:20 +0000
Subject: [PATCH 47/82] 2.2.0

---
 scss/_template_dropdown.scss  | 10 +++-------
 scss/_template_variables.scss | 12 +++++-------
 2 files changed, 8 insertions(+), 14 deletions(-)

diff --git a/scss/_template_dropdown.scss b/scss/_template_dropdown.scss
index 501d46a..1f48699 100644
--- a/scss/_template_dropdown.scss
+++ b/scss/_template_dropdown.scss
@@ -211,8 +211,6 @@ color: #333;
   }
 
 }
-
-
 // uit nav.less einde 
 /* ===================================================================================
 	BOOTSTRAP MEDIA QUERIES OVERRIDES
@@ -227,7 +225,7 @@ When scaled down to less than 768px, the menu collapses and works just like the
 I only made one small addition to the standard HTML – I added a container div around the menu with a class called “sidebar-nav�.
 (In joomla kan je deze wellicht als menu-class, of module-class meegeven)
 */
-@media (min-width: $screen-sm-min) {
+@include media-breakpoint-up(md) { // min 768
   .sidebar-nav .navbar .navbar-collapse {
     padding: 0;
     max-height: none;
@@ -247,9 +245,8 @@ I only made one small addition to the standard HTML – I added a container
     padding-bottom: 12px;
   }
 }
-/* einde make sidebar nav vertical */ 
-
-@media (min-width: $screen-sm-min) { /* Activates hovering the main items to show the sub items */
+// * einde make sidebar nav vertical * / 
+@include media-breakpoint-up(md) { // min 768 Activates hovering the main items to show the sub items
        .nav-pills > li > a,
        .dropdown-menu {
           margin: 0;
@@ -329,7 +326,6 @@ I only made one small addition to the standard HTML – I added a container
 
 }
 
-
 @include media-breakpoint-up(sm)
 {  // min 576
 #img_brandImage
diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss
index 63918fc..9869779 100644
--- a/scss/_template_variables.scss
+++ b/scss/_template_variables.scss
@@ -31,15 +31,13 @@ $screen-xl-min:              breakpoint-min( "xxl"); // was 1200px;
 //$screen-xxl-min:             breakpoint-min( "xxl"); // was 1440px;
 //$screen-xxxl-min:            1600px;
 
-$screen-xs-max:              breakpoint-max( "sm"); // was($screen-sm-min - 1);
-$screen-sm-max:              breakpoint-max( "md"); // was($screen-md-min - 1);
-$screen-md-max:              breakpoint-max( "lg"); // was($screen-lg-min - 1);
-$screen-lg-max:              breakpoint-max( "xl"); // was($screen-xl-min - 1);
-$screen-xl-max:              breakpoint-max( "xxl"); // was($screen-xxl-min - 1);
+$screen-xs-max:              breakpoint-min( "md") - 0.02; // was($screen-sm-min - 1);
+$screen-sm-max:              breakpoint-min( "lg") - 0.02; // was($screen-md-min - 1);
+$screen-md-max:              breakpoint-min( "xl") - 0.02; // was($screen-lg-min - 1);
+$screen-lg-max:              breakpoint-min( "xxl") - 0.02; // was($screen-xl-min - 1);
+$screen-xl-max:              1440px - 0.02; // was($screen-xxl-min - 1);
 //$screen-xxl-max:             ($screen-xxxl-min - 1);
 
-//$grid-gutter-width:           1.5rem !default; // from _bs5 variabels.
-
 $container-sm:                 breakpoint-min( "md"); // was  $container-tablet;
 $container-md:                 breakpoint-min( "lg"); // was $container-desktop;
 $container-lg:                breakpoint-min( "xl"); // was $container-large-desktop;

From 32329c8c5e8c348f7dd8c52ba746b87e705afa04 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Tue, 8 Oct 2024 14:36:18 +0000
Subject: [PATCH 48/82] 2.2.0

---
 scss/_template_css.scss | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/scss/_template_css.scss b/scss/_template_css.scss
index ee218c0..31143b8 100644
--- a/scss/_template_css.scss
+++ b/scss/_template_css.scss
@@ -231,6 +231,7 @@ order: -1;
 /* rss fotos of flickr  met suffix _rssfoto */
 /* rss flickr images (ul li p a img) */
 [class*="rssfoto"] .newsfeed {
+	@include make-container();
 	margin: 0;
 	padding: 0;
 	width: auto;
@@ -255,12 +256,22 @@ order: -1;
 		text-align: left;
 		}
 
-	ol, ul
+	ol, ul, .com-newsfeeds-newsfeed__items, .com-newsfeeds-newsfeed__feed-image
 		{
+		@include make-row();
 		padding:0;
 		}
 	li
 		{
+			@include make-col-ready();
+
+			@include media-breakpoint-up(sm) {
+			  @include make-col(6);
+			}
+			@include media-breakpoint-up(lg) {
+			  @include make-col(4);
+			}
+
 		list-style-type: none;
 		margin-left: 0;
 		margin-right: 10px;

From 8ebda634f6fdd2f088d76638fd0012b2c9d55d8a Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Tue, 8 Oct 2024 18:40:02 +0000
Subject: [PATCH 49/82] 2.2.0

---
 scss/_template_css.scss | 15 ++-------------
 1 file changed, 2 insertions(+), 13 deletions(-)

diff --git a/scss/_template_css.scss b/scss/_template_css.scss
index 31143b8..b0741fc 100644
--- a/scss/_template_css.scss
+++ b/scss/_template_css.scss
@@ -255,7 +255,7 @@ order: -1;
 		margin-bottom: 0px;
 		text-align: left;
 		}
-
+/* new test */
 	ol, ul, .com-newsfeeds-newsfeed__items, .com-newsfeeds-newsfeed__feed-image
 		{
 		@include make-row();
@@ -394,8 +394,6 @@ div.mod-languages {
 }
 
 
-
-
 h1, h2, h3, h4, h5, h6 {
 	font-family: 'Open Sans Condensed',sans-serif;
 	font-weight: 700;
@@ -408,7 +406,7 @@ h1 {
 
 h2 {
   font-size: 26px;
-  line-height: 30px;
+//  line-height: 30px;
 }
 
 h3 {
@@ -431,15 +429,6 @@ h6 {
   line-height: 20px;
 }
 
-/* overige aanpassingen pagination tbv bootstrap 3 */
-    ul.pagination-list li a [class*="icon-"] {
-    }
-     
-    ul.pagination-list li a:hover [class*="icon-"] {
-    }
-/* einde overige aanpassingen pagination tbv bootstrap 3 */
-
-
 [class^="icon-"], [class*=" icon-"] {
     display: inline-block;
     width: 14px;

From 0f831a3575186d982d59c1a1dde86f3392359cc5 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Tue, 8 Oct 2024 18:53:11 +0000
Subject: [PATCH 50/82] 2.2.0

---
 scss/_template_css.scss | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/scss/_template_css.scss b/scss/_template_css.scss
index b0741fc..9f6eaa9 100644
--- a/scss/_template_css.scss
+++ b/scss/_template_css.scss
@@ -273,12 +273,12 @@ order: -1;
 			}
 
 		list-style-type: none;
-		margin-left: 0;
-		margin-right: 10px;
-		margin-bottom: 10px;
-		display: inline-block;
-		height: 320px; /* vaste hoogte (en breedte) voor mooier ordenen */
-		width: 250px;
+//		margin-left: 0;
+//		margin-right: 10px;
+//		margin-bottom: 10px;
+//		display: inline-block;
+//		height: 320px; /* vaste hoogte (en breedte) voor mooier ordenen */
+//		width: 250px;
 		overflow: hidden;
 		
 		a img

From 92badd592fb4a05d1f4463e026a77162a455ae15 Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Wed, 9 Oct 2024 09:21:39 +0000
Subject: [PATCH 51/82] 2.2.0 small changes rssfoto

---
 scss/_template_css.scss | 21 ++++-----------------
 1 file changed, 4 insertions(+), 17 deletions(-)

diff --git a/scss/_template_css.scss b/scss/_template_css.scss
index 9f6eaa9..ff2f5b0 100644
--- a/scss/_template_css.scss
+++ b/scss/_template_css.scss
@@ -273,22 +273,18 @@ order: -1;
 			}
 
 		list-style-type: none;
-//		margin-left: 0;
-//		margin-right: 10px;
-//		margin-bottom: 10px;
-//		display: inline-block;
-//		height: 320px; /* vaste hoogte (en breedte) voor mooier ordenen */
-//		width: 250px;
 		overflow: hidden;
 		
 		a img
 			{
 			background-color: rgba(255,255,255,0.75);
-			padding:4px;
+			padding:5px;
 			border: 1px solid rgba(0,0,0,0.3); 
 		    border-radius: 5px;
-		    box-shadow:	0 0 8px 4px rgba(0,0,0,0.2);
+		    box-shadow:	0 0 10px 5px rgba(0,0,0,0.2);
 		    margin: 5px;
+			max-width: 100%;
+			height: auto;
 			}
 
 			div.feed-item-description p:first-child
@@ -305,15 +301,6 @@ order: -1;
 		}
 	
 } /* end rssfoto newsfeed  */
-/* exceptions for rssfoto01 */
-[class*="rssfoto01"] div.newsfeed li{
-	background-color: lightgray;
-
-	a img
-		{
-		padding:5px;
-		}
-} /* end exceptions for rssfoto01 */
 
 .tag-category fieldset
 { /* tot joomla het zoekveld goed verbergt */

From 1ab1ac5887a2720b360f21576eb30fa573a2771d Mon Sep 17 00:00:00 2001
From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com>
Date: Wed, 9 Oct 2024 09:23:09 +0000
Subject: [PATCH 52/82] 2.2.0 delete node_modules and _variables.scss

---
 scss/_variables.scss                          |  871 -------------
 scss/node_modules/bootstrap/scss/_code.scss   |   48 -
 .../bootstrap/scss/_functions.scss            |   86 --
 scss/node_modules/bootstrap/scss/_grid.scss   |   52 -
 scss/node_modules/bootstrap/scss/_images.scss |   42 -
 scss/node_modules/bootstrap/scss/_mixins.scss |   43 -
 .../bootstrap/scss/_mixins.scss.4.2.1.org     |   41 -
 scss/node_modules/bootstrap/scss/_reboot.scss |  462 -------
 scss/node_modules/bootstrap/scss/_type.scss   |  125 --
 .../bootstrap/scss/_variables.scss            | 1093 -----------------
 .../bootstrap/scss/_variables.scss.4.2.1.org  | 1091 ----------------
 .../bootstrap/scss/mixins/_alert.scss         |   13 -
 .../scss/mixins/_background-variant.scss      |   21 -
 .../bootstrap/scss/mixins/_badge.scss         |   11 -
 .../bootstrap/scss/mixins/_border-radius.scss |   35 -
 .../bootstrap/scss/mixins/_box-shadow.scss    |    5 -
 .../bootstrap/scss/mixins/_breakpoints.scss   |  123 --
 .../bootstrap/scss/mixins/_buttons.scss       |  111 --
 .../bootstrap/scss/mixins/_caret.scss         |   62 -
 .../bootstrap/scss/mixins/_clearfix.scss      |    7 -
 .../bootstrap/scss/mixins/_float.scss         |   11 -
 .../bootstrap/scss/mixins/_forms.scss         |  198 ---
 .../bootstrap/scss/mixins/_gradients.scss     |   45 -
 .../scss/mixins/_grid-framework.scss          |   66 -
 .../bootstrap/scss/mixins/_grid.scss          |   51 -
 .../bootstrap/scss/mixins/_hover.scss         |   37 -
 .../bootstrap/scss/mixins/_image.scss         |   36 -
 .../bootstrap/scss/mixins/_list-group.scss    |   21 -
 .../bootstrap/scss/mixins/_lists.scss         |    7 -
 .../bootstrap/scss/mixins/_nav-divider.scss   |   10 -
 .../bootstrap/scss/mixins/_pagination.scss    |   22 -
 .../bootstrap/scss/mixins/_reset-text.scss    |   17 -
 .../bootstrap/scss/mixins/_resize.scss        |    6 -
 .../bootstrap/scss/mixins/_screen-reader.scss |   33 -
 .../bootstrap/scss/mixins/_size.scss          |    6 -
 .../bootstrap/scss/mixins/_table-row.scss     |   39 -
 .../bootstrap/scss/mixins/_text-emphasis.scss |   14 -
 .../bootstrap/scss/mixins/_text-hide.scss     |   13 -
 .../bootstrap/scss/mixins/_text-truncate.scss |    8 -
 .../bootstrap/scss/mixins/_transition.scss    |   16 -
 .../bootstrap/scss/mixins/_visibility.scss    |    7 -
 .../bootstrap/scss/utilities/_align.scss      |    8 -
 .../bootstrap/scss/utilities/_background.scss |   19 -
 .../bootstrap/scss/utilities/_borders.scss    |   63 -
 .../bootstrap/scss/utilities/_clearfix.scss   |    3 -
 .../bootstrap/scss/utilities/_display.scss    |   38 -
 .../bootstrap/scss/utilities/_embed.scss      |   39 -
 .../bootstrap/scss/utilities/_flex.scss       |   51 -
 .../bootstrap/scss/utilities/_float.scss      |    9 -
 .../bootstrap/scss/utilities/_overflow.scss   |    5 -
 .../bootstrap/scss/utilities/_position.scss   |   32 -
 .../scss/utilities/_screenreaders.scss        |   11 -
 .../bootstrap/scss/utilities/_shadows.scss    |    6 -
 .../bootstrap/scss/utilities/_sizing.scss     |   20 -
 .../bootstrap/scss/utilities/_spacing.scss    |   73 --
 .../bootstrap/scss/utilities/_text.scss       |   67 -
 .../bootstrap/scss/utilities/_visibility.scss |   11 -
 57 files changed, 5460 deletions(-)
 delete mode 100644 scss/_variables.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/_code.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/_functions.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/_grid.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/_images.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/_mixins.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/_mixins.scss.4.2.1.org
 delete mode 100644 scss/node_modules/bootstrap/scss/_reboot.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/_type.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/_variables.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/_variables.scss.4.2.1.org
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_alert.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_background-variant.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_badge.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_border-radius.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_box-shadow.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_breakpoints.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_buttons.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_caret.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_clearfix.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_float.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_forms.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_gradients.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_grid-framework.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_grid.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_hover.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_image.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_list-group.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_lists.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_nav-divider.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_pagination.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_reset-text.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_resize.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_screen-reader.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_size.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_table-row.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_text-emphasis.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_text-hide.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_text-truncate.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_transition.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/mixins/_visibility.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_align.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_background.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_borders.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_clearfix.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_display.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_embed.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_flex.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_float.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_overflow.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_position.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_screenreaders.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_shadows.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_sizing.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_spacing.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_text.scss
 delete mode 100644 scss/node_modules/bootstrap/scss/utilities/_visibility.scss

diff --git a/scss/_variables.scss b/scss/_variables.scss
deleted file mode 100644
index 9f4733d..0000000
--- a/scss/_variables.scss
+++ /dev/null
@@ -1,871 +0,0 @@
-/* variables.scss */
-// versie v3.3.6 gedownload van http://getbootstrap.com/getting-started/
-// 
-// Variables
-// --------------------------------------------------
-
-
-//== Colors
-//
-//## Gray and brand colors for use across Bootstrap.
-
-$gray-base:              #000;
-$gray-darker:            lighten($gray-base, 13.5%); // #222
-$gray-dark:              lighten($gray-base, 20%);   // #333
-$gray:                   lighten($gray-base, 33.5%); // #555
-$gray-light:             lighten($gray-base, 46.7%); // #777
-$gray-lighter:           lighten($gray-base, 93.5%); // #eee
-
-$brand-primary:         darken(#428bca, 6.5%); // #337ab7
-$brand-success:         #5cb85c;
-$brand-info:            #5bc0de;
-$brand-warning:         #f0ad4e;
-$brand-danger:          #d9534f;
-
-
-//== Scaffolding
-//
-//## Settings for some of the most global styles.
-
-//** Background color for ``.
-$body-bg:               #fff;
-//** Global text color on ``.
-$text-color:            $gray-dark;
-
-//** Global textual link color.
-$link-color:            $brand-primary;
-//** Link hover color set via `darken()` function.
-$link-hover-color:      darken($link-color, 15%);
-//** Link hover decoration.
-$link-hover-decoration: underline;
-
-
-//== Typography
-//
-//## Font, line-height, and color for body text, headings, and more.
-
-$font-family-sans-serif:  "Helvetica Neue", Helvetica, Arial, sans-serif;
-$font-family-serif:       Georgia, "Times New Roman", Times, serif;
-//** Default monospace fonts for ``, ``, and `
`.
-$font-family-monospace:   Menlo, Monaco, Consolas, "Courier New", monospace;
-$font-family-base:        $font-family-sans-serif;
-
-$font-size-base:          14px;
-$font-size-large:         ceil(($font-size-base * 1.25)); // ~18px
-$font-size-small:         ceil(($font-size-base * 0.85)); // ~12px
-
-$font-size-h1:            floor(($font-size-base * 2.6)); // ~36px
-$font-size-h2:            floor(($font-size-base * 2.15)); // ~30px
-$font-size-h3:            ceil(($font-size-base * 1.7)); // ~24px
-$font-size-h4:            ceil(($font-size-base * 1.25)); // ~18px
-$font-size-h5:            $font-size-base;
-$font-size-h6:            ceil(($font-size-base * 0.85)); // ~12px
-
-//** Unit-less `line-height` for use in components like buttons.
-$line-height-base:        1.428571429; // 20/14
-//** Computed "line-height" (`font-size` * `line-height`) for use with `margin`, `padding`, etc.
-$line-height-computed:    floor(($font-size-base * $line-height-base)); // ~20px
-
-//** By default, this inherits from the ``.
-$headings-font-family:    inherit;
-$headings-font-weight:    500;
-$headings-line-height:    1.1;
-$headings-color:          inherit;
-
-
-//== Iconography
-//
-//## Specify custom location and filename of the included Glyphicons icon font. Useful for those including Bootstrap via Bower.
-
-//** Load fonts from this directory.
-$icon-font-path:          "../fonts/";
-//** File name for all font files.
-$icon-font-name:          "glyphicons-halflings-regular";
-//** Element ID within SVG icon file.
-$icon-font-svg-id:        "glyphicons_halflingsregular";
-
-
-//== Components
-//
-//## Define common padding and border radius sizes and more. Values based on 14px text and 1.428 line-height (~20px to start).
-
-$padding-base-vertical:     6px;
-$padding-base-horizontal:   12px;
-
-$padding-large-vertical:    10px;
-$padding-large-horizontal:  16px;
-
-$padding-small-vertical:    5px;
-$padding-small-horizontal:  10px;
-
-$padding-xs-vertical:       1px;
-$padding-xs-horizontal:     5px;
-
-$line-height-large:         1.3333333; // extra decimals for Win 8.1 Chrome
-$line-height-small:         1.5;
-
-$border-radius-base:        4px;
-$border-radius-large:       6px;
-$border-radius-small:       3px;
-
-//** Global color for active items (e.g., navs or dropdowns).
-$component-active-color:    #fff;
-//** Global background color for active items (e.g., navs or dropdowns).
-$component-active-bg:       $brand-primary;
-
-//** Width of the `border` for generating carets that indicator dropdowns.
-$caret-width-base:          4px;
-//** Carets increase slightly in size for larger components.
-$caret-width-large:         5px;
-
-
-//== Tables
-//
-//## Customizes the `.table` component with basic values, each used across all table variations.
-
-//** Padding for ``s and ``s.
-$table-cell-padding:            8px;
-//** Padding for cells in `.table-condensed`.
-$table-condensed-cell-padding:  5px;
-
-//** Default background color used for all tables.
-$table-bg:                      transparent;
-//** Background color used for `.table-striped`.
-$table-bg-accent:               #f9f9f9;
-//** Background color used for `.table-hover`.
-$table-bg-hover:                #f5f5f5;
-$table-bg-active:               $table-bg-hover;
-
-//** Border color for table and cell borders.
-$table-border-color:            #ddd;
-
-
-//== Buttons
-//
-//## For each of Bootstrap's buttons, define text, background and border color.
-
-$btn-font-weight:                normal;
-
-$btn-default-color:              #333;
-$btn-default-bg:                 #fff;
-$btn-default-border:             #ccc;
-
-$btn-primary-color:              #fff;
-$btn-primary-bg:                 $brand-primary;
-$btn-primary-border:             darken($btn-primary-bg, 5%);
-
-$btn-success-color:              #fff;
-$btn-success-bg:                 $brand-success;
-$btn-success-border:             darken($btn-success-bg, 5%);
-
-$btn-info-color:                 #fff;
-$btn-info-bg:                    $brand-info;
-$btn-info-border:                darken($btn-info-bg, 5%);
-
-$btn-warning-color:              #fff;
-$btn-warning-bg:                 $brand-warning;
-$btn-warning-border:             darken($btn-warning-bg, 5%);
-
-$btn-danger-color:               #fff;
-$btn-danger-bg:                  $brand-danger;
-$btn-danger-border:              darken($btn-danger-bg, 5%);
-
-$btn-link-disabled-color:        $gray-light;
-
-// Allows for customizing button radius independently from global border radius
-$btn-border-radius-base:         $border-radius-base;
-$btn-border-radius-large:        $border-radius-large;
-$btn-border-radius-small:        $border-radius-small;
-
-
-//== Forms
-//
-//##
-
-//** `` background color
-$input-bg:                       #fff;
-//** `` background color
-$input-bg-disabled:              $gray-lighter;
-
-//** Text color for ``s
-$input-color:                    $gray;
-//** `` border color
-$input-border:                   #ccc;
-
-// TODO: Rename `$input-border-radius` to `$input-border-radius-base` in v4
-//** Default `.form-control` border radius
-// This has no effect on ``s in CSS.
-$input-border-radius:            $border-radius-base;
-//** Large `.form-control` border radius
-$input-border-radius-large:      $border-radius-large;
-//** Small `.form-control` border radius
-$input-border-radius-small:      $border-radius-small;
-
-//** Border color for inputs on focus
-$input-border-focus:             #66afe9;
-
-//** Placeholder text color
-$input-color-placeholder:        #999;
-
-//** Default `.form-control` height
-$input-height-base:              ($line-height-computed + ($padding-base-vertical * 2) + 2);
-//** Large `.form-control` height
-$input-height-large:             (ceil($font-size-large * $line-height-large) + ($padding-large-vertical * 2) + 2);
-//** Small `.form-control` height
-$input-height-small:             (floor($font-size-small * $line-height-small) + ($padding-small-vertical * 2) + 2);
-
-//** `.form-group` margin
-$form-group-margin-bottom:       15px;
-
-$legend-color:                   $gray-dark;
-$legend-border-color:            #e5e5e5;
-
-//** Background color for textual input addons
-$input-group-addon-bg:           $gray-lighter;
-//** Border color for textual input addons
-$input-group-addon-border-color: $input-border;
-
-//** Disabled cursor for form controls and buttons.
-$cursor-disabled:                not-allowed;
-
-
-//== Dropdowns
-//
-//## Dropdown menu container and contents.
-
-//** Background for the dropdown menu.
-$dropdown-bg:                    #fff;
-//** Dropdown menu `border-color`.
-$dropdown-border:                rgba(0,0,0,.15);
-//** Dropdown menu `border-color` **for IE8**.
-$dropdown-fallback-border:       #ccc;
-//** Divider color for between dropdown items.
-$dropdown-divider-bg:            #e5e5e5;
-
-//** Dropdown link text color.
-$dropdown-link-color:            $gray-dark;
-//** Hover color for dropdown links.
-$dropdown-link-hover-color:      darken($gray-dark, 5%);
-//** Hover background for dropdown links.
-$dropdown-link-hover-bg:         #f5f5f5;
-
-//** Active dropdown menu item text color.
-$dropdown-link-active-color:     $component-active-color;
-//** Active dropdown menu item background color.
-$dropdown-link-active-bg:        $component-active-bg;
-
-//** Disabled dropdown menu item background color.
-$dropdown-link-disabled-color:   $gray-light;
-
-//** Text color for headers within dropdown menus.
-$dropdown-header-color:          $gray-light;
-
-//** Deprecated `$dropdown-caret-color` as of v3.1.0
-$dropdown-caret-color:           #000;
-
-
-//-- Z-index master list
-//
-// Warning: Avoid customizing these values. They're used for a bird's eye view
-// of components dependent on the z-axis and are designed to all work together.
-//
-// Note: These variables are not generated into the Customizer.
-
-$zindex-navbar:            1000;
-$zindex-dropdown:          1000;
-$zindex-popover:           1060;
-$zindex-tooltip:           1070;
-$zindex-navbar-fixed:      1030;
-$zindex-modal-background:  1040;
-$zindex-modal:             1050;
-
-
-//== Media queries breakpoints
-//
-//## Define the breakpoints at which your layout will change, adapting to different screen sizes.
-
-// Extra small screen / phone
-//** Deprecated `$screen-xs` as of v3.0.1
-$screen-xs:                  480px;
-//** Deprecated `$screen-xs-min` as of v3.2.0
-$screen-xs-min:              $screen-xs;
-//** Deprecated `$screen-phone` as of v3.0.1
-$screen-phone:               $screen-xs-min;
-
-// Small screen / tablet
-//** Deprecated `$screen-sm` as of v3.0.1
-$screen-sm:                  768px;
-$screen-sm-min:              $screen-sm;
-//** Deprecated `$screen-tablet` as of v3.0.1
-$screen-tablet:              $screen-sm-min;
-
-// Medium screen / desktop
-//** Deprecated `$screen-md` as of v3.0.1
-$screen-md:                  992px;
-$screen-md-min:              $screen-md;
-//** Deprecated `$screen-desktop` as of v3.0.1
-$screen-desktop:             $screen-md-min;
-
-// Large screen / wide desktop
-//** Deprecated `$screen-lg` as of v3.0.1
-$screen-lg:                  1200px;
-$screen-lg-min:              $screen-lg;
-//** Deprecated `$screen-lg-desktop` as of v3.0.1
-$screen-lg-desktop:          $screen-lg-min;
-
-// So media queries don't overlap when required, provide a maximum
-$screen-xs-max:              ($screen-sm-min - 1);
-$screen-sm-max:              ($screen-md-min - 1);
-$screen-md-max:              ($screen-lg-min - 1);
-
-
-//== Grid system
-//
-//## Define your custom responsive grid.
-
-//** Number of columns in the grid.
-$grid-columns:              12;
-//** Padding between columns. Gets divided in half for the left and right.
-$grid-gutter-width:         30px;
-// Navbar collapse
-//** Point at which the navbar becomes uncollapsed.
-$grid-float-breakpoint:     $screen-sm-min;
-//** Point at which the navbar begins collapsing.
-$grid-float-breakpoint-max: ($grid-float-breakpoint - 1);
-
-
-//== Container sizes
-//
-//## Define the maximum width of `.container` for different screen sizes.
-
-// Small screen / tablet
-$container-tablet:             (720px + $grid-gutter-width);
-//** For `$screen-sm-min` and up.
-$container-sm:                 $container-tablet;
-
-// Medium screen / desktop
-$container-desktop:            (940px + $grid-gutter-width);
-//** For `$screen-md-min` and up.
-$container-md:                 $container-desktop;
-
-// Large screen / wide desktop
-$container-large-desktop:      (1140px + $grid-gutter-width);
-//** For `$screen-lg-min` and up.
-$container-lg:                 $container-large-desktop;
-
-
-//== Navbar
-//
-//##
-
-// Basics of a navbar
-$navbar-height:                    50px;
-$navbar-margin-bottom:             $line-height-computed;
-$navbar-border-radius:             $border-radius-base;
-$navbar-padding-horizontal:        floor(($grid-gutter-width / 2));
-$navbar-padding-vertical:          (($navbar-height - $line-height-computed) / 2);
-$navbar-collapse-max-height:       340px;
-
-$navbar-default-color:             #777;
-$navbar-default-bg:                #f8f8f8;
-$navbar-default-border:            darken($navbar-default-bg, 6.5%);
-
-// Navbar links
-$navbar-default-link-color:                #777;
-$navbar-default-link-hover-color:          #333;
-$navbar-default-link-hover-bg:             transparent;
-$navbar-default-link-active-color:         #555;
-$navbar-default-link-active-bg:            darken($navbar-default-bg, 6.5%);
-$navbar-default-link-disabled-color:       #ccc;
-$navbar-default-link-disabled-bg:          transparent;
-
-// Navbar brand label
-$navbar-default-brand-color:               $navbar-default-link-color;
-$navbar-default-brand-hover-color:         darken($navbar-default-brand-color, 10%);
-$navbar-default-brand-hover-bg:            transparent;
-
-// Navbar toggle
-$navbar-default-toggle-hover-bg:           #ddd;
-$navbar-default-toggle-icon-bar-bg:        #888;
-$navbar-default-toggle-border-color:       #ddd;
-
-
-//=== Inverted navbar
-// Reset inverted navbar basics
-$navbar-inverse-color:                      lighten($gray-light, 15%);
-$navbar-inverse-bg:                         #222;
-$navbar-inverse-border:                     darken($navbar-inverse-bg, 10%);
-
-// Inverted navbar links
-$navbar-inverse-link-color:                 lighten($gray-light, 15%);
-$navbar-inverse-link-hover-color:           #fff;
-$navbar-inverse-link-hover-bg:              transparent;
-$navbar-inverse-link-active-color:          $navbar-inverse-link-hover-color;
-$navbar-inverse-link-active-bg:             darken($navbar-inverse-bg, 10%);
-$navbar-inverse-link-disabled-color:        #444;
-$navbar-inverse-link-disabled-bg:           transparent;
-
-// Inverted navbar brand label
-$navbar-inverse-brand-color:                $navbar-inverse-link-color;
-$navbar-inverse-brand-hover-color:          #fff;
-$navbar-inverse-brand-hover-bg:             transparent;
-
-// Inverted navbar toggle
-$navbar-inverse-toggle-hover-bg:            #333;
-$navbar-inverse-toggle-icon-bar-bg:         #fff;
-$navbar-inverse-toggle-border-color:        #333;
-
-
-//== Navs
-//
-//##
-
-//=== Shared nav styles
-$nav-link-padding:                          10px 15px;
-$nav-link-hover-bg:                         $gray-lighter;
-
-$nav-disabled-link-color:                   $gray-light;
-$nav-disabled-link-hover-color:             $gray-light;
-
-//== Tabs
-$nav-tabs-border-color:                     #ddd;
-
-$nav-tabs-link-hover-border-color:          $gray-lighter;
-
-$nav-tabs-active-link-hover-bg:             $body-bg;
-$nav-tabs-active-link-hover-color:          $gray;
-$nav-tabs-active-link-hover-border-color:   #ddd;
-
-$nav-tabs-justified-link-border-color:            #ddd;
-$nav-tabs-justified-active-link-border-color:     $body-bg;
-
-//== Pills
-$nav-pills-border-radius:                   $border-radius-base;
-$nav-pills-active-link-hover-bg:            $component-active-bg;
-$nav-pills-active-link-hover-color:         $component-active-color;
-
-
-//== Pagination
-//
-//##
-
-$pagination-color:                     $link-color;
-$pagination-bg:                        #fff;
-$pagination-border:                    #ddd;
-
-$pagination-hover-color:               $link-hover-color;
-$pagination-hover-bg:                  $gray-lighter;
-$pagination-hover-border:              #ddd;
-
-$pagination-active-color:              #fff;
-$pagination-active-bg:                 $brand-primary;
-$pagination-active-border:             $brand-primary;
-
-$pagination-disabled-color:            $gray-light;
-$pagination-disabled-bg:               #fff;
-$pagination-disabled-border:           #ddd;
-
-
-//== Pager
-//
-//##
-
-$pager-bg:                             $pagination-bg;
-$pager-border:                         $pagination-border;
-$pager-border-radius:                  15px;
-
-$pager-hover-bg:                       $pagination-hover-bg;
-
-$pager-active-bg:                      $pagination-active-bg;
-$pager-active-color:                   $pagination-active-color;
-
-$pager-disabled-color:                 $pagination-disabled-color;
-
-
-//== Jumbotron
-//
-//##
-
-$jumbotron-padding:              30px;
-$jumbotron-color:                inherit;
-$jumbotron-bg:                   $gray-lighter;
-$jumbotron-heading-color:        inherit;
-$jumbotron-font-size:            ceil(($font-size-base * 1.5));
-$jumbotron-heading-font-size:    ceil(($font-size-base * 4.5));
-
-
-//== Form states and alerts
-//
-//## Define colors for form feedback states and, by default, alerts.
-
-$state-success-text:             #3c763d;
-$state-success-bg:               #dff0d8;
-$state-success-border:           darken(adjust-hue($state-success-bg, -10), 5%);
-
-$state-info-text:                #31708f;
-$state-info-bg:                  #d9edf7;
-$state-info-border:              darken(adjust-hue($state-info-bg, -10), 7%);
-
-$state-warning-text:             #8a6d3b;
-$state-warning-bg:               #fcf8e3;
-$state-warning-border:           darken(adjust-hue($state-warning-bg, -10), 5%);
-
-$state-danger-text:              #a94442;
-$state-danger-bg:                #f2dede;
-$state-danger-border:            darken(adjust-hue($state-danger-bg, -10), 5%);
-
-
-//== Tooltips
-//
-//##
-
-//** Tooltip max width
-$tooltip-max-width:           200px;
-//** Tooltip text color
-$tooltip-color:               #fff;
-//** Tooltip background color
-$tooltip-bg:                  #000;
-$tooltip-opacity:             .9;
-
-//** Tooltip arrow width
-$tooltip-arrow-width:         5px;
-//** Tooltip arrow color
-$tooltip-arrow-color:         $tooltip-bg;
-
-
-//== Popovers
-//
-//##
-
-//** Popover body background color
-$popover-bg:                          #fff;
-//** Popover maximum width
-$popover-max-width:                   276px;
-//** Popover border color
-$popover-border-color:                rgba(0,0,0,.2);
-//** Popover fallback border color
-$popover-fallback-border-color:       #ccc;
-
-//** Popover title background color
-$popover-title-bg:                    darken($popover-bg, 3%);
-
-//** Popover arrow width
-$popover-arrow-width:                 10px;
-//** Popover arrow color
-$popover-arrow-color:                 $popover-bg;
-
-//** Popover outer arrow width
-$popover-arrow-outer-width:           ($popover-arrow-width + 1);
-//** Popover outer arrow color
-$popover-arrow-outer-color:           fadein($popover-border-color, 0.05);
-//** Popover outer arrow fallback color
-$popover-arrow-outer-fallback-color:  darken($popover-fallback-border-color, 0.20);
-
-
-//== Labels
-//
-//##
-
-//** Default label background color
-$label-default-bg:            $gray-light;
-//** Primary label background color
-$label-primary-bg:            $brand-primary;
-//** Success label background color
-$label-success-bg:            $brand-success;
-//** Info label background color
-$label-info-bg:               $brand-info;
-//** Warning label background color
-$label-warning-bg:            $brand-warning;
-//** Danger label background color
-$label-danger-bg:             $brand-danger;
-
-//** Default label text color
-$label-color:                 #fff;
-//** Default text color of a linked label
-$label-link-hover-color:      #fff;
-
-
-//== Modals
-//
-//##
-
-//** Padding applied to the modal body
-$modal-inner-padding:         15px;
-
-//** Padding applied to the modal title
-$modal-title-padding:         15px;
-//** Modal title line-height
-$modal-title-line-height:     $line-height-base;
-
-//** Background color of modal content area
-$modal-content-bg:                             #fff;
-//** Modal content border color
-$modal-content-border-color:                   rgba(0,0,0,.2);
-//** Modal content border color **for IE8**
-$modal-content-fallback-border-color:          #999;
-
-//** Modal backdrop background color
-$modal-backdrop-bg:           #000;
-//** Modal backdrop opacity
-$modal-backdrop-opacity:      .5;
-//** Modal header border color
-$modal-header-border-color:   #e5e5e5;
-//** Modal footer border color
-$modal-footer-border-color:   $modal-header-border-color;
-
-$modal-lg:                    900px;
-$modal-md:                    600px;
-$modal-sm:                    300px;
-
-
-//== Alerts
-//
-//## Define alert colors, border radius, and padding.
-
-$alert-padding:               15px;
-$alert-border-radius:         $border-radius-base;
-$alert-link-font-weight:      bold;
-
-$alert-success-bg:            $state-success-bg;
-$alert-success-text:          $state-success-text;
-$alert-success-border:        $state-success-border;
-
-$alert-info-bg:               $state-info-bg;
-$alert-info-text:             $state-info-text;
-$alert-info-border:           $state-info-border;
-
-$alert-warning-bg:            $state-warning-bg;
-$alert-warning-text:          $state-warning-text;
-$alert-warning-border:        $state-warning-border;
-
-$alert-danger-bg:             $state-danger-bg;
-$alert-danger-text:           $state-danger-text;
-$alert-danger-border:         $state-danger-border;
-
-
-//== Progress bars
-//
-//##
-
-//** Background color of the whole progress component
-$progress-bg:                 #f5f5f5;
-//** Progress bar text color
-$progress-bar-color:          #fff;
-//** Variable for setting rounded corners on progress bar.
-$progress-border-radius:      $border-radius-base;
-
-//** Default progress bar color
-$progress-bar-bg:             $brand-primary;
-//** Success progress bar color
-$progress-bar-success-bg:     $brand-success;
-//** Warning progress bar color
-$progress-bar-warning-bg:     $brand-warning;
-//** Danger progress bar color
-$progress-bar-danger-bg:      $brand-danger;
-//** Info progress bar color
-$progress-bar-info-bg:        $brand-info;
-
-
-//== List group
-//
-//##
-
-//** Background color on `.list-group-item`
-$list-group-bg:                 #fff;
-//** `.list-group-item` border color
-$list-group-border:             #ddd;
-//** List group border radius
-$list-group-border-radius:      $border-radius-base;
-
-//** Background color of single list items on hover
-$list-group-hover-bg:           #f5f5f5;
-//** Text color of active list items
-$list-group-active-color:       $component-active-color;
-//** Background color of active list items
-$list-group-active-bg:          $component-active-bg;
-//** Border color of active list elements
-$list-group-active-border:      $list-group-active-bg;
-//** Text color for content within active list items
-$list-group-active-text-color:  lighten($list-group-active-bg, 40%);
-
-//** Text color of disabled list items
-$list-group-disabled-color:      $gray-light;
-//** Background color of disabled list items
-$list-group-disabled-bg:         $gray-lighter;
-//** Text color for content within disabled list items
-$list-group-disabled-text-color: $list-group-disabled-color;
-
-$list-group-link-color:         #555;
-$list-group-link-hover-color:   $list-group-link-color;
-$list-group-link-heading-color: #333;
-
-
-//== Panels
-//
-//##
-
-$panel-bg:                    #fff;
-$panel-body-padding:          15px;
-$panel-heading-padding:       10px 15px;
-$panel-footer-padding:        $panel-heading-padding;
-$panel-border-radius:         $border-radius-base;
-
-//** Border color for elements within panels
-$panel-inner-border:          #ddd;
-$panel-footer-bg:             #f5f5f5;
-
-$panel-default-text:          $gray-dark;
-$panel-default-border:        #ddd;
-$panel-default-heading-bg:    #f5f5f5;
-
-$panel-primary-text:          #fff;
-$panel-primary-border:        $brand-primary;
-$panel-primary-heading-bg:    $brand-primary;
-
-$panel-success-text:          $state-success-text;
-$panel-success-border:        $state-success-border;
-$panel-success-heading-bg:    $state-success-bg;
-
-$panel-info-text:             $state-info-text;
-$panel-info-border:           $state-info-border;
-$panel-info-heading-bg:       $state-info-bg;
-
-$panel-warning-text:          $state-warning-text;
-$panel-warning-border:        $state-warning-border;
-$panel-warning-heading-bg:    $state-warning-bg;
-
-$panel-danger-text:           $state-danger-text;
-$panel-danger-border:         $state-danger-border;
-$panel-danger-heading-bg:     $state-danger-bg;
-
-
-//== Thumbnails
-//
-//##
-
-//** Padding around the thumbnail image
-$thumbnail-padding:           4px;
-//** Thumbnail background color
-$thumbnail-bg:                $body-bg;
-//** Thumbnail border color
-$thumbnail-border:            #ddd;
-//** Thumbnail border radius
-$thumbnail-border-radius:     $border-radius-base;
-
-//** Custom text color for thumbnail captions
-$thumbnail-caption-color:     $text-color;
-//** Padding around the thumbnail caption
-$thumbnail-caption-padding:   9px;
-
-
-//== Wells
-//
-//##
-
-$well-bg:                     #f5f5f5;
-$well-border:                 darken($well-bg, 7%);
-
-
-//== Badges
-//
-//##
-
-$badge-color:                 #fff;
-//** Linked badge text color on hover
-$badge-link-hover-color:      #fff;
-$badge-bg:                    $gray-light;
-
-//** Badge text color in active nav link
-$badge-active-color:          $link-color;
-//** Badge background color in active nav link
-$badge-active-bg:             #fff;
-
-$badge-font-weight:           bold;
-$badge-line-height:           1;
-$badge-border-radius:         10px;
-
-
-//== Breadcrumbs
-//
-//##
-
-$breadcrumb-padding-vertical:   8px;
-$breadcrumb-padding-horizontal: 15px;
-//** Breadcrumb background color
-$breadcrumb-bg:                 #f5f5f5;
-//** Breadcrumb text color
-$breadcrumb-color:              #ccc;
-//** Text color of current page in the breadcrumb
-$breadcrumb-active-color:       $gray-light;
-//** Textual separator for between breadcrumb elements
-$breadcrumb-separator:          "/";
-
-
-//== Carousel
-//
-//##
-
-$carousel-text-shadow:                        0 1px 2px rgba(0,0,0,.6);
-
-$carousel-control-color:                      #fff;
-$carousel-control-width:                      15%;
-$carousel-control-opacity:                    .5;
-$carousel-control-font-size:                  20px;
-
-$carousel-indicator-active-bg:                #fff;
-$carousel-indicator-border-color:             #fff;
-
-$carousel-caption-color:                      #fff;
-
-
-//== Close
-//
-//##
-
-$close-font-weight:           bold;
-$close-color:                 #000;
-$close-text-shadow:           0 1px 0 #fff;
-
-
-//== Code
-//
-//##
-
-$code-color:                  #c7254e;
-$code-bg:                     #f9f2f4;
-
-$kbd-color:                   #fff;
-$kbd-bg:                      #333;
-
-$pre-bg:                      #f5f5f5;
-$pre-color:                   $gray-dark;
-$pre-border-color:            #ccc;
-$pre-scrollable-max-height:   340px;
-
-
-//== Type
-//
-//##
-
-//** Horizontal offset for forms and lists.
-$component-offset-horizontal: 180px;
-//** Text muted color
-$text-muted:                  $gray-light;
-//** Abbreviations and acronyms border color
-$abbr-border-color:           $gray-light;
-//** Headings small color
-$headings-small-color:        $gray-light;
-//** Blockquote small color
-$blockquote-small-color:      $gray-light;
-//** Blockquote font size
-$blockquote-font-size:        ($font-size-base * 1.25);
-//** Blockquote border color
-$blockquote-border-color:     $gray-lighter;
-//** Page header border color
-$page-header-border-color:    $gray-lighter;
-//** Width of horizontal description list titles
-$dl-horizontal-offset:        $component-offset-horizontal;
-//** Point at which .dl-horizontal becomes horizontal
-$dl-horizontal-breakpoint:    $grid-float-breakpoint;
-//** Horizontal line color.
-$hr-border:                   $gray-lighter;
diff --git a/scss/node_modules/bootstrap/scss/_code.scss b/scss/node_modules/bootstrap/scss/_code.scss
deleted file mode 100644
index 9b2e027..0000000
--- a/scss/node_modules/bootstrap/scss/_code.scss
+++ /dev/null
@@ -1,48 +0,0 @@
-// Inline code
-code {
-  font-size: $code-font-size;
-  color: $code-color;
-  word-break: break-word;
-
-  // Streamline the style when inside anchors to avoid broken underline and more
-  a > & {
-    color: inherit;
-  }
-}
-
-// User input typically entered via keyboard
-kbd {
-  padding: $kbd-padding-y $kbd-padding-x;
-  font-size: $kbd-font-size;
-  color: $kbd-color;
-  background-color: $kbd-bg;
-  @include border-radius($border-radius-sm);
-  @include box-shadow($kbd-box-shadow);
-
-  kbd {
-    padding: 0;
-    font-size: 100%;
-    font-weight: $nested-kbd-font-weight;
-    @include box-shadow(none);
-  }
-}
-
-// Blocks of code
-pre {
-  display: block;
-  font-size: $code-font-size;
-  color: $pre-color;
-
-  // Account for some code outputs that place code tags in pre tags
-  code {
-    font-size: inherit;
-    color: inherit;
-    word-break: normal;
-  }
-}
-
-// Enable scrollable blocks of code
-.pre-scrollable {
-  max-height: $pre-scrollable-max-height;
-  overflow-y: scroll;
-}
diff --git a/scss/node_modules/bootstrap/scss/_functions.scss b/scss/node_modules/bootstrap/scss/_functions.scss
deleted file mode 100644
index 77b8c8f..0000000
--- a/scss/node_modules/bootstrap/scss/_functions.scss
+++ /dev/null
@@ -1,86 +0,0 @@
-// Bootstrap functions
-//
-// Utility mixins and functions for evaluating source code across our variables, maps, and mixins.
-
-// Ascending
-// Used to evaluate Sass maps like our grid breakpoints.
-@mixin _assert-ascending($map, $map-name) {
-  $prev-key: null;
-  $prev-num: null;
-  @each $key, $num in $map {
-    @if $prev-num == null or unit($num) == "%" {
-      // Do nothing
-    } @else if not comparable($prev-num, $num) {
-      @warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !";
-    } @else if $prev-num >= $num {
-      @warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !";
-    }
-    $prev-key: $key;
-    $prev-num: $num;
-  }
-}
-
-// Starts at zero
-// Another grid mixin that ensures the min-width of the lowest breakpoint starts at 0.
-@mixin _assert-starts-at-zero($map) {
-  $values: map-values($map);
-  $first-value: nth($values, 1);
-  @if $first-value != 0 {
-    @warn "First breakpoint in `$grid-breakpoints` must start at 0, but starts at #{$first-value}.";
-  }
-}
-
-// Replace `$search` with `$replace` in `$string`
-// Used on our SVG icon backgrounds for custom forms.
-//
-// @author Hugo Giraudel
-// @param {String} $string - Initial string
-// @param {String} $search - Substring to replace
-// @param {String} $replace ('') - New value
-// @return {String} - Updated string
-@function str-replace($string, $search, $replace: "") {
-  $index: str-index($string, $search);
-
-  @if $index {
-    @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
-  }
-
-  @return $string;
-}
-
-// Color contrast
-@function color-yiq($color, $dark: $yiq-text-dark, $light: $yiq-text-light) {
-  $r: red($color);
-  $g: green($color);
-  $b: blue($color);
-
-  $yiq: (($r * 299) + ($g * 587) + ($b * 114)) / 1000;
-
-  @if ($yiq >= $yiq-contrasted-threshold) {
-    @return $dark;
-  } @else {
-    @return $light;
-  }
-}
-
-// Retrieve color Sass maps
-@function color($key: "blue") {
-  @return map-get($colors, $key);
-}
-
-@function theme-color($key: "primary") {
-  @return map-get($theme-colors, $key);
-}
-
-@function gray($key: "100") {
-  @return map-get($grays, $key);
-}
-
-// Request a theme color level
-@function theme-color-level($color-name: "primary", $level: 0) {
-  $color: theme-color($color-name);
-  $color-base: if($level > 0, $black, $white);
-  $level: abs($level);
-
-  @return mix($color-base, $color, $level * $theme-color-interval);
-}
diff --git a/scss/node_modules/bootstrap/scss/_grid.scss b/scss/node_modules/bootstrap/scss/_grid.scss
deleted file mode 100644
index a227515..0000000
--- a/scss/node_modules/bootstrap/scss/_grid.scss
+++ /dev/null
@@ -1,52 +0,0 @@
-// Container widths
-//
-// Set the container width, and override it for fixed navbars in media queries.
-
-@if $enable-grid-classes {
-  .container {
-    @include make-container();
-    @include make-container-max-widths();
-  }
-}
-
-// Fluid container
-//
-// Utilizes the mixin meant for fixed width containers, but with 100% width for
-// fluid, full width layouts.
-
-@if $enable-grid-classes {
-  .container-fluid {
-    @include make-container();
-  }
-}
-
-// Row
-//
-// Rows contain and clear the floats of your columns.
-
-@if $enable-grid-classes {
-  .row {
-    @include make-row();
-  }
-
-  // Remove the negative margin from default .row, then the horizontal padding
-  // from all immediate children columns (to prevent runaway style inheritance).
-  .no-gutters {
-    margin-right: 0;
-    margin-left: 0;
-
-    > .col,
-    > [class*="col-"] {
-      padding-right: 0;
-      padding-left: 0;
-    }
-  }
-}
-
-// Columns
-//
-// Common styles for small and large grid columns
-
-@if $enable-grid-classes {
-  @include make-grid-columns();
-}
diff --git a/scss/node_modules/bootstrap/scss/_images.scss b/scss/node_modules/bootstrap/scss/_images.scss
deleted file mode 100644
index 8e69b77..0000000
--- a/scss/node_modules/bootstrap/scss/_images.scss
+++ /dev/null
@@ -1,42 +0,0 @@
-// Responsive images (ensure images don't scale beyond their parents)
-//
-// This is purposefully opt-in via an explicit class rather than being the default for all ``s.
-// We previously tried the "images are responsive by default" approach in Bootstrap v2,
-// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
-// which weren't expecting the images within themselves to be involuntarily resized.
-// See also https://github.com/twbs/bootstrap/issues/18178
-.img-fluid {
-  @include img-fluid;
-}
-
-
-// Image thumbnails
-.img-thumbnail {
-  padding: $thumbnail-padding;
-  background-color: $thumbnail-bg;
-  border: $thumbnail-border-width solid $thumbnail-border-color;
-  @include border-radius($thumbnail-border-radius);
-  @include box-shadow($thumbnail-box-shadow);
-
-  // Keep them at most 100% wide
-  @include img-fluid;
-}
-
-//
-// Figures
-//
-
-.figure {
-  // Ensures the caption's text aligns with the image.
-  display: inline-block;
-}
-
-.figure-img {
-  margin-bottom: $spacer / 2;
-  line-height: 1;
-}
-
-.figure-caption {
-  font-size: $figure-caption-font-size;
-  color: $figure-caption-color;
-}
diff --git a/scss/node_modules/bootstrap/scss/_mixins.scss b/scss/node_modules/bootstrap/scss/_mixins.scss
deleted file mode 100644
index 991a7de..0000000
--- a/scss/node_modules/bootstrap/scss/_mixins.scss
+++ /dev/null
@@ -1,43 +0,0 @@
-// Toggles
-//
-// Used in conjunction with global variables to enable certain theme features.
-// 20190125 badge 4.2.1 verwijderd vanwege  incompatibilliteit met leafo/scssphp (github #616 #614)
-// badge 4.1 is waarschijnlijk wel compatibel
-// maar zolang er geen noodzaak voor override van bootstrap.css mbt badges is gewoon uitschakelen.
-// Utilities
-@import "mixins/breakpoints";
-@import "mixins/hover";
-@import "mixins/image";
-//@import "mixins/badge";
-@import "mixins/resize";
-@import "mixins/screen-reader";
-@import "mixins/size";
-@import "mixins/reset-text";
-@import "mixins/text-emphasis";
-@import "mixins/text-hide";
-@import "mixins/text-truncate";
-@import "mixins/visibility";
-
-// // Components
-@import "mixins/alert";
-@import "mixins/buttons";
-@import "mixins/caret";
-@import "mixins/pagination";
-@import "mixins/lists";
-@import "mixins/list-group";
-@import "mixins/nav-divider";
-@import "mixins/forms";
-@import "mixins/table-row";
-
-// // Skins
-@import "mixins/background-variant";
-@import "mixins/border-radius";
-@import "mixins/box-shadow";
-@import "mixins/gradients";
-@import "mixins/transition";
-
-// // Layout
-@import "mixins/clearfix";
-@import "mixins/grid-framework";
-@import "mixins/grid";
-@import "mixins/float";
diff --git a/scss/node_modules/bootstrap/scss/_mixins.scss.4.2.1.org b/scss/node_modules/bootstrap/scss/_mixins.scss.4.2.1.org
deleted file mode 100644
index 8710166..0000000
--- a/scss/node_modules/bootstrap/scss/_mixins.scss.4.2.1.org
+++ /dev/null
@@ -1,41 +0,0 @@
-// Toggles
-//
-// Used in conjunction with global variables to enable certain theme features.
-
-// Utilities
-@import "mixins/breakpoints";
-@import "mixins/hover";
-@import "mixins/image";
-@import "mixins/badge";
-@import "mixins/resize";
-@import "mixins/screen-reader";
-@import "mixins/size";
-@import "mixins/reset-text";
-@import "mixins/text-emphasis";
-@import "mixins/text-hide";
-@import "mixins/text-truncate";
-@import "mixins/visibility";
-
-// // Components
-@import "mixins/alert";
-@import "mixins/buttons";
-@import "mixins/caret";
-@import "mixins/pagination";
-@import "mixins/lists";
-@import "mixins/list-group";
-@import "mixins/nav-divider";
-@import "mixins/forms";
-@import "mixins/table-row";
-
-// // Skins
-@import "mixins/background-variant";
-@import "mixins/border-radius";
-@import "mixins/box-shadow";
-@import "mixins/gradients";
-@import "mixins/transition";
-
-// // Layout
-@import "mixins/clearfix";
-@import "mixins/grid-framework";
-@import "mixins/grid";
-@import "mixins/float";
diff --git a/scss/node_modules/bootstrap/scss/_reboot.scss b/scss/node_modules/bootstrap/scss/_reboot.scss
deleted file mode 100644
index d4167cc..0000000
--- a/scss/node_modules/bootstrap/scss/_reboot.scss
+++ /dev/null
@@ -1,462 +0,0 @@
-// stylelint-disable at-rule-no-vendor-prefix, declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix
-
-// Reboot
-//
-// Normalization of HTML elements, manually forked from Normalize.css to remove
-// styles targeting irrelevant browsers while applying new styles.
-//
-// Normalize is licensed MIT. https://github.com/necolas/normalize.css
-
-
-// Document
-//
-// 1. Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.
-// 2. Change the default font family in all browsers.
-// 3. Correct the line height in all browsers.
-// 4. Prevent adjustments of font size after orientation changes in IE on Windows Phone and in iOS.
-// 5. Change the default tap highlight to be completely transparent in iOS.
-
-*,
-*::before,
-*::after {
-  box-sizing: border-box; // 1
-}
-
-html {
-  font-family: sans-serif; // 2
-  line-height: 1.15; // 3
-  -webkit-text-size-adjust: 100%; // 4
-  -webkit-tap-highlight-color: rgba($black, 0); // 5
-}
-
-// Shim for "new" HTML5 structural elements to display correctly (IE10, older browsers)
-// TODO: remove in v5
-// stylelint-disable-next-line selector-list-comma-newline-after
-article, aside, figcaption, figure, footer, header, hgroup, main, nav, section {
-  display: block;
-}
-
-// Body
-//
-// 1. Remove the margin in all browsers.
-// 2. As a best practice, apply a default `background-color`.
-// 3. Set an explicit initial text-align value so that we can later use
-//    the `inherit` value on things like `` elements.
-
-body {
-  margin: 0; // 1
-  font-family: $font-family-base;
-  font-size: $font-size-base;
-  font-weight: $font-weight-base;
-  line-height: $line-height-base;
-  color: $body-color;
-  text-align: left; // 3
-  background-color: $body-bg; // 2
-}
-
-// Suppress the focus outline on elements that cannot be accessed via keyboard.
-// This prevents an unwanted focus outline from appearing around elements that
-// might still respond to pointer events.
-//
-// Credit: https://github.com/suitcss/base
-[tabindex="-1"]:focus {
-  outline: 0 !important;
-}
-
-
-// Content grouping
-//
-// 1. Add the correct box sizing in Firefox.
-// 2. Show the overflow in Edge and IE.
-
-hr {
-  box-sizing: content-box; // 1
-  height: 0; // 1
-  overflow: visible; // 2
-}
-
-
-//
-// Typography
-//
-
-// Remove top margins from headings
-//
-// By default, `

`-`

` all receive top and bottom margins. We nuke the top -// margin for easier control within type scales as it avoids margin collapsing. -// stylelint-disable-next-line selector-list-comma-newline-after -h1, h2, h3, h4, h5, h6 { - margin-top: 0; - margin-bottom: $headings-margin-bottom; -} - -// Reset margins on paragraphs -// -// Similarly, the top margin on `

`s get reset. However, we also reset the -// bottom margin to use `rem` units instead of `em`. -p { - margin-top: 0; - margin-bottom: $paragraph-margin-bottom; -} - -// Abbreviations -// -// 1. Duplicate behavior to the data-* attribute for our tooltip plugin -// 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. -// 3. Add explicit cursor to indicate changed behavior. -// 4. Remove the bottom border in Firefox 39-. -// 5. Prevent the text-decoration to be skipped. - -abbr[title], -abbr[data-original-title] { // 1 - text-decoration: underline; // 2 - text-decoration: underline dotted; // 2 - cursor: help; // 3 - border-bottom: 0; // 4 - text-decoration-skip-ink: none; // 5 -} - -address { - margin-bottom: 1rem; - font-style: normal; - line-height: inherit; -} - -ol, -ul, -dl { - margin-top: 0; - margin-bottom: 1rem; -} - -ol ol, -ul ul, -ol ul, -ul ol { - margin-bottom: 0; -} - -dt { - font-weight: $dt-font-weight; -} - -dd { - margin-bottom: .5rem; - margin-left: 0; // Undo browser default -} - -blockquote { - margin: 0 0 1rem; -} - -b, -strong { - font-weight: $font-weight-bolder; // Add the correct font weight in Chrome, Edge, and Safari -} - -small { - font-size: 80%; // Add the correct font size in all browsers -} - -// -// Prevent `sub` and `sup` elements from affecting the line height in -// all browsers. -// - -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; -} - -sub { bottom: -.25em; } -sup { top: -.5em; } - - -// -// Links -// - -a { - color: $link-color; - text-decoration: $link-decoration; - background-color: transparent; // Remove the gray background on active links in IE 10. - - @include hover { - color: $link-hover-color; - text-decoration: $link-hover-decoration; - } -} - -// And undo these styles for placeholder links/named anchors (without href) -// which have not been made explicitly keyboard-focusable (without tabindex). -// It would be more straightforward to just use a[href] in previous block, but that -// causes specificity issues in many other styles that are too complex to fix. -// See https://github.com/twbs/bootstrap/issues/19402 - -a:not([href]):not([tabindex]) { - color: inherit; - text-decoration: none; - - @include hover-focus { - color: inherit; - text-decoration: none; - } - - &:focus { - outline: 0; - } -} - - -// -// Code -// - -pre, -code, -kbd, -samp { - font-family: $font-family-monospace; - font-size: 1em; // Correct the odd `em` font sizing in all browsers. -} - -pre { - // Remove browser default top margin - margin-top: 0; - // Reset browser default of `1em` to use `rem`s - margin-bottom: 1rem; - // Don't allow content to break outside - overflow: auto; -} - - -// -// Figures -// - -figure { - // Apply a consistent margin strategy (matches our type styles). - margin: 0 0 1rem; -} - - -// -// Images and content -// - -img { - vertical-align: middle; - border-style: none; // Remove the border on images inside links in IE 10-. -} - -svg { - // Workaround for the SVG overflow bug in IE10/11 is still required. - // See https://github.com/twbs/bootstrap/issues/26878 - overflow: hidden; - vertical-align: middle; -} - - -// -// Tables -// - -table { - border-collapse: collapse; // Prevent double borders -} - -caption { - padding-top: $table-cell-padding; - padding-bottom: $table-cell-padding; - color: $table-caption-color; - text-align: left; - caption-side: bottom; -} - -th { - // Matches default `` alignment by inheriting from the ``, or the - // closest parent with a set `text-align`. - text-align: inherit; -} - - -// -// Forms -// - -label { - // Allow labels to use `margin` for spacing. - display: inline-block; - margin-bottom: $label-margin-bottom; -} - -// Remove the default `border-radius` that macOS Chrome adds. -// -// Details at https://github.com/twbs/bootstrap/issues/24093 -button { - border-radius: 0; -} - -// Work around a Firefox/IE bug where the transparent `button` background -// results in a loss of the default `button` focus styles. -// -// Credit: https://github.com/suitcss/base/ -button:focus { - outline: 1px dotted; - outline: 5px auto -webkit-focus-ring-color; -} - -input, -button, -select, -optgroup, -textarea { - margin: 0; // Remove the margin in Firefox and Safari - font-family: inherit; - font-size: inherit; - line-height: inherit; -} - -button, -input { - overflow: visible; // Show the overflow in Edge -} - -button, -select { - text-transform: none; // Remove the inheritance of text transform in Firefox -} - -// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` -// controls in Android 4. -// 2. Correct the inability to style clickable types in iOS and Safari. -button, -[type="button"], // 1 -[type="reset"], -[type="submit"] { - -webkit-appearance: button; // 2 -} - -// Remove inner border and padding from Firefox, but don't restore the outline like Normalize. -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - padding: 0; - border-style: none; -} - -input[type="radio"], -input[type="checkbox"] { - box-sizing: border-box; // 1. Add the correct box sizing in IE 10- - padding: 0; // 2. Remove the padding in IE 10- -} - - -input[type="date"], -input[type="time"], -input[type="datetime-local"], -input[type="month"] { - // Remove the default appearance of temporal inputs to avoid a Mobile Safari - // bug where setting a custom line-height prevents text from being vertically - // centered within the input. - // See https://bugs.webkit.org/show_bug.cgi?id=139848 - // and https://github.com/twbs/bootstrap/issues/11266 - -webkit-appearance: listbox; -} - -textarea { - overflow: auto; // Remove the default vertical scrollbar in IE. - // Textareas should really only resize vertically so they don't break their (horizontal) containers. - resize: vertical; -} - -fieldset { - // Browsers set a default `min-width: min-content;` on fieldsets, - // unlike e.g. `

`s, which have `min-width: 0;` by default. - // So we reset that to ensure fieldsets behave more like a standard block element. - // See https://github.com/twbs/bootstrap/issues/12359 - // and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements - min-width: 0; - // Reset the default outline behavior of fieldsets so they don't affect page layout. - padding: 0; - margin: 0; - border: 0; -} - -// 1. Correct the text wrapping in Edge and IE. -// 2. Correct the color inheritance from `fieldset` elements in IE. -legend { - display: block; - width: 100%; - max-width: 100%; // 1 - padding: 0; - margin-bottom: .5rem; - font-size: 1.5rem; - line-height: inherit; - color: inherit; // 2 - white-space: normal; // 1 -} - -progress { - vertical-align: baseline; // Add the correct vertical alignment in Chrome, Firefox, and Opera. -} - -// Correct the cursor style of increment and decrement buttons in Chrome. -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -[type="search"] { - // This overrides the extra rounded corners on search inputs in iOS so that our - // `.form-control` class can properly style them. Note that this cannot simply - // be added to `.form-control` as it's not specific enough. For details, see - // https://github.com/twbs/bootstrap/issues/11586. - outline-offset: -2px; // 2. Correct the outline style in Safari. - -webkit-appearance: none; -} - -// -// Remove the inner padding and cancel buttons in Chrome and Safari on macOS. -// - -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -// -// 1. Correct the inability to style clickable types in iOS and Safari. -// 2. Change font properties to `inherit` in Safari. -// - -::-webkit-file-upload-button { - font: inherit; // 2 - -webkit-appearance: button; // 1 -} - -// -// Correct element displays -// - -output { - display: inline-block; -} - -summary { - display: list-item; // Add the correct display in all browsers - cursor: pointer; -} - -template { - display: none; // Add the correct display in IE -} - -// Always hide an element with the `hidden` HTML attribute (from PureCSS). -// Needed for proper display in IE 10-. -[hidden] { - display: none !important; -} diff --git a/scss/node_modules/bootstrap/scss/_type.scss b/scss/node_modules/bootstrap/scss/_type.scss deleted file mode 100644 index 37dd967..0000000 --- a/scss/node_modules/bootstrap/scss/_type.scss +++ /dev/null @@ -1,125 +0,0 @@ -// stylelint-disable declaration-no-important, selector-list-comma-newline-after - -// -// Headings -// - -h1, h2, h3, h4, h5, h6, -.h1, .h2, .h3, .h4, .h5, .h6 { - margin-bottom: $headings-margin-bottom; - font-family: $headings-font-family; - font-weight: $headings-font-weight; - line-height: $headings-line-height; - color: $headings-color; -} - -h1, .h1 { font-size: $h1-font-size; } -h2, .h2 { font-size: $h2-font-size; } -h3, .h3 { font-size: $h3-font-size; } -h4, .h4 { font-size: $h4-font-size; } -h5, .h5 { font-size: $h5-font-size; } -h6, .h6 { font-size: $h6-font-size; } - -.lead { - font-size: $lead-font-size; - font-weight: $lead-font-weight; -} - -// Type display classes -.display-1 { - font-size: $display1-size; - font-weight: $display1-weight; - line-height: $display-line-height; -} -.display-2 { - font-size: $display2-size; - font-weight: $display2-weight; - line-height: $display-line-height; -} -.display-3 { - font-size: $display3-size; - font-weight: $display3-weight; - line-height: $display-line-height; -} -.display-4 { - font-size: $display4-size; - font-weight: $display4-weight; - line-height: $display-line-height; -} - - -// -// Horizontal rules -// - -hr { - margin-top: $hr-margin-y; - margin-bottom: $hr-margin-y; - border: 0; - border-top: $hr-border-width solid $hr-border-color; -} - - -// -// Emphasis -// - -small, -.small { - font-size: $small-font-size; - font-weight: $font-weight-normal; -} - -mark, -.mark { - padding: $mark-padding; - background-color: $mark-bg; -} - - -// -// Lists -// - -.list-unstyled { - @include list-unstyled; -} - -// Inline turns list items into inline-block -.list-inline { - @include list-unstyled; -} -.list-inline-item { - display: inline-block; - - &:not(:last-child) { - margin-right: $list-inline-padding; - } -} - - -// -// Misc -// - -// Builds on `abbr` -.initialism { - font-size: 90%; - text-transform: uppercase; -} - -// Blockquotes -.blockquote { - margin-bottom: $spacer; - font-size: $blockquote-font-size; -} - -.blockquote-footer { - display: block; - font-size: $blockquote-small-font-size; - color: $blockquote-small-color; - - &::before { - content: "\2014\00A0"; // em dash, nbsp - } -} diff --git a/scss/node_modules/bootstrap/scss/_variables.scss b/scss/node_modules/bootstrap/scss/_variables.scss deleted file mode 100644 index b666639..0000000 --- a/scss/node_modules/bootstrap/scss/_variables.scss +++ /dev/null @@ -1,1093 +0,0 @@ -// Variables bs 4.2.1 -// -// Variables should follow the `$component-state-property-size` formula for -// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. -// /* 5 times calc added to resolve Incompatible units rem and px. */ - -// Color system - -$white: #fff !default; -$gray-100: #f8f9fa !default; -$gray-200: #e9ecef !default; -$gray-300: #dee2e6 !default; -$gray-400: #ced4da !default; -$gray-500: #adb5bd !default; -$gray-600: #6c757d !default; -$gray-700: #495057 !default; -$gray-800: #343a40 !default; -$gray-900: #212529 !default; -$black: #000 !default; - -$grays: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$grays: map-merge( - ( - "100": $gray-100, - "200": $gray-200, - "300": $gray-300, - "400": $gray-400, - "500": $gray-500, - "600": $gray-600, - "700": $gray-700, - "800": $gray-800, - "900": $gray-900 - ), - $grays -); - -$blue: #007bff !default; -$indigo: #6610f2 !default; -$purple: #6f42c1 !default; -$pink: #e83e8c !default; -$red: #dc3545 !default; -$orange: #fd7e14 !default; -$yellow: #ffc107 !default; -$green: #28a745 !default; -$teal: #20c997 !default; -$cyan: #17a2b8 !default; - -$colors: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$colors: map-merge( - ( - "blue": $blue, - "indigo": $indigo, - "purple": $purple, - "pink": $pink, - "red": $red, - "orange": $orange, - "yellow": $yellow, - "green": $green, - "teal": $teal, - "cyan": $cyan, - "white": $white, - "gray": $gray-600, - "gray-dark": $gray-800 - ), - $colors -); - -$primary: $blue !default; -$secondary: $gray-600 !default; -$success: $green !default; -$info: $cyan !default; -$warning: $yellow !default; -$danger: $red !default; -$light: $gray-100 !default; -$dark: $gray-800 !default; - -$theme-colors: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$theme-colors: map-merge( - ( - "primary": $primary, - "secondary": $secondary, - "success": $success, - "info": $info, - "warning": $warning, - "danger": $danger, - "light": $light, - "dark": $dark - ), - $theme-colors -); - -// Set a specific jump point for requesting color jumps -$theme-color-interval: 8% !default; - -// The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255. -$yiq-contrasted-threshold: 150 !default; - -// Customize the light and dark text colors for use in our YIQ color contrast function. -$yiq-text-dark: $gray-900 !default; -$yiq-text-light: $white !default; - - -// Options -// -// Quickly modify global styling by enabling or disabling optional features. - -$enable-caret: true !default; -$enable-rounded: true !default; -$enable-shadows: false !default; -$enable-gradients: false !default; -$enable-transitions: true !default; -$enable-prefers-reduced-motion-media-query: true !default; -$enable-hover-media-query: false !default; // Deprecated, no longer affects any compiled CSS -$enable-grid-classes: true !default; -$enable-print-styles: true !default; -$enable-validation-icons: true !default; - - -// Spacing -// -// Control the default styling of most Bootstrap elements by modifying these -// variables. Mostly focused on spacing. -// You can add more entries to the $spacers map, should you need more variation. - -$spacer: 1rem !default; -$spacers: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$spacers: map-merge( - ( - 0: 0, - 1: ($spacer * .25), - 2: ($spacer * .5), - 3: $spacer, - 4: ($spacer * 1.5), - 5: ($spacer * 3) - ), - $spacers -); - -// This variable affects the `.h-*` and `.w-*` classes. -$sizes: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$sizes: map-merge( - ( - 25: 25%, - 50: 50%, - 75: 75%, - 100: 100%, - auto: auto - ), - $sizes -); - - -// Body -// -// Settings for the `` element. - -$body-bg: $white !default; -$body-color: $gray-900 !default; - - -// Links -// -// Style anchor elements. - -$link-color: theme-color("primary") !default; -$link-decoration: none !default; -$link-hover-color: darken($link-color, 15%) !default; -$link-hover-decoration: underline !default; -// Darken percentage for links with `.text-*` class (e.g. `.text-success`) -$emphasized-link-hover-darken-percentage: 15% !default; - -// Paragraphs -// -// Style p element. - -$paragraph-margin-bottom: 1rem !default; - - -// Grid breakpoints -// -// Define the minimum dimensions at which your layout will change, -// adapting to different screen sizes, for use in media queries. - -$grid-breakpoints: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$grid-breakpoints: map-merge( - ( - xs: 0, - sm: 576px, - md: 768px, - lg: 992px, - xl: 1200px - ), - $grid-breakpoints -); - -@include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); -@include _assert-starts-at-zero($grid-breakpoints); - - -// Grid containers -// -// Define the maximum width of `.container` for different screen sizes. - -$container-max-widths: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$container-max-widths: map-merge( - ( - sm: 540px, - md: 720px, - lg: 960px, - xl: 1140px - ), - $container-max-widths -); - -@include _assert-ascending($container-max-widths, "$container-max-widths"); - - -// Grid columns -// -// Set the number of columns and specify the width of the gutters. - -$grid-columns: 12 !default; -$grid-gutter-width: 30px !default; - - -// Components -// -// Define common padding and border radius sizes and more. - -$line-height-lg: 1.5 !default; -$line-height-sm: 1.5 !default; - -$border-width: 1px !default; -$border-color: $gray-300 !default; - -$border-radius: .25rem !default; -$border-radius-lg: .3rem !default; -$border-radius-sm: .2rem !default; - -$rounded-pill: 50rem !default; - -$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default; -$box-shadow: 0 .5rem 1rem rgba($black, .15) !default; -$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default; - -$component-active-color: $white !default; -$component-active-bg: theme-color("primary") !default; - -$caret-width: .3em !default; - -$transition-base: all .2s ease-in-out !default; -$transition-fade: opacity .15s linear !default; -$transition-collapse: height .35s ease !default; - -$embed-responsive-aspect-ratios: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$embed-responsive-aspect-ratios: join( - ( - (21 9), - (16 9), - (3 4), - (1 1), - ), - $embed-responsive-aspect-ratios -); - -// Fonts -// -// Font, line-height, and color for body text, headings, and more. - -// stylelint-disable value-keyword-case -$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; -$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; -$font-family-base: $font-family-sans-serif !default; -// stylelint-enable value-keyword-case - -$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` -$font-size-lg: ($font-size-base * 1.25) !default; -$font-size-sm: ($font-size-base * .875) !default; - -$font-weight-lighter: lighter !default; -$font-weight-light: 300 !default; -$font-weight-normal: 400 !default; -$font-weight-bold: 700 !default; -$font-weight-bolder: bolder !default; - -$font-weight-base: $font-weight-normal !default; -$line-height-base: 1.5 !default; - -$h1-font-size: $font-size-base * 2.5 !default; -$h2-font-size: $font-size-base * 2 !default; -$h3-font-size: $font-size-base * 1.75 !default; -$h4-font-size: $font-size-base * 1.5 !default; -$h5-font-size: $font-size-base * 1.25 !default; -$h6-font-size: $font-size-base !default; - -$headings-margin-bottom: $spacer / 2 !default; -$headings-font-family: inherit !default; -$headings-font-weight: 500 !default; -$headings-line-height: 1.2 !default; -$headings-color: inherit !default; - -$display1-size: 6rem !default; -$display2-size: 5.5rem !default; -$display3-size: 4.5rem !default; -$display4-size: 3.5rem !default; - -$display1-weight: 300 !default; -$display2-weight: 300 !default; -$display3-weight: 300 !default; -$display4-weight: 300 !default; -$display-line-height: $headings-line-height !default; - -$lead-font-size: ($font-size-base * 1.25) !default; -$lead-font-weight: 300 !default; - -$small-font-size: 80% !default; - -$text-muted: $gray-600 !default; - -$blockquote-small-color: $gray-600 !default; -$blockquote-small-font-size: $small-font-size !default; -$blockquote-font-size: ($font-size-base * 1.25) !default; - -$hr-border-color: rgba($black, .1) !default; -$hr-border-width: $border-width !default; - -$mark-padding: .2em !default; - -$dt-font-weight: $font-weight-bold !default; - -$kbd-box-shadow: inset 0 -.1rem 0 rgba($black, .25) !default; -$nested-kbd-font-weight: $font-weight-bold !default; - -$list-inline-padding: .5rem !default; - -$mark-bg: #fcf8e3 !default; - -$hr-margin-y: $spacer !default; - - -// Tables -// -// Customizes the `.table` component with basic values, each used across all table variations. - -$table-cell-padding: .75rem !default; -$table-cell-padding-sm: .3rem !default; - -$table-bg: transparent !default; -$table-accent-bg: rgba($black, .05) !default; -$table-hover-bg: rgba($black, .075) !default; -$table-active-bg: $table-hover-bg !default; - -$table-border-width: $border-width !default; -$table-border-color: $gray-300 !default; - -$table-head-bg: $gray-200 !default; -$table-head-color: $gray-700 !default; - -$table-dark-bg: $gray-900 !default; -$table-dark-accent-bg: rgba($white, .05) !default; -$table-dark-hover-bg: rgba($white, .075) !default; -$table-dark-border-color: lighten($gray-900, 7.5%) !default; -$table-dark-color: $white !default; - -$table-striped-order: odd !default; - -$table-caption-color: $text-muted !default; - -$table-bg-level: -9 !default; -$table-border-level: -6 !default; - - -// Buttons + Forms -// -// Shared variables that are reassigned to `$input-` and `$btn-` specific variables. - -$input-btn-padding-y: .375rem !default; -$input-btn-padding-x: .75rem !default; -$input-btn-font-size: $font-size-base !default; -$input-btn-line-height: $line-height-base !default; - -$input-btn-focus-width: .2rem !default; -$input-btn-focus-color: rgba($component-active-bg, .25) !default; -$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default; - -$input-btn-padding-y-sm: .25rem !default; -$input-btn-padding-x-sm: .5rem !default; -$input-btn-font-size-sm: $font-size-sm !default; -$input-btn-line-height-sm: $line-height-sm !default; - -$input-btn-padding-y-lg: .5rem !default; -$input-btn-padding-x-lg: 1rem !default; -$input-btn-font-size-lg: $font-size-lg !default; -$input-btn-line-height-lg: $line-height-lg !default; - -$input-btn-border-width: $border-width !default; - - -// Buttons -// -// For each of Bootstrap's buttons, define text, background, and border color. - -$btn-padding-y: $input-btn-padding-y !default; -$btn-padding-x: $input-btn-padding-x !default; -$btn-font-size: $input-btn-font-size !default; -$btn-line-height: $input-btn-line-height !default; - -$btn-padding-y-sm: $input-btn-padding-y-sm !default; -$btn-padding-x-sm: $input-btn-padding-x-sm !default; -$btn-font-size-sm: $input-btn-font-size-sm !default; -$btn-line-height-sm: $input-btn-line-height-sm !default; - -$btn-padding-y-lg: $input-btn-padding-y-lg !default; -$btn-padding-x-lg: $input-btn-padding-x-lg !default; -$btn-font-size-lg: $input-btn-font-size-lg !default; -$btn-line-height-lg: $input-btn-line-height-lg !default; - -$btn-border-width: $input-btn-border-width !default; - -$btn-font-weight: $font-weight-normal !default; -$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default; -$btn-focus-width: $input-btn-focus-width !default; -$btn-focus-box-shadow: $input-btn-focus-box-shadow !default; -$btn-disabled-opacity: .65 !default; -$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default; - -$btn-link-disabled-color: $gray-600 !default; - -$btn-block-spacing-y: .5rem !default; - -// Allows for customizing button radius independently from global border radius -$btn-border-radius: $border-radius !default; -$btn-border-radius-lg: $border-radius-lg !default; -$btn-border-radius-sm: $border-radius-sm !default; - -$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; - - -// Forms - -$label-margin-bottom: .5rem !default; - -$input-padding-y: $input-btn-padding-y !default; -$input-padding-x: $input-btn-padding-x !default; -$input-font-size: $input-btn-font-size !default; -$input-font-weight: $font-weight-base !default; -$input-line-height: $input-btn-line-height !default; - -$input-padding-y-sm: $input-btn-padding-y-sm !default; -$input-padding-x-sm: $input-btn-padding-x-sm !default; -$input-font-size-sm: $input-btn-font-size-sm !default; -$input-line-height-sm: $input-btn-line-height-sm !default; - -$input-padding-y-lg: $input-btn-padding-y-lg !default; -$input-padding-x-lg: $input-btn-padding-x-lg !default; -$input-font-size-lg: $input-btn-font-size-lg !default; -$input-line-height-lg: $input-btn-line-height-lg !default; - -$input-bg: $white !default; -$input-disabled-bg: $gray-200 !default; - -$input-color: $gray-700 !default; -$input-border-color: $gray-400 !default; -$input-border-width: $input-btn-border-width !default; -$input-box-shadow: inset 0 1px 1px rgba($black, .075) !default; - -$input-border-radius: $border-radius !default; -$input-border-radius-lg: $border-radius-lg !default; -$input-border-radius-sm: $border-radius-sm !default; - -$input-focus-bg: $input-bg !default; -$input-focus-border-color: lighten($component-active-bg, 25%) !default; -$input-focus-color: $input-color !default; -$input-focus-width: $input-btn-focus-width !default; -$input-focus-box-shadow: $input-btn-focus-box-shadow !default; - -$input-placeholder-color: $gray-600 !default; -$input-plaintext-color: $body-color !default; - -$input-height-border: $input-border-width * 2 !default; -/* 3 times calc added to resolve Incompatible units rem and px. */ -$input-height-inner: calc(($input-btn-font-size * $input-btn-line-height) + ($input-btn-padding-y * 2)) !default; -$input-height: calc(#{$input-height-inner} + #{$input-height-border}) !default; - -$input-height-inner-sm: calc(($input-btn-font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2)) !default; -$input-height-sm: calc(#{$input-height-inner-sm} + #{$input-height-border}) !default; - -$input-height-inner-lg: calc(($input-btn-font-size-lg * $input-btn-line-height-lg) + ($input-btn-padding-y-lg * 2)) !default; -$input-height-lg: calc(#{$input-height-inner-lg} + #{$input-height-border}) !default; - -$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; - -$form-text-margin-top: .25rem !default; - -$form-check-input-gutter: 1.25rem !default; -$form-check-input-margin-y: .3rem !default; -$form-check-input-margin-x: .25rem !default; - -$form-check-inline-margin-x: .75rem !default; -$form-check-inline-input-margin-x: .3125rem !default; - -$form-grid-gutter-width: 10px !default; -$form-group-margin-bottom: 1rem !default; - -$input-group-addon-color: $input-color !default; -$input-group-addon-bg: $gray-200 !default; -$input-group-addon-border-color: $input-border-color !default; - -$custom-forms-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; - -$custom-control-gutter: .5rem !default; -$custom-control-spacer-x: 1rem !default; - -$custom-control-indicator-size: 1rem !default; -$custom-control-indicator-bg: $input-bg !default; - -$custom-control-indicator-bg-size: 50% 50% !default; -$custom-control-indicator-box-shadow: $input-box-shadow !default; -$custom-control-indicator-border-color: $gray-500 !default; -$custom-control-indicator-border-width: $input-border-width !default; - -$custom-control-indicator-disabled-bg: $input-disabled-bg !default; -$custom-control-label-disabled-color: $gray-600 !default; - -$custom-control-indicator-checked-color: $component-active-color !default; -$custom-control-indicator-checked-bg: $component-active-bg !default; -$custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), .5) !default; -$custom-control-indicator-checked-box-shadow: none !default; -$custom-control-indicator-checked-border-color: $custom-control-indicator-checked-bg !default; - -$custom-control-indicator-focus-box-shadow: $input-btn-focus-box-shadow !default; -$custom-control-indicator-focus-border-color: $input-focus-border-color !default; - -$custom-control-indicator-active-color: $component-active-color !default; -$custom-control-indicator-active-bg: lighten($component-active-bg, 35%) !default; -$custom-control-indicator-active-box-shadow: none !default; -$custom-control-indicator-active-border-color: $custom-control-indicator-active-bg !default; - -$custom-checkbox-indicator-border-radius: $border-radius !default; -$custom-checkbox-indicator-icon-checked: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='#{$custom-control-indicator-checked-color}' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e"), "#", "%23") !default; - -$custom-checkbox-indicator-indeterminate-bg: $component-active-bg !default; -$custom-checkbox-indicator-indeterminate-color: $custom-control-indicator-checked-color !default; -$custom-checkbox-indicator-icon-indeterminate: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='#{$custom-checkbox-indicator-indeterminate-color}' d='M0 2h4'/%3e%3c/svg%3e"), "#", "%23") !default; -$custom-checkbox-indicator-indeterminate-box-shadow: none !default; -$custom-checkbox-indicator-indeterminate-border-color: $custom-checkbox-indicator-indeterminate-bg !default; - -$custom-radio-indicator-border-radius: 50% !default; -$custom-radio-indicator-icon-checked: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$custom-control-indicator-checked-color}'/%3e%3c/svg%3e"), "#", "%23") !default; - -$custom-switch-width: $custom-control-indicator-size * 1.75 !default; -$custom-switch-indicator-border-radius: $custom-control-indicator-size / 2 !default; -$custom-switch-indicator-size: calc(#{$custom-control-indicator-size} - #{$custom-control-indicator-border-width * 4}) !default; - -$custom-select-padding-y: $input-btn-padding-y !default; -$custom-select-padding-x: $input-btn-padding-x !default; -$custom-select-height: $input-height !default; -$custom-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator -$custom-select-font-weight: $input-font-weight !default; -$custom-select-line-height: $input-line-height !default; -$custom-select-color: $input-color !default; -$custom-select-disabled-color: $gray-600 !default; -$custom-select-bg: $input-bg !default; -$custom-select-disabled-bg: $gray-200 !default; -$custom-select-bg-size: 8px 10px !default; // In pixels because image dimensions -$custom-select-indicator-color: $gray-800 !default; -$custom-select-indicator: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e"), "#", "%23") !default; -$custom-select-background: $custom-select-indicator no-repeat right $custom-select-padding-x center / $custom-select-bg-size !default; // Used so we can have multiple background elements (e.g., arrow and feedback icon) - -$custom-select-feedback-icon-padding-right: $input-height-inner * 3 / 4 + $custom-select-padding-x + $custom-select-indicator-padding !default; -$custom-select-feedback-icon-position: center right ($custom-select-padding-x + $custom-select-indicator-padding) !default; -$custom-select-feedback-icon-size: ($input-height-inner / 2) ($input-height-inner / 2) !default; - -$custom-select-border-width: $input-border-width !default; -$custom-select-border-color: $input-border-color !default; -$custom-select-border-radius: $border-radius !default; -$custom-select-box-shadow: inset 0 1px 2px rgba($black, .075) !default; - -$custom-select-focus-border-color: $input-focus-border-color !default; -$custom-select-focus-width: $input-focus-width !default; -$custom-select-focus-box-shadow: 0 0 0 $custom-select-focus-width rgba($custom-select-focus-border-color, .5) !default; - -$custom-select-padding-y-sm: $input-padding-y-sm !default; -$custom-select-padding-x-sm: $input-padding-x-sm !default; -$custom-select-font-size-sm: $input-btn-font-size-sm !default; -$custom-select-height-sm: $input-height-sm !default; - -$custom-select-padding-y-lg: $input-padding-y-lg !default; -$custom-select-padding-x-lg: $input-padding-x-lg !default; -$custom-select-font-size-lg: $input-btn-font-size-lg !default; -$custom-select-height-lg: $input-height-lg !default; - -$custom-range-track-width: 100% !default; -$custom-range-track-height: .5rem !default; -$custom-range-track-cursor: pointer !default; -$custom-range-track-bg: $gray-300 !default; -$custom-range-track-border-radius: 1rem !default; -$custom-range-track-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default; - -$custom-range-thumb-width: 1rem !default; -$custom-range-thumb-height: $custom-range-thumb-width !default; -$custom-range-thumb-bg: $component-active-bg !default; -$custom-range-thumb-border: 0 !default; -$custom-range-thumb-border-radius: 1rem !default; -$custom-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default; -$custom-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default; -$custom-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in IE/Edge -$custom-range-thumb-active-bg: lighten($component-active-bg, 35%) !default; -$custom-range-thumb-disabled-bg: $gray-500 !default; - -$custom-file-height: $input-height !default; -$custom-file-height-inner: $input-height-inner !default; -$custom-file-focus-border-color: $input-focus-border-color !default; -$custom-file-focus-box-shadow: $input-focus-box-shadow !default; -$custom-file-disabled-bg: $input-disabled-bg !default; - -$custom-file-padding-y: $input-padding-y !default; -$custom-file-padding-x: $input-padding-x !default; -$custom-file-line-height: $input-line-height !default; -$custom-file-font-weight: $input-font-weight !default; -$custom-file-color: $input-color !default; -$custom-file-bg: $input-bg !default; -$custom-file-border-width: $input-border-width !default; -$custom-file-border-color: $input-border-color !default; -$custom-file-border-radius: $input-border-radius !default; -$custom-file-box-shadow: $input-box-shadow !default; -$custom-file-button-color: $custom-file-color !default; -$custom-file-button-bg: $input-group-addon-bg !default; -$custom-file-text: ( - en: "Browse" -) !default; - - -// Form validation - -$form-feedback-margin-top: $form-text-margin-top !default; -$form-feedback-font-size: $small-font-size !default; -$form-feedback-valid-color: theme-color("success") !default; -$form-feedback-invalid-color: theme-color("danger") !default; - -$form-feedback-icon-valid-color: $form-feedback-valid-color !default; -$form-feedback-icon-valid: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"), "#", "%23") !default; -$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default; -$form-feedback-icon-invalid: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$form-feedback-icon-invalid-color}' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E"), "#", "%23") !default; - - -// Dropdowns -// -// Dropdown menu container and contents. - -$dropdown-min-width: 10rem !default; -$dropdown-padding-y: .5rem !default; -$dropdown-spacer: .125rem !default; -$dropdown-bg: $white !default; -$dropdown-border-color: rgba($black, .15) !default; -$dropdown-border-radius: $border-radius !default; -$dropdown-border-width: $border-width !default; -$dropdown-inner-border-radius: calc(#{$dropdown-border-radius} - #{$dropdown-border-width}) !default; -$dropdown-divider-bg: $gray-200 !default; -$dropdown-box-shadow: 0 .5rem 1rem rgba($black, .175) !default; - -$dropdown-link-color: $gray-900 !default; -$dropdown-link-hover-color: darken($gray-900, 5%) !default; -$dropdown-link-hover-bg: $gray-100 !default; - -$dropdown-link-active-color: $component-active-color !default; -$dropdown-link-active-bg: $component-active-bg !default; - -$dropdown-link-disabled-color: $gray-600 !default; - -$dropdown-item-padding-y: .25rem !default; -$dropdown-item-padding-x: 1.5rem !default; - -$dropdown-header-color: $gray-600 !default; - - -// Z-index master list -// -// Warning: Avoid customizing these values. They're used for a bird's eye view -// of components dependent on the z-axis and are designed to all work together. - -$zindex-dropdown: 1000 !default; -$zindex-sticky: 1020 !default; -$zindex-fixed: 1030 !default; -$zindex-modal-backdrop: 1040 !default; -$zindex-modal: 1050 !default; -$zindex-popover: 1060 !default; -$zindex-tooltip: 1070 !default; - - -// Navs - -$nav-link-padding-y: .5rem !default; -$nav-link-padding-x: 1rem !default; -$nav-link-disabled-color: $gray-600 !default; - -$nav-tabs-border-color: $gray-300 !default; -$nav-tabs-border-width: $border-width !default; -$nav-tabs-border-radius: $border-radius !default; -$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default; -$nav-tabs-link-active-color: $gray-700 !default; -$nav-tabs-link-active-bg: $body-bg !default; -$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default; - -$nav-pills-border-radius: $border-radius !default; -$nav-pills-link-active-color: $component-active-color !default; -$nav-pills-link-active-bg: $component-active-bg !default; - -$nav-divider-color: $gray-200 !default; -$nav-divider-margin-y: $spacer / 2 !default; - - -// Navbar - -$navbar-padding-y: $spacer / 2 !default; -$navbar-padding-x: $spacer !default; - -$navbar-nav-link-padding-x: .5rem !default; - -$navbar-brand-font-size: $font-size-lg !default; -// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link -/* 2 times calc added to resolve Incompatible units rem and px. */ -$nav-link-height: calc($font-size-base * $line-height-base + $nav-link-padding-y * 2) !default; -$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; -$navbar-brand-padding-y: calc(($nav-link-height - $navbar-brand-height) / 2) !default; - -$navbar-toggler-padding-y: .25rem !default; -$navbar-toggler-padding-x: .75rem !default; -$navbar-toggler-font-size: $font-size-lg !default; -$navbar-toggler-border-radius: $btn-border-radius !default; - -$navbar-dark-color: rgba($white, .5) !default; -$navbar-dark-hover-color: rgba($white, .75) !default; -$navbar-dark-active-color: $white !default; -$navbar-dark-disabled-color: rgba($white, .25) !default; -$navbar-dark-toggler-icon-bg: str-replace(url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"), "#", "%23") !default; -$navbar-dark-toggler-border-color: rgba($white, .1) !default; - -$navbar-light-color: rgba($black, .5) !default; -$navbar-light-hover-color: rgba($black, .7) !default; -$navbar-light-active-color: rgba($black, .9) !default; -$navbar-light-disabled-color: rgba($black, .3) !default; -$navbar-light-toggler-icon-bg: str-replace(url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"), "#", "%23") !default; -$navbar-light-toggler-border-color: rgba($black, .1) !default; - -$navbar-light-brand-color: $navbar-light-active-color !default; -$navbar-light-brand-hover-color: $navbar-light-active-color !default; -$navbar-dark-brand-color: $navbar-dark-active-color !default; -$navbar-dark-brand-hover-color: $navbar-dark-active-color !default; - - -// Pagination - -$pagination-padding-y: .5rem !default; -$pagination-padding-x: .75rem !default; -$pagination-padding-y-sm: .25rem !default; -$pagination-padding-x-sm: .5rem !default; -$pagination-padding-y-lg: .75rem !default; -$pagination-padding-x-lg: 1.5rem !default; -$pagination-line-height: 1.25 !default; - -$pagination-color: $link-color !default; -$pagination-bg: $white !default; -$pagination-border-width: $border-width !default; -$pagination-border-color: $gray-300 !default; - -$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default; -$pagination-focus-outline: 0 !default; - -$pagination-hover-color: $link-hover-color !default; -$pagination-hover-bg: $gray-200 !default; -$pagination-hover-border-color: $gray-300 !default; - -$pagination-active-color: $component-active-color !default; -$pagination-active-bg: $component-active-bg !default; -$pagination-active-border-color: $pagination-active-bg !default; - -$pagination-disabled-color: $gray-600 !default; -$pagination-disabled-bg: $white !default; -$pagination-disabled-border-color: $gray-300 !default; - - -// Jumbotron - -$jumbotron-padding: 2rem !default; -$jumbotron-bg: $gray-200 !default; - - -// Cards - -$card-spacer-y: .75rem !default; -$card-spacer-x: 1.25rem !default; -$card-border-width: $border-width !default; -$card-border-radius: $border-radius !default; -$card-border-color: rgba($black, .125) !default; -$card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}) !default; -$card-cap-bg: rgba($black, .03) !default; -$card-cap-color: inherit !default; -$card-bg: $white !default; - -$card-img-overlay-padding: 1.25rem !default; - -$card-group-margin: $grid-gutter-width / 2 !default; -$card-deck-margin: $card-group-margin !default; - -$card-columns-count: 3 !default; -$card-columns-gap: 1.25rem !default; -$card-columns-margin: $card-spacer-y !default; - - -// Tooltips - -$tooltip-font-size: $font-size-sm !default; -$tooltip-max-width: 200px !default; -$tooltip-color: $white !default; -$tooltip-bg: $black !default; -$tooltip-border-radius: $border-radius !default; -$tooltip-opacity: .9 !default; -$tooltip-padding-y: .25rem !default; -$tooltip-padding-x: .5rem !default; -$tooltip-margin: 0 !default; - -$tooltip-arrow-width: .8rem !default; -$tooltip-arrow-height: .4rem !default; -$tooltip-arrow-color: $tooltip-bg !default; - -// Form tooltips must come after regular tooltips -$form-feedback-tooltip-padding-y: $tooltip-padding-y !default; -$form-feedback-tooltip-padding-x: $tooltip-padding-x !default; -$form-feedback-tooltip-font-size: $tooltip-font-size !default; -$form-feedback-tooltip-line-height: $line-height-base !default; -$form-feedback-tooltip-opacity: $tooltip-opacity !default; -$form-feedback-tooltip-border-radius: $tooltip-border-radius !default; - - -// Popovers - -$popover-font-size: $font-size-sm !default; -$popover-bg: $white !default; -$popover-max-width: 276px !default; -$popover-border-width: $border-width !default; -$popover-border-color: rgba($black, .2) !default; -$popover-border-radius: $border-radius-lg !default; -$popover-box-shadow: 0 .25rem .5rem rgba($black, .2) !default; - -$popover-header-bg: darken($popover-bg, 3%) !default; -$popover-header-color: $headings-color !default; -$popover-header-padding-y: .5rem !default; -$popover-header-padding-x: .75rem !default; - -$popover-body-color: $body-color !default; -$popover-body-padding-y: $popover-header-padding-y !default; -$popover-body-padding-x: $popover-header-padding-x !default; - -$popover-arrow-width: 1rem !default; -$popover-arrow-height: .5rem !default; -$popover-arrow-color: $popover-bg !default; - -$popover-arrow-outer-color: fade-in($popover-border-color, .05) !default; - - -// Toasts -$toast-max-width: 350px !default; -$toast-padding-x: .75rem !default; -$toast-padding-y: .25rem !default; -$toast-font-size: .875rem !default; -$toast-background-color: rgba($white, .85) !default; -$toast-border-width: 1px !default; -$toast-border-color: rgba(0, 0, 0, .1) !default; -$toast-border-radius: .25rem !default; -$toast-box-shadow: 0 .25rem .75rem rgba($black, .1) !default; - -$toast-header-color: $gray-600 !default; -$toast-header-background-color: rgba($white, .85) !default; -$toast-header-border-color: rgba(0, 0, 0, .05) !default; - - -// Badges - -$badge-font-size: 75% !default; -$badge-font-weight: $font-weight-bold !default; -$badge-padding-y: .25em !default; -$badge-padding-x: .4em !default; -$badge-border-radius: $border-radius !default; - -$badge-pill-padding-x: .6em !default; -// Use a higher than normal value to ensure completely rounded edges when -// customizing padding or font-size on labels. -$badge-pill-border-radius: 10rem !default; - - -// Modals - -// Padding applied to the modal body -$modal-inner-padding: 1rem !default; - -$modal-dialog-margin: .5rem !default; -$modal-dialog-margin-y-sm-up: 1.75rem !default; - -$modal-title-line-height: $line-height-base !default; - -$modal-content-bg: $white !default; -$modal-content-border-color: rgba($black, .2) !default; -$modal-content-border-width: $border-width !default; -$modal-content-border-radius: $border-radius-lg !default; -$modal-content-box-shadow-xs: 0 .25rem .5rem rgba($black, .5) !default; -$modal-content-box-shadow-sm-up: 0 .5rem 1rem rgba($black, .5) !default; - -$modal-backdrop-bg: $black !default; -$modal-backdrop-opacity: .5 !default; -$modal-header-border-color: $gray-200 !default; -$modal-footer-border-color: $modal-header-border-color !default; -$modal-header-border-width: $modal-content-border-width !default; -$modal-footer-border-width: $modal-header-border-width !default; -$modal-header-padding-y: 1rem !default; -$modal-header-padding-x: 1rem !default; -$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility - -$modal-xl: 1140px !default; -$modal-lg: 800px !default; -$modal-md: 500px !default; -$modal-sm: 300px !default; - -$modal-fade-transform: translate(0, -50px) !default; -$modal-show-transform: none !default; -$modal-transition: transform .3s ease-out !default; - - -// Alerts -// -// Define alert colors, border radius, and padding. - -$alert-padding-y: .75rem !default; -$alert-padding-x: 1.25rem !default; -$alert-margin-bottom: 1rem !default; -$alert-border-radius: $border-radius !default; -$alert-link-font-weight: $font-weight-bold !default; -$alert-border-width: $border-width !default; - -$alert-bg-level: -10 !default; -$alert-border-level: -9 !default; -$alert-color-level: 6 !default; - - -// Progress bars - -$progress-height: 1rem !default; -$progress-font-size: ($font-size-base * .75) !default; -$progress-bg: $gray-200 !default; -$progress-border-radius: $border-radius !default; -$progress-box-shadow: inset 0 .1rem .1rem rgba($black, .1) !default; -$progress-bar-color: $white !default; -$progress-bar-bg: theme-color("primary") !default; -$progress-bar-animation-timing: 1s linear infinite !default; -$progress-bar-transition: width .6s ease !default; - - -// List group - -$list-group-bg: $white !default; -$list-group-border-color: rgba($black, .125) !default; -$list-group-border-width: $border-width !default; -$list-group-border-radius: $border-radius !default; - -$list-group-item-padding-y: .75rem !default; -$list-group-item-padding-x: 1.25rem !default; - -$list-group-hover-bg: $gray-100 !default; -$list-group-active-color: $component-active-color !default; -$list-group-active-bg: $component-active-bg !default; -$list-group-active-border-color: $list-group-active-bg !default; - -$list-group-disabled-color: $gray-600 !default; -$list-group-disabled-bg: $list-group-bg !default; - -$list-group-action-color: $gray-700 !default; -$list-group-action-hover-color: $list-group-action-color !default; - -$list-group-action-active-color: $body-color !default; -$list-group-action-active-bg: $gray-200 !default; - - -// Image thumbnails - -$thumbnail-padding: .25rem !default; -$thumbnail-bg: $body-bg !default; -$thumbnail-border-width: $border-width !default; -$thumbnail-border-color: $gray-300 !default; -$thumbnail-border-radius: $border-radius !default; -$thumbnail-box-shadow: 0 1px 2px rgba($black, .075) !default; - - -// Figures - -$figure-caption-font-size: 90% !default; -$figure-caption-color: $gray-600 !default; - - -// Breadcrumbs - -$breadcrumb-padding-y: .75rem !default; -$breadcrumb-padding-x: 1rem !default; -$breadcrumb-item-padding: .5rem !default; - -$breadcrumb-margin-bottom: 1rem !default; - -$breadcrumb-bg: $gray-200 !default; -$breadcrumb-divider-color: $gray-600 !default; -$breadcrumb-active-color: $gray-600 !default; -$breadcrumb-divider: quote("/") !default; - -$breadcrumb-border-radius: $border-radius !default; - - -// Carousel - -$carousel-control-color: $white !default; -$carousel-control-width: 15% !default; -$carousel-control-opacity: .5 !default; -$carousel-control-hover-opacity: .9 !default; -$carousel-control-transition: opacity .15s ease !default; - -$carousel-indicator-width: 30px !default; -$carousel-indicator-height: 3px !default; -$carousel-indicator-hit-area-height: 10px !default; -$carousel-indicator-spacer: 3px !default; -$carousel-indicator-active-bg: $white !default; -$carousel-indicator-transition: opacity .6s ease !default; - -$carousel-caption-width: 70% !default; -$carousel-caption-color: $white !default; - -$carousel-control-icon-width: 20px !default; - -$carousel-control-prev-icon-bg: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e"), "#", "%23") !default; -$carousel-control-next-icon-bg: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e"), "#", "%23") !default; - -$carousel-transition-duration: .6s !default; -$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`) - - -// Spinners - -$spinner-width: 2rem !default; -$spinner-height: $spinner-width !default; -$spinner-border-width: .25em !default; - -$spinner-width-sm: 1rem !default; -$spinner-height-sm: $spinner-width-sm !default; -$spinner-border-width-sm: .2em !default; - - -// Close - -$close-font-size: $font-size-base * 1.5 !default; -$close-font-weight: $font-weight-bold !default; -$close-color: $black !default; -$close-text-shadow: 0 1px 0 $white !default; - - -// Code - -$code-font-size: 87.5% !default; -$code-color: $pink !default; - -$kbd-padding-y: .2rem !default; -$kbd-padding-x: .4rem !default; -$kbd-font-size: $code-font-size !default; -$kbd-color: $white !default; -$kbd-bg: $gray-900 !default; - -$pre-color: $gray-900 !default; -$pre-scrollable-max-height: 340px !default; - - -// Utilities - -$overflows: auto, hidden !default; -$positions: static, relative, absolute, fixed, sticky !default; - - -// Printing - -$print-page-size: a3 !default; -$print-body-min-width: map-get($grid-breakpoints, "lg") !default; diff --git a/scss/node_modules/bootstrap/scss/_variables.scss.4.2.1.org b/scss/node_modules/bootstrap/scss/_variables.scss.4.2.1.org deleted file mode 100644 index 25e2684..0000000 --- a/scss/node_modules/bootstrap/scss/_variables.scss.4.2.1.org +++ /dev/null @@ -1,1091 +0,0 @@ -// Variables -// -// Variables should follow the `$component-state-property-size` formula for -// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. - -// Color system - -$white: #fff !default; -$gray-100: #f8f9fa !default; -$gray-200: #e9ecef !default; -$gray-300: #dee2e6 !default; -$gray-400: #ced4da !default; -$gray-500: #adb5bd !default; -$gray-600: #6c757d !default; -$gray-700: #495057 !default; -$gray-800: #343a40 !default; -$gray-900: #212529 !default; -$black: #000 !default; - -$grays: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$grays: map-merge( - ( - "100": $gray-100, - "200": $gray-200, - "300": $gray-300, - "400": $gray-400, - "500": $gray-500, - "600": $gray-600, - "700": $gray-700, - "800": $gray-800, - "900": $gray-900 - ), - $grays -); - -$blue: #007bff !default; -$indigo: #6610f2 !default; -$purple: #6f42c1 !default; -$pink: #e83e8c !default; -$red: #dc3545 !default; -$orange: #fd7e14 !default; -$yellow: #ffc107 !default; -$green: #28a745 !default; -$teal: #20c997 !default; -$cyan: #17a2b8 !default; - -$colors: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$colors: map-merge( - ( - "blue": $blue, - "indigo": $indigo, - "purple": $purple, - "pink": $pink, - "red": $red, - "orange": $orange, - "yellow": $yellow, - "green": $green, - "teal": $teal, - "cyan": $cyan, - "white": $white, - "gray": $gray-600, - "gray-dark": $gray-800 - ), - $colors -); - -$primary: $blue !default; -$secondary: $gray-600 !default; -$success: $green !default; -$info: $cyan !default; -$warning: $yellow !default; -$danger: $red !default; -$light: $gray-100 !default; -$dark: $gray-800 !default; - -$theme-colors: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$theme-colors: map-merge( - ( - "primary": $primary, - "secondary": $secondary, - "success": $success, - "info": $info, - "warning": $warning, - "danger": $danger, - "light": $light, - "dark": $dark - ), - $theme-colors -); - -// Set a specific jump point for requesting color jumps -$theme-color-interval: 8% !default; - -// The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255. -$yiq-contrasted-threshold: 150 !default; - -// Customize the light and dark text colors for use in our YIQ color contrast function. -$yiq-text-dark: $gray-900 !default; -$yiq-text-light: $white !default; - - -// Options -// -// Quickly modify global styling by enabling or disabling optional features. - -$enable-caret: true !default; -$enable-rounded: true !default; -$enable-shadows: false !default; -$enable-gradients: false !default; -$enable-transitions: true !default; -$enable-prefers-reduced-motion-media-query: true !default; -$enable-hover-media-query: false !default; // Deprecated, no longer affects any compiled CSS -$enable-grid-classes: true !default; -$enable-print-styles: true !default; -$enable-validation-icons: true !default; - - -// Spacing -// -// Control the default styling of most Bootstrap elements by modifying these -// variables. Mostly focused on spacing. -// You can add more entries to the $spacers map, should you need more variation. - -$spacer: 1rem !default; -$spacers: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$spacers: map-merge( - ( - 0: 0, - 1: ($spacer * .25), - 2: ($spacer * .5), - 3: $spacer, - 4: ($spacer * 1.5), - 5: ($spacer * 3) - ), - $spacers -); - -// This variable affects the `.h-*` and `.w-*` classes. -$sizes: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$sizes: map-merge( - ( - 25: 25%, - 50: 50%, - 75: 75%, - 100: 100%, - auto: auto - ), - $sizes -); - - -// Body -// -// Settings for the `` element. - -$body-bg: $white !default; -$body-color: $gray-900 !default; - - -// Links -// -// Style anchor elements. - -$link-color: theme-color("primary") !default; -$link-decoration: none !default; -$link-hover-color: darken($link-color, 15%) !default; -$link-hover-decoration: underline !default; -// Darken percentage for links with `.text-*` class (e.g. `.text-success`) -$emphasized-link-hover-darken-percentage: 15% !default; - -// Paragraphs -// -// Style p element. - -$paragraph-margin-bottom: 1rem !default; - - -// Grid breakpoints -// -// Define the minimum dimensions at which your layout will change, -// adapting to different screen sizes, for use in media queries. - -$grid-breakpoints: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$grid-breakpoints: map-merge( - ( - xs: 0, - sm: 576px, - md: 768px, - lg: 992px, - xl: 1200px - ), - $grid-breakpoints -); - -@include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); -@include _assert-starts-at-zero($grid-breakpoints); - - -// Grid containers -// -// Define the maximum width of `.container` for different screen sizes. - -$container-max-widths: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$container-max-widths: map-merge( - ( - sm: 540px, - md: 720px, - lg: 960px, - xl: 1140px - ), - $container-max-widths -); - -@include _assert-ascending($container-max-widths, "$container-max-widths"); - - -// Grid columns -// -// Set the number of columns and specify the width of the gutters. - -$grid-columns: 12 !default; -$grid-gutter-width: 30px !default; - - -// Components -// -// Define common padding and border radius sizes and more. - -$line-height-lg: 1.5 !default; -$line-height-sm: 1.5 !default; - -$border-width: 1px !default; -$border-color: $gray-300 !default; - -$border-radius: .25rem !default; -$border-radius-lg: .3rem !default; -$border-radius-sm: .2rem !default; - -$rounded-pill: 50rem !default; - -$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default; -$box-shadow: 0 .5rem 1rem rgba($black, .15) !default; -$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default; - -$component-active-color: $white !default; -$component-active-bg: theme-color("primary") !default; - -$caret-width: .3em !default; - -$transition-base: all .2s ease-in-out !default; -$transition-fade: opacity .15s linear !default; -$transition-collapse: height .35s ease !default; - -$embed-responsive-aspect-ratios: () !default; -// stylelint-disable-next-line scss/dollar-variable-default -$embed-responsive-aspect-ratios: join( - ( - (21 9), - (16 9), - (3 4), - (1 1), - ), - $embed-responsive-aspect-ratios -); - -// Fonts -// -// Font, line-height, and color for body text, headings, and more. - -// stylelint-disable value-keyword-case -$font-family-sans-serif: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; -$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; -$font-family-base: $font-family-sans-serif !default; -// stylelint-enable value-keyword-case - -$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` -$font-size-lg: ($font-size-base * 1.25) !default; -$font-size-sm: ($font-size-base * .875) !default; - -$font-weight-lighter: lighter !default; -$font-weight-light: 300 !default; -$font-weight-normal: 400 !default; -$font-weight-bold: 700 !default; -$font-weight-bolder: bolder !default; - -$font-weight-base: $font-weight-normal !default; -$line-height-base: 1.5 !default; - -$h1-font-size: $font-size-base * 2.5 !default; -$h2-font-size: $font-size-base * 2 !default; -$h3-font-size: $font-size-base * 1.75 !default; -$h4-font-size: $font-size-base * 1.5 !default; -$h5-font-size: $font-size-base * 1.25 !default; -$h6-font-size: $font-size-base !default; - -$headings-margin-bottom: $spacer / 2 !default; -$headings-font-family: inherit !default; -$headings-font-weight: 500 !default; -$headings-line-height: 1.2 !default; -$headings-color: inherit !default; - -$display1-size: 6rem !default; -$display2-size: 5.5rem !default; -$display3-size: 4.5rem !default; -$display4-size: 3.5rem !default; - -$display1-weight: 300 !default; -$display2-weight: 300 !default; -$display3-weight: 300 !default; -$display4-weight: 300 !default; -$display-line-height: $headings-line-height !default; - -$lead-font-size: ($font-size-base * 1.25) !default; -$lead-font-weight: 300 !default; - -$small-font-size: 80% !default; - -$text-muted: $gray-600 !default; - -$blockquote-small-color: $gray-600 !default; -$blockquote-small-font-size: $small-font-size !default; -$blockquote-font-size: ($font-size-base * 1.25) !default; - -$hr-border-color: rgba($black, .1) !default; -$hr-border-width: $border-width !default; - -$mark-padding: .2em !default; - -$dt-font-weight: $font-weight-bold !default; - -$kbd-box-shadow: inset 0 -.1rem 0 rgba($black, .25) !default; -$nested-kbd-font-weight: $font-weight-bold !default; - -$list-inline-padding: .5rem !default; - -$mark-bg: #fcf8e3 !default; - -$hr-margin-y: $spacer !default; - - -// Tables -// -// Customizes the `.table` component with basic values, each used across all table variations. - -$table-cell-padding: .75rem !default; -$table-cell-padding-sm: .3rem !default; - -$table-bg: transparent !default; -$table-accent-bg: rgba($black, .05) !default; -$table-hover-bg: rgba($black, .075) !default; -$table-active-bg: $table-hover-bg !default; - -$table-border-width: $border-width !default; -$table-border-color: $gray-300 !default; - -$table-head-bg: $gray-200 !default; -$table-head-color: $gray-700 !default; - -$table-dark-bg: $gray-900 !default; -$table-dark-accent-bg: rgba($white, .05) !default; -$table-dark-hover-bg: rgba($white, .075) !default; -$table-dark-border-color: lighten($gray-900, 7.5%) !default; -$table-dark-color: $white !default; - -$table-striped-order: odd !default; - -$table-caption-color: $text-muted !default; - -$table-bg-level: -9 !default; -$table-border-level: -6 !default; - - -// Buttons + Forms -// -// Shared variables that are reassigned to `$input-` and `$btn-` specific variables. - -$input-btn-padding-y: .375rem !default; -$input-btn-padding-x: .75rem !default; -$input-btn-font-size: $font-size-base !default; -$input-btn-line-height: $line-height-base !default; - -$input-btn-focus-width: .2rem !default; -$input-btn-focus-color: rgba($component-active-bg, .25) !default; -$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default; - -$input-btn-padding-y-sm: .25rem !default; -$input-btn-padding-x-sm: .5rem !default; -$input-btn-font-size-sm: $font-size-sm !default; -$input-btn-line-height-sm: $line-height-sm !default; - -$input-btn-padding-y-lg: .5rem !default; -$input-btn-padding-x-lg: 1rem !default; -$input-btn-font-size-lg: $font-size-lg !default; -$input-btn-line-height-lg: $line-height-lg !default; - -$input-btn-border-width: $border-width !default; - - -// Buttons -// -// For each of Bootstrap's buttons, define text, background, and border color. - -$btn-padding-y: $input-btn-padding-y !default; -$btn-padding-x: $input-btn-padding-x !default; -$btn-font-size: $input-btn-font-size !default; -$btn-line-height: $input-btn-line-height !default; - -$btn-padding-y-sm: $input-btn-padding-y-sm !default; -$btn-padding-x-sm: $input-btn-padding-x-sm !default; -$btn-font-size-sm: $input-btn-font-size-sm !default; -$btn-line-height-sm: $input-btn-line-height-sm !default; - -$btn-padding-y-lg: $input-btn-padding-y-lg !default; -$btn-padding-x-lg: $input-btn-padding-x-lg !default; -$btn-font-size-lg: $input-btn-font-size-lg !default; -$btn-line-height-lg: $input-btn-line-height-lg !default; - -$btn-border-width: $input-btn-border-width !default; - -$btn-font-weight: $font-weight-normal !default; -$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default; -$btn-focus-width: $input-btn-focus-width !default; -$btn-focus-box-shadow: $input-btn-focus-box-shadow !default; -$btn-disabled-opacity: .65 !default; -$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default; - -$btn-link-disabled-color: $gray-600 !default; - -$btn-block-spacing-y: .5rem !default; - -// Allows for customizing button radius independently from global border radius -$btn-border-radius: $border-radius !default; -$btn-border-radius-lg: $border-radius-lg !default; -$btn-border-radius-sm: $border-radius-sm !default; - -$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; - - -// Forms - -$label-margin-bottom: .5rem !default; - -$input-padding-y: $input-btn-padding-y !default; -$input-padding-x: $input-btn-padding-x !default; -$input-font-size: $input-btn-font-size !default; -$input-font-weight: $font-weight-base !default; -$input-line-height: $input-btn-line-height !default; - -$input-padding-y-sm: $input-btn-padding-y-sm !default; -$input-padding-x-sm: $input-btn-padding-x-sm !default; -$input-font-size-sm: $input-btn-font-size-sm !default; -$input-line-height-sm: $input-btn-line-height-sm !default; - -$input-padding-y-lg: $input-btn-padding-y-lg !default; -$input-padding-x-lg: $input-btn-padding-x-lg !default; -$input-font-size-lg: $input-btn-font-size-lg !default; -$input-line-height-lg: $input-btn-line-height-lg !default; - -$input-bg: $white !default; -$input-disabled-bg: $gray-200 !default; - -$input-color: $gray-700 !default; -$input-border-color: $gray-400 !default; -$input-border-width: $input-btn-border-width !default; -$input-box-shadow: inset 0 1px 1px rgba($black, .075) !default; - -$input-border-radius: $border-radius !default; -$input-border-radius-lg: $border-radius-lg !default; -$input-border-radius-sm: $border-radius-sm !default; - -$input-focus-bg: $input-bg !default; -$input-focus-border-color: lighten($component-active-bg, 25%) !default; -$input-focus-color: $input-color !default; -$input-focus-width: $input-btn-focus-width !default; -$input-focus-box-shadow: $input-btn-focus-box-shadow !default; - -$input-placeholder-color: $gray-600 !default; -$input-plaintext-color: $body-color !default; - -$input-height-border: $input-border-width * 2 !default; - -$input-height-inner: ($input-btn-font-size * $input-btn-line-height) + ($input-btn-padding-y * 2) !default; -$input-height: calc(#{$input-height-inner} + #{$input-height-border}) !default; - -$input-height-inner-sm: ($input-btn-font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2) !default; -$input-height-sm: calc(#{$input-height-inner-sm} + #{$input-height-border}) !default; - -$input-height-inner-lg: ($input-btn-font-size-lg * $input-btn-line-height-lg) + ($input-btn-padding-y-lg * 2) !default; -$input-height-lg: calc(#{$input-height-inner-lg} + #{$input-height-border}) !default; - -$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; - -$form-text-margin-top: .25rem !default; - -$form-check-input-gutter: 1.25rem !default; -$form-check-input-margin-y: .3rem !default; -$form-check-input-margin-x: .25rem !default; - -$form-check-inline-margin-x: .75rem !default; -$form-check-inline-input-margin-x: .3125rem !default; - -$form-grid-gutter-width: 10px !default; -$form-group-margin-bottom: 1rem !default; - -$input-group-addon-color: $input-color !default; -$input-group-addon-bg: $gray-200 !default; -$input-group-addon-border-color: $input-border-color !default; - -$custom-forms-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; - -$custom-control-gutter: .5rem !default; -$custom-control-spacer-x: 1rem !default; - -$custom-control-indicator-size: 1rem !default; -$custom-control-indicator-bg: $input-bg !default; - -$custom-control-indicator-bg-size: 50% 50% !default; -$custom-control-indicator-box-shadow: $input-box-shadow !default; -$custom-control-indicator-border-color: $gray-500 !default; -$custom-control-indicator-border-width: $input-border-width !default; - -$custom-control-indicator-disabled-bg: $input-disabled-bg !default; -$custom-control-label-disabled-color: $gray-600 !default; - -$custom-control-indicator-checked-color: $component-active-color !default; -$custom-control-indicator-checked-bg: $component-active-bg !default; -$custom-control-indicator-checked-disabled-bg: rgba(theme-color("primary"), .5) !default; -$custom-control-indicator-checked-box-shadow: none !default; -$custom-control-indicator-checked-border-color: $custom-control-indicator-checked-bg !default; - -$custom-control-indicator-focus-box-shadow: $input-btn-focus-box-shadow !default; -$custom-control-indicator-focus-border-color: $input-focus-border-color !default; - -$custom-control-indicator-active-color: $component-active-color !default; -$custom-control-indicator-active-bg: lighten($component-active-bg, 35%) !default; -$custom-control-indicator-active-box-shadow: none !default; -$custom-control-indicator-active-border-color: $custom-control-indicator-active-bg !default; - -$custom-checkbox-indicator-border-radius: $border-radius !default; -$custom-checkbox-indicator-icon-checked: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='#{$custom-control-indicator-checked-color}' d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26 2.974 7.25 8 2.193z'/%3e%3c/svg%3e"), "#", "%23") !default; - -$custom-checkbox-indicator-indeterminate-bg: $component-active-bg !default; -$custom-checkbox-indicator-indeterminate-color: $custom-control-indicator-checked-color !default; -$custom-checkbox-indicator-icon-indeterminate: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 4'%3e%3cpath stroke='#{$custom-checkbox-indicator-indeterminate-color}' d='M0 2h4'/%3e%3c/svg%3e"), "#", "%23") !default; -$custom-checkbox-indicator-indeterminate-box-shadow: none !default; -$custom-checkbox-indicator-indeterminate-border-color: $custom-checkbox-indicator-indeterminate-bg !default; - -$custom-radio-indicator-border-radius: 50% !default; -$custom-radio-indicator-icon-checked: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='#{$custom-control-indicator-checked-color}'/%3e%3c/svg%3e"), "#", "%23") !default; - -$custom-switch-width: $custom-control-indicator-size * 1.75 !default; -$custom-switch-indicator-border-radius: $custom-control-indicator-size / 2 !default; -$custom-switch-indicator-size: calc(#{$custom-control-indicator-size} - #{$custom-control-indicator-border-width * 4}) !default; - -$custom-select-padding-y: $input-btn-padding-y !default; -$custom-select-padding-x: $input-btn-padding-x !default; -$custom-select-height: $input-height !default; -$custom-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator -$custom-select-font-weight: $input-font-weight !default; -$custom-select-line-height: $input-line-height !default; -$custom-select-color: $input-color !default; -$custom-select-disabled-color: $gray-600 !default; -$custom-select-bg: $input-bg !default; -$custom-select-disabled-bg: $gray-200 !default; -$custom-select-bg-size: 8px 10px !default; // In pixels because image dimensions -$custom-select-indicator-color: $gray-800 !default; -$custom-select-indicator: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3e%3cpath fill='#{$custom-select-indicator-color}' d='M2 0L0 2h4zm0 5L0 3h4z'/%3e%3c/svg%3e"), "#", "%23") !default; -$custom-select-background: $custom-select-indicator no-repeat right $custom-select-padding-x center / $custom-select-bg-size !default; // Used so we can have multiple background elements (e.g., arrow and feedback icon) - -$custom-select-feedback-icon-padding-right: $input-height-inner * 3 / 4 + $custom-select-padding-x + $custom-select-indicator-padding !default; -$custom-select-feedback-icon-position: center right ($custom-select-padding-x + $custom-select-indicator-padding) !default; -$custom-select-feedback-icon-size: ($input-height-inner / 2) ($input-height-inner / 2) !default; - -$custom-select-border-width: $input-border-width !default; -$custom-select-border-color: $input-border-color !default; -$custom-select-border-radius: $border-radius !default; -$custom-select-box-shadow: inset 0 1px 2px rgba($black, .075) !default; - -$custom-select-focus-border-color: $input-focus-border-color !default; -$custom-select-focus-width: $input-focus-width !default; -$custom-select-focus-box-shadow: 0 0 0 $custom-select-focus-width rgba($custom-select-focus-border-color, .5) !default; - -$custom-select-padding-y-sm: $input-padding-y-sm !default; -$custom-select-padding-x-sm: $input-padding-x-sm !default; -$custom-select-font-size-sm: $input-btn-font-size-sm !default; -$custom-select-height-sm: $input-height-sm !default; - -$custom-select-padding-y-lg: $input-padding-y-lg !default; -$custom-select-padding-x-lg: $input-padding-x-lg !default; -$custom-select-font-size-lg: $input-btn-font-size-lg !default; -$custom-select-height-lg: $input-height-lg !default; - -$custom-range-track-width: 100% !default; -$custom-range-track-height: .5rem !default; -$custom-range-track-cursor: pointer !default; -$custom-range-track-bg: $gray-300 !default; -$custom-range-track-border-radius: 1rem !default; -$custom-range-track-box-shadow: inset 0 .25rem .25rem rgba($black, .1) !default; - -$custom-range-thumb-width: 1rem !default; -$custom-range-thumb-height: $custom-range-thumb-width !default; -$custom-range-thumb-bg: $component-active-bg !default; -$custom-range-thumb-border: 0 !default; -$custom-range-thumb-border-radius: 1rem !default; -$custom-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default; -$custom-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default; -$custom-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in IE/Edge -$custom-range-thumb-active-bg: lighten($component-active-bg, 35%) !default; -$custom-range-thumb-disabled-bg: $gray-500 !default; - -$custom-file-height: $input-height !default; -$custom-file-height-inner: $input-height-inner !default; -$custom-file-focus-border-color: $input-focus-border-color !default; -$custom-file-focus-box-shadow: $input-focus-box-shadow !default; -$custom-file-disabled-bg: $input-disabled-bg !default; - -$custom-file-padding-y: $input-padding-y !default; -$custom-file-padding-x: $input-padding-x !default; -$custom-file-line-height: $input-line-height !default; -$custom-file-font-weight: $input-font-weight !default; -$custom-file-color: $input-color !default; -$custom-file-bg: $input-bg !default; -$custom-file-border-width: $input-border-width !default; -$custom-file-border-color: $input-border-color !default; -$custom-file-border-radius: $input-border-radius !default; -$custom-file-box-shadow: $input-box-shadow !default; -$custom-file-button-color: $custom-file-color !default; -$custom-file-button-bg: $input-group-addon-bg !default; -$custom-file-text: ( - en: "Browse" -) !default; - - -// Form validation - -$form-feedback-margin-top: $form-text-margin-top !default; -$form-feedback-font-size: $small-font-size !default; -$form-feedback-valid-color: theme-color("success") !default; -$form-feedback-invalid-color: theme-color("danger") !default; - -$form-feedback-icon-valid-color: $form-feedback-valid-color !default; -$form-feedback-icon-valid: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e"), "#", "%23") !default; -$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default; -$form-feedback-icon-invalid: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$form-feedback-icon-invalid-color}' viewBox='-2 -2 7 7'%3e%3cpath stroke='%23d9534f' d='M0 0l3 3m0-3L0 3'/%3e%3ccircle r='.5'/%3e%3ccircle cx='3' r='.5'/%3e%3ccircle cy='3' r='.5'/%3e%3ccircle cx='3' cy='3' r='.5'/%3e%3c/svg%3E"), "#", "%23") !default; - - -// Dropdowns -// -// Dropdown menu container and contents. - -$dropdown-min-width: 10rem !default; -$dropdown-padding-y: .5rem !default; -$dropdown-spacer: .125rem !default; -$dropdown-bg: $white !default; -$dropdown-border-color: rgba($black, .15) !default; -$dropdown-border-radius: $border-radius !default; -$dropdown-border-width: $border-width !default; -$dropdown-inner-border-radius: calc(#{$dropdown-border-radius} - #{$dropdown-border-width}) !default; -$dropdown-divider-bg: $gray-200 !default; -$dropdown-box-shadow: 0 .5rem 1rem rgba($black, .175) !default; - -$dropdown-link-color: $gray-900 !default; -$dropdown-link-hover-color: darken($gray-900, 5%) !default; -$dropdown-link-hover-bg: $gray-100 !default; - -$dropdown-link-active-color: $component-active-color !default; -$dropdown-link-active-bg: $component-active-bg !default; - -$dropdown-link-disabled-color: $gray-600 !default; - -$dropdown-item-padding-y: .25rem !default; -$dropdown-item-padding-x: 1.5rem !default; - -$dropdown-header-color: $gray-600 !default; - - -// Z-index master list -// -// Warning: Avoid customizing these values. They're used for a bird's eye view -// of components dependent on the z-axis and are designed to all work together. - -$zindex-dropdown: 1000 !default; -$zindex-sticky: 1020 !default; -$zindex-fixed: 1030 !default; -$zindex-modal-backdrop: 1040 !default; -$zindex-modal: 1050 !default; -$zindex-popover: 1060 !default; -$zindex-tooltip: 1070 !default; - - -// Navs - -$nav-link-padding-y: .5rem !default; -$nav-link-padding-x: 1rem !default; -$nav-link-disabled-color: $gray-600 !default; - -$nav-tabs-border-color: $gray-300 !default; -$nav-tabs-border-width: $border-width !default; -$nav-tabs-border-radius: $border-radius !default; -$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default; -$nav-tabs-link-active-color: $gray-700 !default; -$nav-tabs-link-active-bg: $body-bg !default; -$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default; - -$nav-pills-border-radius: $border-radius !default; -$nav-pills-link-active-color: $component-active-color !default; -$nav-pills-link-active-bg: $component-active-bg !default; - -$nav-divider-color: $gray-200 !default; -$nav-divider-margin-y: $spacer / 2 !default; - - -// Navbar - -$navbar-padding-y: $spacer / 2 !default; -$navbar-padding-x: $spacer !default; - -$navbar-nav-link-padding-x: .5rem !default; - -$navbar-brand-font-size: $font-size-lg !default; -// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link -$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default; -$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; -$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) / 2 !default; - -$navbar-toggler-padding-y: .25rem !default; -$navbar-toggler-padding-x: .75rem !default; -$navbar-toggler-font-size: $font-size-lg !default; -$navbar-toggler-border-radius: $btn-border-radius !default; - -$navbar-dark-color: rgba($white, .5) !default; -$navbar-dark-hover-color: rgba($white, .75) !default; -$navbar-dark-active-color: $white !default; -$navbar-dark-disabled-color: rgba($white, .25) !default; -$navbar-dark-toggler-icon-bg: str-replace(url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='#{$navbar-dark-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"), "#", "%23") !default; -$navbar-dark-toggler-border-color: rgba($white, .1) !default; - -$navbar-light-color: rgba($black, .5) !default; -$navbar-light-hover-color: rgba($black, .7) !default; -$navbar-light-active-color: rgba($black, .9) !default; -$navbar-light-disabled-color: rgba($black, .3) !default; -$navbar-light-toggler-icon-bg: str-replace(url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='#{$navbar-light-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"), "#", "%23") !default; -$navbar-light-toggler-border-color: rgba($black, .1) !default; - -$navbar-light-brand-color: $navbar-light-active-color !default; -$navbar-light-brand-hover-color: $navbar-light-active-color !default; -$navbar-dark-brand-color: $navbar-dark-active-color !default; -$navbar-dark-brand-hover-color: $navbar-dark-active-color !default; - - -// Pagination - -$pagination-padding-y: .5rem !default; -$pagination-padding-x: .75rem !default; -$pagination-padding-y-sm: .25rem !default; -$pagination-padding-x-sm: .5rem !default; -$pagination-padding-y-lg: .75rem !default; -$pagination-padding-x-lg: 1.5rem !default; -$pagination-line-height: 1.25 !default; - -$pagination-color: $link-color !default; -$pagination-bg: $white !default; -$pagination-border-width: $border-width !default; -$pagination-border-color: $gray-300 !default; - -$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default; -$pagination-focus-outline: 0 !default; - -$pagination-hover-color: $link-hover-color !default; -$pagination-hover-bg: $gray-200 !default; -$pagination-hover-border-color: $gray-300 !default; - -$pagination-active-color: $component-active-color !default; -$pagination-active-bg: $component-active-bg !default; -$pagination-active-border-color: $pagination-active-bg !default; - -$pagination-disabled-color: $gray-600 !default; -$pagination-disabled-bg: $white !default; -$pagination-disabled-border-color: $gray-300 !default; - - -// Jumbotron - -$jumbotron-padding: 2rem !default; -$jumbotron-bg: $gray-200 !default; - - -// Cards - -$card-spacer-y: .75rem !default; -$card-spacer-x: 1.25rem !default; -$card-border-width: $border-width !default; -$card-border-radius: $border-radius !default; -$card-border-color: rgba($black, .125) !default; -$card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}) !default; -$card-cap-bg: rgba($black, .03) !default; -$card-cap-color: inherit !default; -$card-bg: $white !default; - -$card-img-overlay-padding: 1.25rem !default; - -$card-group-margin: $grid-gutter-width / 2 !default; -$card-deck-margin: $card-group-margin !default; - -$card-columns-count: 3 !default; -$card-columns-gap: 1.25rem !default; -$card-columns-margin: $card-spacer-y !default; - - -// Tooltips - -$tooltip-font-size: $font-size-sm !default; -$tooltip-max-width: 200px !default; -$tooltip-color: $white !default; -$tooltip-bg: $black !default; -$tooltip-border-radius: $border-radius !default; -$tooltip-opacity: .9 !default; -$tooltip-padding-y: .25rem !default; -$tooltip-padding-x: .5rem !default; -$tooltip-margin: 0 !default; - -$tooltip-arrow-width: .8rem !default; -$tooltip-arrow-height: .4rem !default; -$tooltip-arrow-color: $tooltip-bg !default; - -// Form tooltips must come after regular tooltips -$form-feedback-tooltip-padding-y: $tooltip-padding-y !default; -$form-feedback-tooltip-padding-x: $tooltip-padding-x !default; -$form-feedback-tooltip-font-size: $tooltip-font-size !default; -$form-feedback-tooltip-line-height: $line-height-base !default; -$form-feedback-tooltip-opacity: $tooltip-opacity !default; -$form-feedback-tooltip-border-radius: $tooltip-border-radius !default; - - -// Popovers - -$popover-font-size: $font-size-sm !default; -$popover-bg: $white !default; -$popover-max-width: 276px !default; -$popover-border-width: $border-width !default; -$popover-border-color: rgba($black, .2) !default; -$popover-border-radius: $border-radius-lg !default; -$popover-box-shadow: 0 .25rem .5rem rgba($black, .2) !default; - -$popover-header-bg: darken($popover-bg, 3%) !default; -$popover-header-color: $headings-color !default; -$popover-header-padding-y: .5rem !default; -$popover-header-padding-x: .75rem !default; - -$popover-body-color: $body-color !default; -$popover-body-padding-y: $popover-header-padding-y !default; -$popover-body-padding-x: $popover-header-padding-x !default; - -$popover-arrow-width: 1rem !default; -$popover-arrow-height: .5rem !default; -$popover-arrow-color: $popover-bg !default; - -$popover-arrow-outer-color: fade-in($popover-border-color, .05) !default; - - -// Toasts -$toast-max-width: 350px !default; -$toast-padding-x: .75rem !default; -$toast-padding-y: .25rem !default; -$toast-font-size: .875rem !default; -$toast-background-color: rgba($white, .85) !default; -$toast-border-width: 1px !default; -$toast-border-color: rgba(0, 0, 0, .1) !default; -$toast-border-radius: .25rem !default; -$toast-box-shadow: 0 .25rem .75rem rgba($black, .1) !default; - -$toast-header-color: $gray-600 !default; -$toast-header-background-color: rgba($white, .85) !default; -$toast-header-border-color: rgba(0, 0, 0, .05) !default; - - -// Badges - -$badge-font-size: 75% !default; -$badge-font-weight: $font-weight-bold !default; -$badge-padding-y: .25em !default; -$badge-padding-x: .4em !default; -$badge-border-radius: $border-radius !default; - -$badge-pill-padding-x: .6em !default; -// Use a higher than normal value to ensure completely rounded edges when -// customizing padding or font-size on labels. -$badge-pill-border-radius: 10rem !default; - - -// Modals - -// Padding applied to the modal body -$modal-inner-padding: 1rem !default; - -$modal-dialog-margin: .5rem !default; -$modal-dialog-margin-y-sm-up: 1.75rem !default; - -$modal-title-line-height: $line-height-base !default; - -$modal-content-bg: $white !default; -$modal-content-border-color: rgba($black, .2) !default; -$modal-content-border-width: $border-width !default; -$modal-content-border-radius: $border-radius-lg !default; -$modal-content-box-shadow-xs: 0 .25rem .5rem rgba($black, .5) !default; -$modal-content-box-shadow-sm-up: 0 .5rem 1rem rgba($black, .5) !default; - -$modal-backdrop-bg: $black !default; -$modal-backdrop-opacity: .5 !default; -$modal-header-border-color: $gray-200 !default; -$modal-footer-border-color: $modal-header-border-color !default; -$modal-header-border-width: $modal-content-border-width !default; -$modal-footer-border-width: $modal-header-border-width !default; -$modal-header-padding-y: 1rem !default; -$modal-header-padding-x: 1rem !default; -$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility - -$modal-xl: 1140px !default; -$modal-lg: 800px !default; -$modal-md: 500px !default; -$modal-sm: 300px !default; - -$modal-fade-transform: translate(0, -50px) !default; -$modal-show-transform: none !default; -$modal-transition: transform .3s ease-out !default; - - -// Alerts -// -// Define alert colors, border radius, and padding. - -$alert-padding-y: .75rem !default; -$alert-padding-x: 1.25rem !default; -$alert-margin-bottom: 1rem !default; -$alert-border-radius: $border-radius !default; -$alert-link-font-weight: $font-weight-bold !default; -$alert-border-width: $border-width !default; - -$alert-bg-level: -10 !default; -$alert-border-level: -9 !default; -$alert-color-level: 6 !default; - - -// Progress bars - -$progress-height: 1rem !default; -$progress-font-size: ($font-size-base * .75) !default; -$progress-bg: $gray-200 !default; -$progress-border-radius: $border-radius !default; -$progress-box-shadow: inset 0 .1rem .1rem rgba($black, .1) !default; -$progress-bar-color: $white !default; -$progress-bar-bg: theme-color("primary") !default; -$progress-bar-animation-timing: 1s linear infinite !default; -$progress-bar-transition: width .6s ease !default; - - -// List group - -$list-group-bg: $white !default; -$list-group-border-color: rgba($black, .125) !default; -$list-group-border-width: $border-width !default; -$list-group-border-radius: $border-radius !default; - -$list-group-item-padding-y: .75rem !default; -$list-group-item-padding-x: 1.25rem !default; - -$list-group-hover-bg: $gray-100 !default; -$list-group-active-color: $component-active-color !default; -$list-group-active-bg: $component-active-bg !default; -$list-group-active-border-color: $list-group-active-bg !default; - -$list-group-disabled-color: $gray-600 !default; -$list-group-disabled-bg: $list-group-bg !default; - -$list-group-action-color: $gray-700 !default; -$list-group-action-hover-color: $list-group-action-color !default; - -$list-group-action-active-color: $body-color !default; -$list-group-action-active-bg: $gray-200 !default; - - -// Image thumbnails - -$thumbnail-padding: .25rem !default; -$thumbnail-bg: $body-bg !default; -$thumbnail-border-width: $border-width !default; -$thumbnail-border-color: $gray-300 !default; -$thumbnail-border-radius: $border-radius !default; -$thumbnail-box-shadow: 0 1px 2px rgba($black, .075) !default; - - -// Figures - -$figure-caption-font-size: 90% !default; -$figure-caption-color: $gray-600 !default; - - -// Breadcrumbs - -$breadcrumb-padding-y: .75rem !default; -$breadcrumb-padding-x: 1rem !default; -$breadcrumb-item-padding: .5rem !default; - -$breadcrumb-margin-bottom: 1rem !default; - -$breadcrumb-bg: $gray-200 !default; -$breadcrumb-divider-color: $gray-600 !default; -$breadcrumb-active-color: $gray-600 !default; -$breadcrumb-divider: quote("/") !default; - -$breadcrumb-border-radius: $border-radius !default; - - -// Carousel - -$carousel-control-color: $white !default; -$carousel-control-width: 15% !default; -$carousel-control-opacity: .5 !default; -$carousel-control-hover-opacity: .9 !default; -$carousel-control-transition: opacity .15s ease !default; - -$carousel-indicator-width: 30px !default; -$carousel-indicator-height: 3px !default; -$carousel-indicator-hit-area-height: 10px !default; -$carousel-indicator-spacer: 3px !default; -$carousel-indicator-active-bg: $white !default; -$carousel-indicator-transition: opacity .6s ease !default; - -$carousel-caption-width: 70% !default; -$carousel-caption-color: $white !default; - -$carousel-control-icon-width: 20px !default; - -$carousel-control-prev-icon-bg: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3e%3cpath d='M5.25 0l-4 4 4 4 1.5-1.5-2.5-2.5 2.5-2.5-1.5-1.5z'/%3e%3c/svg%3e"), "#", "%23") !default; -$carousel-control-next-icon-bg: str-replace(url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='#{$carousel-control-color}' viewBox='0 0 8 8'%3e%3cpath d='M2.75 0l-1.5 1.5 2.5 2.5-2.5 2.5 1.5 1.5 4-4-4-4z'/%3e%3c/svg%3e"), "#", "%23") !default; - -$carousel-transition-duration: .6s !default; -$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`) - - -// Spinners - -$spinner-width: 2rem !default; -$spinner-height: $spinner-width !default; -$spinner-border-width: .25em !default; - -$spinner-width-sm: 1rem !default; -$spinner-height-sm: $spinner-width-sm !default; -$spinner-border-width-sm: .2em !default; - - -// Close - -$close-font-size: $font-size-base * 1.5 !default; -$close-font-weight: $font-weight-bold !default; -$close-color: $black !default; -$close-text-shadow: 0 1px 0 $white !default; - - -// Code - -$code-font-size: 87.5% !default; -$code-color: $pink !default; - -$kbd-padding-y: .2rem !default; -$kbd-padding-x: .4rem !default; -$kbd-font-size: $code-font-size !default; -$kbd-color: $white !default; -$kbd-bg: $gray-900 !default; - -$pre-color: $gray-900 !default; -$pre-scrollable-max-height: 340px !default; - - -// Utilities - -$overflows: auto, hidden !default; -$positions: static, relative, absolute, fixed, sticky !default; - - -// Printing - -$print-page-size: a3 !default; -$print-body-min-width: map-get($grid-breakpoints, "lg") !default; diff --git a/scss/node_modules/bootstrap/scss/mixins/_alert.scss b/scss/node_modules/bootstrap/scss/mixins/_alert.scss deleted file mode 100644 index db5a7eb..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_alert.scss +++ /dev/null @@ -1,13 +0,0 @@ -@mixin alert-variant($background, $border, $color) { - color: $color; - @include gradient-bg($background); - border-color: $border; - - hr { - border-top-color: darken($border, 5%); - } - - .alert-link { - color: darken($color, 10%); - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_background-variant.scss b/scss/node_modules/bootstrap/scss/mixins/_background-variant.scss deleted file mode 100644 index 494439d..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_background-variant.scss +++ /dev/null @@ -1,21 +0,0 @@ -// stylelint-disable declaration-no-important - -// Contextual backgrounds - -@mixin bg-variant($parent, $color) { - #{$parent} { - background-color: $color !important; - } - a#{$parent}, - button#{$parent} { - @include hover-focus { - background-color: darken($color, 10%) !important; - } - } -} - -@mixin bg-gradient-variant($parent, $color) { - #{$parent} { - background: $color linear-gradient(180deg, mix($body-bg, $color, 15%), $color) repeat-x !important; - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_badge.scss b/scss/node_modules/bootstrap/scss/mixins/_badge.scss deleted file mode 100644 index cf99b35..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_badge.scss +++ /dev/null @@ -1,11 +0,0 @@ -@mixin badge-variant($bg) { - color: color-yiq($bg); - background-color: $bg; - - @at-root a#{&} { - @include hover-focus { - color: color-yiq($bg); - background-color: darken($bg, 10%); - } - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_border-radius.scss b/scss/node_modules/bootstrap/scss/mixins/_border-radius.scss deleted file mode 100644 index 2024feb..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_border-radius.scss +++ /dev/null @@ -1,35 +0,0 @@ -// Single side border-radius - -@mixin border-radius($radius: $border-radius) { - @if $enable-rounded { - border-radius: $radius; - } -} - -@mixin border-top-radius($radius) { - @if $enable-rounded { - border-top-left-radius: $radius; - border-top-right-radius: $radius; - } -} - -@mixin border-right-radius($radius) { - @if $enable-rounded { - border-top-right-radius: $radius; - border-bottom-right-radius: $radius; - } -} - -@mixin border-bottom-radius($radius) { - @if $enable-rounded { - border-bottom-right-radius: $radius; - border-bottom-left-radius: $radius; - } -} - -@mixin border-left-radius($radius) { - @if $enable-rounded { - border-top-left-radius: $radius; - border-bottom-left-radius: $radius; - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_box-shadow.scss b/scss/node_modules/bootstrap/scss/mixins/_box-shadow.scss deleted file mode 100644 index b2410e5..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_box-shadow.scss +++ /dev/null @@ -1,5 +0,0 @@ -@mixin box-shadow($shadow...) { - @if $enable-shadows { - box-shadow: $shadow; - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_breakpoints.scss b/scss/node_modules/bootstrap/scss/mixins/_breakpoints.scss deleted file mode 100644 index 23a5de9..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_breakpoints.scss +++ /dev/null @@ -1,123 +0,0 @@ -// Breakpoint viewport sizes and media queries. -// -// Breakpoints are defined as a map of (name: minimum width), order from small to large: -// -// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px) -// -// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. - -// Name of the next breakpoint, or null for the last breakpoint. -// -// >> breakpoint-next(sm) -// md -// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) -// md -// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl)) -// md -@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { - $n: index($breakpoint-names, $name); - @return if($n != null and $n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); -} - -// Minimum breakpoint width. Null for the smallest (first) breakpoint. -// -// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) -// 576px -@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { - $min: map-get($breakpoints, $name); - @return if($min != 0, $min, null); -} - -// Maximum breakpoint width. Null for the largest (last) breakpoint. -// The maximum value is calculated as the minimum of the next one less 0.02px -// to work around the limitations of `min-` and `max-` prefixes and viewports with fractional widths. -// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max -// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari. -// See https://bugs.webkit.org/show_bug.cgi?id=178261 -// -// >> breakpoint-max(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) -// 767.98px -@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { - $next: breakpoint-next($name, $breakpoints); - @return if($next, breakpoint-min($next, $breakpoints) - .02, null); -} - -// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front. -// Useful for making responsive utilities. -// -// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) -// "" (Returns a blank string) -// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) -// "-sm" -@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) { - @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}"); -} - -// Media of at least the minimum breakpoint width. No query for the smallest breakpoint. -// Makes the @content apply to the given breakpoint and wider. -@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) { - $min: breakpoint-min($name, $breakpoints); - @if $min { - @media (min-width: $min) { - @content; - } - } @else { - @content; - } -} - -// Media of at most the maximum breakpoint width. No query for the largest breakpoint. -// Makes the @content apply to the given breakpoint and narrower. -@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) { - $max: breakpoint-max($name, $breakpoints); - @if $max { - @media (max-width: $max) { - @content; - } - } @else { - @content; - } -} - -// Media that spans multiple breakpoint widths. -// Makes the @content apply between the min and max breakpoints -@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) { - $min: breakpoint-min($lower, $breakpoints); - $max: breakpoint-max($upper, $breakpoints); - - @if $min != null and $max != null { - @media (min-width: $min) and (max-width: $max) { - @content; - } - } @else if $max == null { - @include media-breakpoint-up($lower, $breakpoints) { - @content; - } - } @else if $min == null { - @include media-breakpoint-down($upper, $breakpoints) { - @content; - } - } -} - -// Media between the breakpoint's minimum and maximum widths. -// No minimum for the smallest breakpoint, and no maximum for the largest one. -// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower. -@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) { - $min: breakpoint-min($name, $breakpoints); - $max: breakpoint-max($name, $breakpoints); - - @if $min != null and $max != null { - @media (min-width: $min) and (max-width: $max) { - @content; - } - } @else if $max == null { - @include media-breakpoint-up($name, $breakpoints) { - @content; - } - } @else if $min == null { - @include media-breakpoint-down($name, $breakpoints) { - @content; - } - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_buttons.scss b/scss/node_modules/bootstrap/scss/mixins/_buttons.scss deleted file mode 100644 index 3e1e2c0..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_buttons.scss +++ /dev/null @@ -1,111 +0,0 @@ -// Button variants -// -// Easily pump out default styles, as well as :hover, :focus, :active, -// and disabled options for all buttons - -@mixin button-variant($background, $border, $hover-background: darken($background, 7.5%), $hover-border: darken($border, 10%), $active-background: darken($background, 10%), $active-border: darken($border, 12.5%)) { - color: color-yiq($background); - @include gradient-bg($background); - border-color: $border; - @include box-shadow($btn-box-shadow); - - @include hover { - color: color-yiq($hover-background); - @include gradient-bg($hover-background); - border-color: $hover-border; - } - - &:focus, - &.focus { - // Avoid using mixin so we can pass custom focus shadow properly - @if $enable-shadows { - box-shadow: $btn-box-shadow, 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5); - } @else { - box-shadow: 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5); - } - } - - // Disabled comes first so active can properly restyle - &.disabled, - &:disabled { - color: color-yiq($background); - background-color: $background; - border-color: $border; - // Remove CSS gradients if they're enabled - @if $enable-gradients { - background-image: none; - } - } - - &:not(:disabled):not(.disabled):active, - &:not(:disabled):not(.disabled).active, - .show > &.dropdown-toggle { - color: color-yiq($active-background); - background-color: $active-background; - @if $enable-gradients { - background-image: none; // Remove the gradient for the pressed/active state - } - border-color: $active-border; - - &:focus { - // Avoid using mixin so we can pass custom focus shadow properly - @if $enable-shadows { - box-shadow: $btn-active-box-shadow, 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5); - } @else { - box-shadow: 0 0 0 $btn-focus-width rgba(mix(color-yiq($background), $border, 15%), .5); - } - } - } -} - -@mixin button-outline-variant($color, $color-hover: color-yiq($color), $active-background: $color, $active-border: $color) { - color: $color; - border-color: $color; - - @include hover { - color: $color-hover; - background-color: $active-background; - border-color: $active-border; - } - - &:focus, - &.focus { - box-shadow: 0 0 0 $btn-focus-width rgba($color, .5); - } - - &.disabled, - &:disabled { - color: $color; - background-color: transparent; - } - - &:not(:disabled):not(.disabled):active, - &:not(:disabled):not(.disabled).active, - .show > &.dropdown-toggle { - color: color-yiq($active-background); - background-color: $active-background; - border-color: $active-border; - - &:focus { - // Avoid using mixin so we can pass custom focus shadow properly - @if $enable-shadows and $btn-active-box-shadow != none { - box-shadow: $btn-active-box-shadow, 0 0 0 $btn-focus-width rgba($color, .5); - } @else { - box-shadow: 0 0 0 $btn-focus-width rgba($color, .5); - } - } - } -} - -// Button sizes -@mixin button-size($padding-y, $padding-x, $font-size, $line-height, $border-radius) { - padding: $padding-y $padding-x; - font-size: $font-size; - line-height: $line-height; - // Manually declare to provide an override to the browser default - @if $enable-rounded { - border-radius: $border-radius; - } @else { - border-radius: 0; - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_caret.scss b/scss/node_modules/bootstrap/scss/mixins/_caret.scss deleted file mode 100644 index 982522c..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_caret.scss +++ /dev/null @@ -1,62 +0,0 @@ -@mixin caret-down { - border-top: $caret-width solid; - border-right: $caret-width solid transparent; - border-bottom: 0; - border-left: $caret-width solid transparent; -} - -@mixin caret-up { - border-top: 0; - border-right: $caret-width solid transparent; - border-bottom: $caret-width solid; - border-left: $caret-width solid transparent; -} - -@mixin caret-right { - border-top: $caret-width solid transparent; - border-right: 0; - border-bottom: $caret-width solid transparent; - border-left: $caret-width solid; -} - -@mixin caret-left { - border-top: $caret-width solid transparent; - border-right: $caret-width solid; - border-bottom: $caret-width solid transparent; -} - -@mixin caret($direction: down) { - @if $enable-caret { - &::after { - display: inline-block; - margin-left: $caret-width * .85; - vertical-align: $caret-width * .85; - content: ""; - @if $direction == down { - @include caret-down; - } @else if $direction == up { - @include caret-up; - } @else if $direction == right { - @include caret-right; - } - } - - @if $direction == left { - &::after { - display: none; - } - - &::before { - display: inline-block; - margin-right: $caret-width * .85; - vertical-align: $caret-width * .85; - content: ""; - @include caret-left; - } - } - - &:empty::after { - margin-left: 0; - } - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_clearfix.scss b/scss/node_modules/bootstrap/scss/mixins/_clearfix.scss deleted file mode 100644 index 11a977b..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_clearfix.scss +++ /dev/null @@ -1,7 +0,0 @@ -@mixin clearfix() { - &::after { - display: block; - clear: both; - content: ""; - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_float.scss b/scss/node_modules/bootstrap/scss/mixins/_float.scss deleted file mode 100644 index 48fa8b6..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_float.scss +++ /dev/null @@ -1,11 +0,0 @@ -// stylelint-disable declaration-no-important - -@mixin float-left { - float: left !important; -} -@mixin float-right { - float: right !important; -} -@mixin float-none { - float: none !important; -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_forms.scss b/scss/node_modules/bootstrap/scss/mixins/_forms.scss deleted file mode 100644 index b8eb59d..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_forms.scss +++ /dev/null @@ -1,198 +0,0 @@ -// Form control focus state -// -// Generate a customized focus state and for any input with the specified color, -// which defaults to the `$input-focus-border-color` variable. -// -// We highly encourage you to not customize the default value, but instead use -// this to tweak colors on an as-needed basis. This aesthetic change is based on -// WebKit's default styles, but applicable to a wider range of browsers. Its -// usability and accessibility should be taken into account with any change. -// -// Example usage: change the default blue border and shadow to white for better -// contrast against a dark gray background. -@mixin form-control-focus() { - &:focus { - color: $input-focus-color; - background-color: $input-focus-bg; - border-color: $input-focus-border-color; - outline: 0; - // Avoid using mixin so we can pass custom focus shadow properly - @if $enable-shadows { - box-shadow: $input-box-shadow, $input-focus-box-shadow; - } @else { - box-shadow: $input-focus-box-shadow; - } - } -} - - -@mixin form-validation-state($state, $color) { - .#{$state}-feedback { - display: none; - width: 100%; - margin-top: $form-feedback-margin-top; - font-size: $form-feedback-font-size; - color: $color; - } - - .#{$state}-tooltip { - position: absolute; - top: 100%; - z-index: 5; - display: none; - max-width: 100%; // Contain to parent when possible - padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x; - margin-top: .1rem; - font-size: $form-feedback-tooltip-font-size; - line-height: $form-feedback-tooltip-line-height; - color: color-yiq($color); - background-color: rgba($color, $form-feedback-tooltip-opacity); - @include border-radius($form-feedback-tooltip-border-radius); - } - - .form-control { - .was-validated &:#{$state}, - &.is-#{$state} { - border-color: $color; - - @if $enable-validation-icons { - padding-right: $input-height-inner; - background-repeat: no-repeat; - background-position: center right calc(#{$input-height-inner} / 4); - background-size: calc(#{$input-height-inner} / 2) calc(#{$input-height-inner} / 2); - - @if $state == "valid" { - background-image: $form-feedback-icon-valid; - } @else { - background-image: $form-feedback-icon-invalid; - } - } - - &:focus { - border-color: $color; - box-shadow: 0 0 0 $input-focus-width rgba($color, .25); - } - - ~ .#{$state}-feedback, - ~ .#{$state}-tooltip { - display: block; - } - } - } - - // stylelint-disable-next-line selector-no-qualifying-type - textarea.form-control { - .was-validated &:#{$state}, - &.is-#{$state} { - @if $enable-validation-icons { - padding-right: $input-height-inner; - background-position: top calc(#{$input-height-inner} / 4) right calc(#{$input-height-inner} / 4); - } - } - } - - .custom-select { - .was-validated &:#{$state}, - &.is-#{$state} { - border-color: $color; - - @if $enable-validation-icons { - $form-feedback-icon: if($state == "valid", $form-feedback-icon-valid, $form-feedback-icon-invalid); - padding-right: $custom-select-feedback-icon-padding-right; - background: $custom-select-background, $form-feedback-icon no-repeat $custom-select-feedback-icon-position / $custom-select-feedback-icon-size; - } - - &:focus { - border-color: $color; - box-shadow: 0 0 0 $input-focus-width rgba($color, .25); - } - - ~ .#{$state}-feedback, - ~ .#{$state}-tooltip { - display: block; - } - } - } - - - .form-control-file { - .was-validated &:#{$state}, - &.is-#{$state} { - ~ .#{$state}-feedback, - ~ .#{$state}-tooltip { - display: block; - } - } - } - - .form-check-input { - .was-validated &:#{$state}, - &.is-#{$state} { - ~ .form-check-label { - color: $color; - } - - ~ .#{$state}-feedback, - ~ .#{$state}-tooltip { - display: block; - } - } - } - - .custom-control-input { - .was-validated &:#{$state}, - &.is-#{$state} { - ~ .custom-control-label { - color: $color; - - &::before { - border-color: $color; - } - } - - ~ .#{$state}-feedback, - ~ .#{$state}-tooltip { - display: block; - } - - &:checked { - ~ .custom-control-label::before { - border-color: lighten($color, 10%); - @include gradient-bg(lighten($color, 10%)); - } - } - - &:focus { - ~ .custom-control-label::before { - box-shadow: 0 0 0 $input-focus-width rgba($color, .25); - } - - &:not(:checked) ~ .custom-control-label::before { - border-color: $color; - } - } - } - } - - // custom file - .custom-file-input { - .was-validated &:#{$state}, - &.is-#{$state} { - ~ .custom-file-label { - border-color: $color; - } - - ~ .#{$state}-feedback, - ~ .#{$state}-tooltip { - display: block; - } - - &:focus { - ~ .custom-file-label { - border-color: $color; - box-shadow: 0 0 0 $input-focus-width rgba($color, .25); - } - } - } - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_gradients.scss b/scss/node_modules/bootstrap/scss/mixins/_gradients.scss deleted file mode 100644 index 88c4d64..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_gradients.scss +++ /dev/null @@ -1,45 +0,0 @@ -// Gradients - -@mixin gradient-bg($color) { - @if $enable-gradients { - background: $color linear-gradient(180deg, mix($body-bg, $color, 15%), $color) repeat-x; - } @else { - background-color: $color; - } -} - -// Horizontal gradient, from left to right -// -// Creates two color stops, start and end, by specifying a color and position for each color stop. -@mixin gradient-x($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) { - background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent); - background-repeat: repeat-x; -} - -// Vertical gradient, from top to bottom -// -// Creates two color stops, start and end, by specifying a color and position for each color stop. -@mixin gradient-y($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) { - background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); - background-repeat: repeat-x; -} - -@mixin gradient-directional($start-color: $gray-700, $end-color: $gray-800, $deg: 45deg) { - background-image: linear-gradient($deg, $start-color, $end-color); - background-repeat: repeat-x; -} -@mixin gradient-x-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { - background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color); - background-repeat: no-repeat; -} -@mixin gradient-y-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { - background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color); - background-repeat: no-repeat; -} -@mixin gradient-radial($inner-color: $gray-700, $outer-color: $gray-800) { - background-image: radial-gradient(circle, $inner-color, $outer-color); - background-repeat: no-repeat; -} -@mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) { - background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent); -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_grid-framework.scss b/scss/node_modules/bootstrap/scss/mixins/_grid-framework.scss deleted file mode 100644 index 649c28b..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_grid-framework.scss +++ /dev/null @@ -1,66 +0,0 @@ -// Framework grid generation -// -// Used only by Bootstrap to generate the correct number of grid classes given -// any value of `$grid-columns`. - -@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) { - // Common properties for all breakpoints - %grid-column { - position: relative; - width: 100%; - padding-right: $gutter / 2; - padding-left: $gutter / 2; - } - - @each $breakpoint in map-keys($breakpoints) { - $infix: breakpoint-infix($breakpoint, $breakpoints); - - // Allow columns to stretch full width below their breakpoints - @for $i from 1 through $columns { - .col#{$infix}-#{$i} { - @extend %grid-column; - } - } - .col#{$infix}, - .col#{$infix}-auto { - @extend %grid-column; - } - - @include media-breakpoint-up($breakpoint, $breakpoints) { - // Provide basic `.col-{bp}` classes for equal-width flexbox columns - .col#{$infix} { - flex-basis: 0; - flex-grow: 1; - max-width: 100%; - } - .col#{$infix}-auto { - flex: 0 0 auto; - width: auto; - max-width: 100%; // Reset earlier grid tiers - } - - @for $i from 1 through $columns { - .col#{$infix}-#{$i} { - @include make-col($i, $columns); - } - } - - .order#{$infix}-first { order: -1; } - - .order#{$infix}-last { order: $columns + 1; } - - @for $i from 0 through $columns { - .order#{$infix}-#{$i} { order: $i; } - } - - // `$columns - 1` because offsetting by the width of an entire row isn't possible - @for $i from 0 through ($columns - 1) { - @if not ($infix == "" and $i == 0) { // Avoid emitting useless .offset-0 - .offset#{$infix}-#{$i} { - @include make-col-offset($i, $columns); - } - } - } - } - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_grid.scss b/scss/node_modules/bootstrap/scss/mixins/_grid.scss deleted file mode 100644 index 924eb0c..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_grid.scss +++ /dev/null @@ -1,51 +0,0 @@ -/// Grid system -// -// Generate semantic grid columns with these mixins. - -@mixin make-container($gutter: $grid-gutter-width) { - width: 100%; - padding-right: $gutter / 2; - padding-left: $gutter / 2; - margin-right: auto; - margin-left: auto; -} - - -// For each breakpoint, define the maximum width of the container in a media query -@mixin make-container-max-widths($max-widths: $container-max-widths, $breakpoints: $grid-breakpoints) { - @each $breakpoint, $container-max-width in $max-widths { - @include media-breakpoint-up($breakpoint, $breakpoints) { - max-width: $container-max-width; - } - } -} - -@mixin make-row($gutter: $grid-gutter-width) { - display: flex; - flex-wrap: wrap; - margin-right: -$gutter / 2; - margin-left: -$gutter / 2; -} - -@mixin make-col-ready($gutter: $grid-gutter-width) { - position: relative; - // Prevent columns from becoming too narrow when at smaller grid tiers by - // always setting `width: 100%;`. This works because we use `flex` values - // later on to override this initial width. - width: 100%; - padding-right: $gutter / 2; - padding-left: $gutter / 2; -} - -@mixin make-col($size, $columns: $grid-columns) { - flex: 0 0 percentage($size / $columns); - // Add a `max-width` to ensure content within each column does not blow out - // the width of the column. Applies to IE10+ and Firefox. Chrome and Safari - // do not appear to require this. - max-width: percentage($size / $columns); -} - -@mixin make-col-offset($size, $columns: $grid-columns) { - $num: $size / $columns; - margin-left: if($num == 0, 0, percentage($num)); -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_hover.scss b/scss/node_modules/bootstrap/scss/mixins/_hover.scss deleted file mode 100644 index 192f847..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_hover.scss +++ /dev/null @@ -1,37 +0,0 @@ -// Hover mixin and `$enable-hover-media-query` are deprecated. -// -// Originally added during our alphas and maintained during betas, this mixin was -// designed to prevent `:hover` stickiness on iOS-an issue where hover styles -// would persist after initial touch. -// -// For backward compatibility, we've kept these mixins and updated them to -// always return their regular pseudo-classes instead of a shimmed media query. -// -// Issue: https://github.com/twbs/bootstrap/issues/25195 - -@mixin hover { - &:hover { @content; } -} - -@mixin hover-focus { - &:hover, - &:focus { - @content; - } -} - -@mixin plain-hover-focus { - &, - &:hover, - &:focus { - @content; - } -} - -@mixin hover-focus-active { - &:hover, - &:focus, - &:active { - @content; - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_image.scss b/scss/node_modules/bootstrap/scss/mixins/_image.scss deleted file mode 100644 index 0544f0d..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_image.scss +++ /dev/null @@ -1,36 +0,0 @@ -// Image Mixins -// - Responsive image -// - Retina image - - -// Responsive image -// -// Keep images from scaling beyond the width of their parents. - -@mixin img-fluid { - // Part 1: Set a maximum relative to the parent - max-width: 100%; - // Part 2: Override the height to auto, otherwise images will be stretched - // when setting a width and height attribute on the img element. - height: auto; -} - - -// Retina image -// -// Short retina mixin for setting background-image and -size. - -// stylelint-disable indentation, media-query-list-comma-newline-after -@mixin img-retina($file-1x, $file-2x, $width-1x, $height-1x) { - background-image: url($file-1x); - - // Autoprefixer takes care of adding -webkit-min-device-pixel-ratio and -o-min-device-pixel-ratio, - // but doesn't convert dppx=>dpi. - // There's no such thing as unprefixed min-device-pixel-ratio since it's nonstandard. - // Compatibility info: https://caniuse.com/#feat=css-media-resolution - @media only screen and (min-resolution: 192dpi), // IE9-11 don't support dppx - only screen and (min-resolution: 2dppx) { // Standardized - background-image: url($file-2x); - background-size: $width-1x $height-1x; - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_list-group.scss b/scss/node_modules/bootstrap/scss/mixins/_list-group.scss deleted file mode 100644 index cd47a4e..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_list-group.scss +++ /dev/null @@ -1,21 +0,0 @@ -// List Groups - -@mixin list-group-item-variant($state, $background, $color) { - .list-group-item-#{$state} { - color: $color; - background-color: $background; - - &.list-group-item-action { - @include hover-focus { - color: $color; - background-color: darken($background, 5%); - } - - &.active { - color: $white; - background-color: $color; - border-color: $color; - } - } - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_lists.scss b/scss/node_modules/bootstrap/scss/mixins/_lists.scss deleted file mode 100644 index 2518562..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_lists.scss +++ /dev/null @@ -1,7 +0,0 @@ -// Lists - -// Unstyled keeps list items block level, just removes default browser padding and list-style -@mixin list-unstyled { - padding-left: 0; - list-style: none; -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_nav-divider.scss b/scss/node_modules/bootstrap/scss/mixins/_nav-divider.scss deleted file mode 100644 index 4fb37b6..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_nav-divider.scss +++ /dev/null @@ -1,10 +0,0 @@ -// Horizontal dividers -// -// Dividers (basically an hr) within dropdowns and nav lists - -@mixin nav-divider($color: $nav-divider-color, $margin-y: $nav-divider-margin-y) { - height: 0; - margin: $margin-y 0; - overflow: hidden; - border-top: 1px solid $color; -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_pagination.scss b/scss/node_modules/bootstrap/scss/mixins/_pagination.scss deleted file mode 100644 index ff36eb6..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_pagination.scss +++ /dev/null @@ -1,22 +0,0 @@ -// Pagination - -@mixin pagination-size($padding-y, $padding-x, $font-size, $line-height, $border-radius) { - .page-link { - padding: $padding-y $padding-x; - font-size: $font-size; - line-height: $line-height; - } - - .page-item { - &:first-child { - .page-link { - @include border-left-radius($border-radius); - } - } - &:last-child { - .page-link { - @include border-right-radius($border-radius); - } - } - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_reset-text.scss b/scss/node_modules/bootstrap/scss/mixins/_reset-text.scss deleted file mode 100644 index 71edb00..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_reset-text.scss +++ /dev/null @@ -1,17 +0,0 @@ -@mixin reset-text { - font-family: $font-family-base; - // We deliberately do NOT reset font-size or word-wrap. - font-style: normal; - font-weight: $font-weight-normal; - line-height: $line-height-base; - text-align: left; // Fallback for where `start` is not supported - text-align: start; // stylelint-disable-line declaration-block-no-duplicate-properties - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-break: normal; - word-spacing: normal; - white-space: normal; - line-break: auto; -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_resize.scss b/scss/node_modules/bootstrap/scss/mixins/_resize.scss deleted file mode 100644 index 66f233a..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_resize.scss +++ /dev/null @@ -1,6 +0,0 @@ -// Resize anything - -@mixin resizable($direction) { - overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` - resize: $direction; // Options: horizontal, vertical, both -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_screen-reader.scss b/scss/node_modules/bootstrap/scss/mixins/_screen-reader.scss deleted file mode 100644 index 812591b..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_screen-reader.scss +++ /dev/null @@ -1,33 +0,0 @@ -// Only display content to screen readers -// -// See: https://a11yproject.com/posts/how-to-hide-content/ -// See: https://hugogiraudel.com/2016/10/13/css-hide-and-seek/ - -@mixin sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - overflow: hidden; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border: 0; -} - -// Use in conjunction with .sr-only to only display content when it's focused. -// -// Useful for "Skip to main content" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1 -// -// Credit: HTML5 Boilerplate - -@mixin sr-only-focusable { - &:active, - &:focus { - position: static; - width: auto; - height: auto; - overflow: visible; - clip: auto; - white-space: normal; - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_size.scss b/scss/node_modules/bootstrap/scss/mixins/_size.scss deleted file mode 100644 index b9dd48e..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_size.scss +++ /dev/null @@ -1,6 +0,0 @@ -// Sizing shortcuts - -@mixin size($width, $height: $width) { - width: $width; - height: $height; -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_table-row.scss b/scss/node_modules/bootstrap/scss/mixins/_table-row.scss deleted file mode 100644 index f8d6186..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_table-row.scss +++ /dev/null @@ -1,39 +0,0 @@ -// Tables - -@mixin table-row-variant($state, $background, $border: null) { - // Exact selectors below required to override `.table-striped` and prevent - // inheritance to nested tables. - .table-#{$state} { - &, - > th, - > td { - background-color: $background; - } - - @if $border != null { - th, - td, - thead th, - tbody + tbody { - border-color: $border; - } - } - } - - // Hover states for `.table-hover` - // Note: this is not available for cells or rows within `thead` or `tfoot`. - .table-hover { - $hover-background: darken($background, 5%); - - .table-#{$state} { - @include hover { - background-color: $hover-background; - - > td, - > th { - background-color: $hover-background; - } - } - } - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_text-emphasis.scss b/scss/node_modules/bootstrap/scss/mixins/_text-emphasis.scss deleted file mode 100644 index 1819fb0..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_text-emphasis.scss +++ /dev/null @@ -1,14 +0,0 @@ -// stylelint-disable declaration-no-important - -// Typography - -@mixin text-emphasis-variant($parent, $color) { - #{$parent} { - color: $color !important; - } - a#{$parent} { - @include hover-focus { - color: darken($color, $emphasized-link-hover-darken-percentage) !important; - } - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_text-hide.scss b/scss/node_modules/bootstrap/scss/mixins/_text-hide.scss deleted file mode 100644 index 9ffab16..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_text-hide.scss +++ /dev/null @@ -1,13 +0,0 @@ -// CSS image replacement -@mixin text-hide($ignore-warning: false) { - // stylelint-disable-next-line font-family-no-missing-generic-family-keyword - font: 0/0 a; - color: transparent; - text-shadow: none; - background-color: transparent; - border: 0; - - @if ($ignore-warning != true) { - @warn "The `text-hide()` mixin has been deprecated as of v4.1.0. It will be removed entirely in v5."; - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_text-truncate.scss b/scss/node_modules/bootstrap/scss/mixins/_text-truncate.scss deleted file mode 100644 index 3504bb1..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_text-truncate.scss +++ /dev/null @@ -1,8 +0,0 @@ -// Text truncate -// Requires inline-block or block for proper styling - -@mixin text-truncate() { - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_transition.scss b/scss/node_modules/bootstrap/scss/mixins/_transition.scss deleted file mode 100644 index 485f76c..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_transition.scss +++ /dev/null @@ -1,16 +0,0 @@ -// stylelint-disable property-blacklist -@mixin transition($transition...) { - @if $enable-transitions { - @if length($transition) == 0 { - transition: $transition-base; - } @else { - transition: $transition; - } - } - - @if $enable-prefers-reduced-motion-media-query { - @media screen and (prefers-reduced-motion: reduce) { - transition: none; - } - } -} diff --git a/scss/node_modules/bootstrap/scss/mixins/_visibility.scss b/scss/node_modules/bootstrap/scss/mixins/_visibility.scss deleted file mode 100644 index fe523d0..0000000 --- a/scss/node_modules/bootstrap/scss/mixins/_visibility.scss +++ /dev/null @@ -1,7 +0,0 @@ -// stylelint-disable declaration-no-important - -// Visibility - -@mixin invisible($visibility) { - visibility: $visibility !important; -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_align.scss b/scss/node_modules/bootstrap/scss/utilities/_align.scss deleted file mode 100644 index 8b7df9f..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_align.scss +++ /dev/null @@ -1,8 +0,0 @@ -// stylelint-disable declaration-no-important - -.align-baseline { vertical-align: baseline !important; } // Browser default -.align-top { vertical-align: top !important; } -.align-middle { vertical-align: middle !important; } -.align-bottom { vertical-align: bottom !important; } -.align-text-bottom { vertical-align: text-bottom !important; } -.align-text-top { vertical-align: text-top !important; } diff --git a/scss/node_modules/bootstrap/scss/utilities/_background.scss b/scss/node_modules/bootstrap/scss/utilities/_background.scss deleted file mode 100644 index 1f18b2f..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_background.scss +++ /dev/null @@ -1,19 +0,0 @@ -// stylelint-disable declaration-no-important - -@each $color, $value in $theme-colors { - @include bg-variant(".bg-#{$color}", $value); -} - -@if $enable-gradients { - @each $color, $value in $theme-colors { - @include bg-gradient-variant(".bg-gradient-#{$color}", $value); - } -} - -.bg-white { - background-color: $white !important; -} - -.bg-transparent { - background-color: transparent !important; -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_borders.scss b/scss/node_modules/bootstrap/scss/utilities/_borders.scss deleted file mode 100644 index fb759c9..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_borders.scss +++ /dev/null @@ -1,63 +0,0 @@ -// stylelint-disable declaration-no-important - -// -// Border -// - -.border { border: $border-width solid $border-color !important; } -.border-top { border-top: $border-width solid $border-color !important; } -.border-right { border-right: $border-width solid $border-color !important; } -.border-bottom { border-bottom: $border-width solid $border-color !important; } -.border-left { border-left: $border-width solid $border-color !important; } - -.border-0 { border: 0 !important; } -.border-top-0 { border-top: 0 !important; } -.border-right-0 { border-right: 0 !important; } -.border-bottom-0 { border-bottom: 0 !important; } -.border-left-0 { border-left: 0 !important; } - -@each $color, $value in $theme-colors { - .border-#{$color} { - border-color: $value !important; - } -} - -.border-white { - border-color: $white !important; -} - -// -// Border-radius -// - -.rounded { - border-radius: $border-radius !important; -} -.rounded-top { - border-top-left-radius: $border-radius !important; - border-top-right-radius: $border-radius !important; -} -.rounded-right { - border-top-right-radius: $border-radius !important; - border-bottom-right-radius: $border-radius !important; -} -.rounded-bottom { - border-bottom-right-radius: $border-radius !important; - border-bottom-left-radius: $border-radius !important; -} -.rounded-left { - border-top-left-radius: $border-radius !important; - border-bottom-left-radius: $border-radius !important; -} - -.rounded-circle { - border-radius: 50% !important; -} - -.rounded-pill { - border-radius: $rounded-pill !important; -} - -.rounded-0 { - border-radius: 0 !important; -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_clearfix.scss b/scss/node_modules/bootstrap/scss/utilities/_clearfix.scss deleted file mode 100644 index e92522a..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_clearfix.scss +++ /dev/null @@ -1,3 +0,0 @@ -.clearfix { - @include clearfix(); -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_display.scss b/scss/node_modules/bootstrap/scss/utilities/_display.scss deleted file mode 100644 index 20aeeb5..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_display.scss +++ /dev/null @@ -1,38 +0,0 @@ -// stylelint-disable declaration-no-important - -// -// Utilities for common `display` values -// - -@each $breakpoint in map-keys($grid-breakpoints) { - @include media-breakpoint-up($breakpoint) { - $infix: breakpoint-infix($breakpoint, $grid-breakpoints); - - .d#{$infix}-none { display: none !important; } - .d#{$infix}-inline { display: inline !important; } - .d#{$infix}-inline-block { display: inline-block !important; } - .d#{$infix}-block { display: block !important; } - .d#{$infix}-table { display: table !important; } - .d#{$infix}-table-row { display: table-row !important; } - .d#{$infix}-table-cell { display: table-cell !important; } - .d#{$infix}-flex { display: flex !important; } - .d#{$infix}-inline-flex { display: inline-flex !important; } - } -} - - -// -// Utilities for toggling `display` in print -// - -@media print { - .d-print-none { display: none !important; } - .d-print-inline { display: inline !important; } - .d-print-inline-block { display: inline-block !important; } - .d-print-block { display: block !important; } - .d-print-table { display: table !important; } - .d-print-table-row { display: table-row !important; } - .d-print-table-cell { display: table-cell !important; } - .d-print-flex { display: flex !important; } - .d-print-inline-flex { display: inline-flex !important; } -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_embed.scss b/scss/node_modules/bootstrap/scss/utilities/_embed.scss deleted file mode 100644 index 4497ac0..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_embed.scss +++ /dev/null @@ -1,39 +0,0 @@ -// Credit: Nicolas Gallagher and SUIT CSS. - -.embed-responsive { - position: relative; - display: block; - width: 100%; - padding: 0; - overflow: hidden; - - &::before { - display: block; - content: ""; - } - - .embed-responsive-item, - iframe, - embed, - object, - video { - position: absolute; - top: 0; - bottom: 0; - left: 0; - width: 100%; - height: 100%; - border: 0; - } -} - -@each $embed-responsive-aspect-ratio in $embed-responsive-aspect-ratios { - $embed-responsive-aspect-ratio-x: nth($embed-responsive-aspect-ratio, 1); - $embed-responsive-aspect-ratio-y: nth($embed-responsive-aspect-ratio, 2); - - .embed-responsive-#{$embed-responsive-aspect-ratio-x}by#{$embed-responsive-aspect-ratio-y} { - &::before { - padding-top: percentage($embed-responsive-aspect-ratio-y / $embed-responsive-aspect-ratio-x); - } - } -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_flex.scss b/scss/node_modules/bootstrap/scss/utilities/_flex.scss deleted file mode 100644 index 3d4266e..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_flex.scss +++ /dev/null @@ -1,51 +0,0 @@ -// stylelint-disable declaration-no-important - -// Flex variation -// -// Custom styles for additional flex alignment options. - -@each $breakpoint in map-keys($grid-breakpoints) { - @include media-breakpoint-up($breakpoint) { - $infix: breakpoint-infix($breakpoint, $grid-breakpoints); - - .flex#{$infix}-row { flex-direction: row !important; } - .flex#{$infix}-column { flex-direction: column !important; } - .flex#{$infix}-row-reverse { flex-direction: row-reverse !important; } - .flex#{$infix}-column-reverse { flex-direction: column-reverse !important; } - - .flex#{$infix}-wrap { flex-wrap: wrap !important; } - .flex#{$infix}-nowrap { flex-wrap: nowrap !important; } - .flex#{$infix}-wrap-reverse { flex-wrap: wrap-reverse !important; } - .flex#{$infix}-fill { flex: 1 1 auto !important; } - .flex#{$infix}-grow-0 { flex-grow: 0 !important; } - .flex#{$infix}-grow-1 { flex-grow: 1 !important; } - .flex#{$infix}-shrink-0 { flex-shrink: 0 !important; } - .flex#{$infix}-shrink-1 { flex-shrink: 1 !important; } - - .justify-content#{$infix}-start { justify-content: flex-start !important; } - .justify-content#{$infix}-end { justify-content: flex-end !important; } - .justify-content#{$infix}-center { justify-content: center !important; } - .justify-content#{$infix}-between { justify-content: space-between !important; } - .justify-content#{$infix}-around { justify-content: space-around !important; } - - .align-items#{$infix}-start { align-items: flex-start !important; } - .align-items#{$infix}-end { align-items: flex-end !important; } - .align-items#{$infix}-center { align-items: center !important; } - .align-items#{$infix}-baseline { align-items: baseline !important; } - .align-items#{$infix}-stretch { align-items: stretch !important; } - - .align-content#{$infix}-start { align-content: flex-start !important; } - .align-content#{$infix}-end { align-content: flex-end !important; } - .align-content#{$infix}-center { align-content: center !important; } - .align-content#{$infix}-between { align-content: space-between !important; } - .align-content#{$infix}-around { align-content: space-around !important; } - .align-content#{$infix}-stretch { align-content: stretch !important; } - - .align-self#{$infix}-auto { align-self: auto !important; } - .align-self#{$infix}-start { align-self: flex-start !important; } - .align-self#{$infix}-end { align-self: flex-end !important; } - .align-self#{$infix}-center { align-self: center !important; } - .align-self#{$infix}-baseline { align-self: baseline !important; } - .align-self#{$infix}-stretch { align-self: stretch !important; } - } -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_float.scss b/scss/node_modules/bootstrap/scss/utilities/_float.scss deleted file mode 100644 index 01655e9..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_float.scss +++ /dev/null @@ -1,9 +0,0 @@ -@each $breakpoint in map-keys($grid-breakpoints) { - @include media-breakpoint-up($breakpoint) { - $infix: breakpoint-infix($breakpoint, $grid-breakpoints); - - .float#{$infix}-left { @include float-left; } - .float#{$infix}-right { @include float-right; } - .float#{$infix}-none { @include float-none; } - } -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_overflow.scss b/scss/node_modules/bootstrap/scss/utilities/_overflow.scss deleted file mode 100644 index 8326c30..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_overflow.scss +++ /dev/null @@ -1,5 +0,0 @@ -// stylelint-disable declaration-no-important - -@each $value in $overflows { - .overflow-#{$value} { overflow: $value !important; } -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_position.scss b/scss/node_modules/bootstrap/scss/utilities/_position.scss deleted file mode 100644 index cdf6c11..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_position.scss +++ /dev/null @@ -1,32 +0,0 @@ -// stylelint-disable declaration-no-important - -// Common values -@each $position in $positions { - .position-#{$position} { position: $position !important; } -} - -// Shorthand - -.fixed-top { - position: fixed; - top: 0; - right: 0; - left: 0; - z-index: $zindex-fixed; -} - -.fixed-bottom { - position: fixed; - right: 0; - bottom: 0; - left: 0; - z-index: $zindex-fixed; -} - -.sticky-top { - @supports (position: sticky) { - position: sticky; - top: 0; - z-index: $zindex-sticky; - } -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_screenreaders.scss b/scss/node_modules/bootstrap/scss/utilities/_screenreaders.scss deleted file mode 100644 index 9f26fde..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_screenreaders.scss +++ /dev/null @@ -1,11 +0,0 @@ -// -// Screenreaders -// - -.sr-only { - @include sr-only(); -} - -.sr-only-focusable { - @include sr-only-focusable(); -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_shadows.scss b/scss/node_modules/bootstrap/scss/utilities/_shadows.scss deleted file mode 100644 index f5d03fc..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_shadows.scss +++ /dev/null @@ -1,6 +0,0 @@ -// stylelint-disable declaration-no-important - -.shadow-sm { box-shadow: $box-shadow-sm !important; } -.shadow { box-shadow: $box-shadow !important; } -.shadow-lg { box-shadow: $box-shadow-lg !important; } -.shadow-none { box-shadow: none !important; } diff --git a/scss/node_modules/bootstrap/scss/utilities/_sizing.scss b/scss/node_modules/bootstrap/scss/utilities/_sizing.scss deleted file mode 100644 index f376488..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_sizing.scss +++ /dev/null @@ -1,20 +0,0 @@ -// stylelint-disable declaration-no-important - -// Width and height - -@each $prop, $abbrev in (width: w, height: h) { - @each $size, $length in $sizes { - .#{$abbrev}-#{$size} { #{$prop}: $length !important; } - } -} - -.mw-100 { max-width: 100% !important; } -.mh-100 { max-height: 100% !important; } - -// Viewport additional helpers - -.min-vw-100 { min-width: 100vw !important; } -.min-vh-100 { min-height: 100vh !important; } - -.vw-100 { width: 100vw !important; } -.vh-100 { height: 100vh !important; } diff --git a/scss/node_modules/bootstrap/scss/utilities/_spacing.scss b/scss/node_modules/bootstrap/scss/utilities/_spacing.scss deleted file mode 100644 index 3511367..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_spacing.scss +++ /dev/null @@ -1,73 +0,0 @@ -// stylelint-disable declaration-no-important - -// Margin and Padding - -@each $breakpoint in map-keys($grid-breakpoints) { - @include media-breakpoint-up($breakpoint) { - $infix: breakpoint-infix($breakpoint, $grid-breakpoints); - - @each $prop, $abbrev in (margin: m, padding: p) { - @each $size, $length in $spacers { - .#{$abbrev}#{$infix}-#{$size} { #{$prop}: $length !important; } - .#{$abbrev}t#{$infix}-#{$size}, - .#{$abbrev}y#{$infix}-#{$size} { - #{$prop}-top: $length !important; - } - .#{$abbrev}r#{$infix}-#{$size}, - .#{$abbrev}x#{$infix}-#{$size} { - #{$prop}-right: $length !important; - } - .#{$abbrev}b#{$infix}-#{$size}, - .#{$abbrev}y#{$infix}-#{$size} { - #{$prop}-bottom: $length !important; - } - .#{$abbrev}l#{$infix}-#{$size}, - .#{$abbrev}x#{$infix}-#{$size} { - #{$prop}-left: $length !important; - } - } - } - - // Negative margins (e.g., where `.mb-n1` is negative version of `.mb-1`) - @each $size, $length in $spacers { - @if $size != 0 { - .m#{$infix}-n#{$size} { margin: -$length !important; } - .mt#{$infix}-n#{$size}, - .my#{$infix}-n#{$size} { - margin-top: -$length !important; - } - .mr#{$infix}-n#{$size}, - .mx#{$infix}-n#{$size} { - margin-right: -$length !important; - } - .mb#{$infix}-n#{$size}, - .my#{$infix}-n#{$size} { - margin-bottom: -$length !important; - } - .ml#{$infix}-n#{$size}, - .mx#{$infix}-n#{$size} { - margin-left: -$length !important; - } - } - } - - // Some special margin utils - .m#{$infix}-auto { margin: auto !important; } - .mt#{$infix}-auto, - .my#{$infix}-auto { - margin-top: auto !important; - } - .mr#{$infix}-auto, - .mx#{$infix}-auto { - margin-right: auto !important; - } - .mb#{$infix}-auto, - .my#{$infix}-auto { - margin-bottom: auto !important; - } - .ml#{$infix}-auto, - .mx#{$infix}-auto { - margin-left: auto !important; - } - } -} diff --git a/scss/node_modules/bootstrap/scss/utilities/_text.scss b/scss/node_modules/bootstrap/scss/utilities/_text.scss deleted file mode 100644 index 0edb8e5..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_text.scss +++ /dev/null @@ -1,67 +0,0 @@ -// stylelint-disable declaration-no-important - -// -// Text -// - -.text-monospace { font-family: $font-family-monospace; } - -// Alignment - -.text-justify { text-align: justify !important; } -.text-wrap { white-space: normal !important; } -.text-nowrap { white-space: nowrap !important; } -.text-truncate { @include text-truncate; } - -// Responsive alignment - -@each $breakpoint in map-keys($grid-breakpoints) { - @include media-breakpoint-up($breakpoint) { - $infix: breakpoint-infix($breakpoint, $grid-breakpoints); - - .text#{$infix}-left { text-align: left !important; } - .text#{$infix}-right { text-align: right !important; } - .text#{$infix}-center { text-align: center !important; } - } -} - -// Transformation - -.text-lowercase { text-transform: lowercase !important; } -.text-uppercase { text-transform: uppercase !important; } -.text-capitalize { text-transform: capitalize !important; } - -// Weight and italics - -.font-weight-light { font-weight: $font-weight-light !important; } -.font-weight-lighter { font-weight: $font-weight-lighter !important; } -.font-weight-normal { font-weight: $font-weight-normal !important; } -.font-weight-bold { font-weight: $font-weight-bold !important; } -.font-weight-bolder { font-weight: $font-weight-bolder !important; } -.font-italic { font-style: italic !important; } - -// Contextual colors - -.text-white { color: $white !important; } - -@each $color, $value in $theme-colors { - @include text-emphasis-variant(".text-#{$color}", $value); -} - -.text-body { color: $body-color !important; } -.text-muted { color: $text-muted !important; } - -.text-black-50 { color: rgba($black, .5) !important; } -.text-white-50 { color: rgba($white, .5) !important; } - -// Misc - -.text-hide { - @include text-hide($ignore-warning: true); -} - -.text-decoration-none { text-decoration: none !important; } - -// Reset - -.text-reset { color: inherit !important; } diff --git a/scss/node_modules/bootstrap/scss/utilities/_visibility.scss b/scss/node_modules/bootstrap/scss/utilities/_visibility.scss deleted file mode 100644 index 823406d..0000000 --- a/scss/node_modules/bootstrap/scss/utilities/_visibility.scss +++ /dev/null @@ -1,11 +0,0 @@ -// -// Visibility utilities -// - -.visible { - @include invisible(visible); -} - -.invisible { - @include invisible(hidden); -} From 9ec3e24cce50f4cdd7a9311627e526d4381f307d Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:37:01 +0000 Subject: [PATCH 53/82] 2.2.0 process columns-n --- scss/_template_css.scss | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index ff2f5b0..0ca98f2 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -101,6 +101,20 @@ body>div.container { .bg-transparent { // background-color: transparent!important; } + +/* blog process colums-n across for n= 1 to 12 to BS row and classes */ +.blog-items { + @include make-row(); + + @for $i from 1 through $grid-columns { + + &.columns-#{$i} { + @include make-col-ready(); + + @include row-cols($i); + } + } +} .blog { /* .blog_inline algemene definities (gestuurd door blog tabblad paginaweergave paginaclass: niets blog is standaard) heeft definities op alle breedtes, naarmate het scherm breder wordt krijgen meer From de1004037d516a8b4929095ce9463e4612aa9518 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:37:11 +0000 Subject: [PATCH 54/82] 2.2.0 --- scss/_template_css.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 0ca98f2..850dd01 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -102,7 +102,7 @@ body>div.container { background-color: transparent!important; } -/* blog process colums-n across for n= 1 to 12 to BS row and classes */ +/* blog process joomla colums-n across for n= 1 to 12 to BS row and classes */ .blog-items { @include make-row(); From 18e653c33be362d213c01ec544729af898844523 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Wed, 9 Oct 2024 16:54:48 +0000 Subject: [PATCH 55/82] 2.2.0 --- scss/_template_css.scss | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 850dd01..1fc26d0 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -105,12 +105,13 @@ body>div.container { /* blog process joomla colums-n across for n= 1 to 12 to BS row and classes */ .blog-items { @include make-row(); + > * { + @include make-col-ready(); + } @for $i from 1 through $grid-columns { &.columns-#{$i} { - @include make-col-ready(); - @include row-cols($i); } } From 13c65d644ae18f59e266f93c6f0c0de60d1f980d Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:16:41 +0000 Subject: [PATCH 56/82] 2.2.0 --- scss/_template_css.scss | 51 ++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 1fc26d0..be0fa6d 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -107,6 +107,9 @@ body>div.container { @include make-row(); > * { @include make-col-ready(); + img { max-width: 100%; + height:auto; + } } @for $i from 1 through $grid-columns { @@ -116,7 +119,7 @@ body>div.container { } } } -.blog { +//.blog { /* .blog_inline algemene definities (gestuurd door blog tabblad paginaweergave paginaclass: niets blog is standaard) heeft definities op alle breedtes, naarmate het scherm breder wordt krijgen meer spans hun eigenlijke breedte (99% / 12 * ) -1% en margin-right 1%. @@ -127,31 +130,31 @@ body>div.container { volgende nivo ontbreekt bij taglist komt overeen met div.item volgende nivo span.tag-body (en h3) komt overeen met p */ - .items-leading, - .items-row, - .list-striped { - word-spacing: -0.25em; - width: 100% - } +// .items-leading, +// .items-row, +// .list-striped { +// word-spacing: -0.25em; +// width: 100% +// } - .items-leading > div, - .items-row > div, - .items-row > div > div, - .list-striped > li { - display: inline-block; - word-spacing: normal; - vertical-align: top; - float: none; - max-width:100%; - } - - .item, .span6, .span4, .span3, .span2, .span1, - .cat-list-row0, .cat-list-row1 { - width: 100%; - margin-right: 0px; - } +// .items-leading > div, +// .items-row > div, +// .items-row > div > div, +// .list-striped > li { +// display: inline-block; +// word-spacing: normal; +// vertical-align: top; +// float: none; +// max-width:100%; +// } + +// .item, .span6, .span4, .span3, .span2, .span1, +// .cat-list-row0, .cat-list-row1 { +// width: 100%; +// margin-right: 0px; +// } -} +//} .header-inner { display: -ms-flexbox; From d47b987d7e55751a97eb0eef58ce4d4691d63a9f Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:45:45 +0000 Subject: [PATCH 57/82] 2.2.0 --- scss/_template_css.scss | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index be0fa6d..f1d1af5 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -103,6 +103,10 @@ body>div.container { } /* blog process joomla colums-n across for n= 1 to 12 to BS row and classes */ +[class^="com-content"][class$="blog"], +.blog-featured { + @include make-container(); +} .blog-items { @include make-row(); > * { @@ -111,13 +115,21 @@ body>div.container { height:auto; } } + &[class*="columns"] { + @include row-cols(1); + } - @for $i from 1 through $grid-columns { +} +@include media-breakpoint-up(md) { +.blog-items { + @for $i from 2 through $grid-columns { &.columns-#{$i} { - @include row-cols($i); + @include row-cols($i); } } + +} } //.blog { /* .blog_inline algemene definities (gestuurd door blog tabblad paginaweergave paginaclass: niets blog is standaard) From b1d4db55391a68bf6e277344bf506ab51abe945c Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Wed, 9 Oct 2024 18:09:28 +0000 Subject: [PATCH 58/82] 2.2.0 --- scss/_template_css.scss | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index f1d1af5..7a97972 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -106,6 +106,9 @@ body>div.container { [class^="com-content"][class$="blog"], .blog-featured { @include make-container(); + margin: 0; + padding: 0; + } .blog-items { @include make-row(); @@ -266,7 +269,7 @@ order: -1; padding: 0; width: auto; - h2 + h2, .com-newsfeeds-newsfeed__feed-image { margin: 0; font-weight: bold; @@ -286,7 +289,7 @@ order: -1; text-align: left; } /* new test */ - ol, ul, .com-newsfeeds-newsfeed__items, .com-newsfeeds-newsfeed__feed-image + ol, ul, .com-newsfeeds-newsfeed__items { @include make-row(); padding:0; From f513df2233f819245da3a11cac447f5b7e94cf68 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 10 Oct 2024 07:31:37 +0000 Subject: [PATCH 59/82] 2.2.0 photo-box-shadow as mixin --- rules/compiler.php | 5 +---- scss/_template_css.scss | 17 ++++++++------- scss/_template_mixins_functions.scss | 31 ++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+), 12 deletions(-) create mode 100644 scss/_template_mixins_functions.scss diff --git a/rules/compiler.php b/rules/compiler.php index 8f6eef3..37aadd5 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -448,13 +448,10 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input } // standaard bootstrap variables mixins etc. einde -//fwrite($st_file, '@import "system.scss";' . "\n"); -//fwrite($st_file, '@import "general.scss";' . "\n"); fwrite($st_file, "//\n// other variables\n//\n"); fwrite($st_file, '@import "magnificpopup.variables.scss";' . "\n"); fwrite($st_file, '@import "template_variables.scss";' . "\n"); -//fwrite($st_file, '@import "flickr_badge.scss";' . "\n"); -//fwrite($st_file, '@import "joomla_update_icons.scss";' . "\n"); +fwrite($st_file, '@import "_template_mixins_functions";' . "\n"); fwrite($st_file, "//\n// css\n//\n"); if (! empty($background)) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 7a97972..02ed9c5 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -310,14 +310,15 @@ order: -1; a img { - background-color: rgba(255,255,255,0.75); - padding:5px; - border: 1px solid rgba(0,0,0,0.3); - border-radius: 5px; - box-shadow: 0 0 10px 5px rgba(0,0,0,0.2); - margin: 5px; - max-width: 100%; - height: auto; + @include photo-box-shadow(); +// background-color: rgba(255,255,255,0.75); +// padding:5px; +// border: 1px solid rgba(0,0,0,0.3); +// border-radius: 5px; +// box-shadow: 0 0 10px 5px rgba(0,0,0,0.2); +// margin: 5px; +// max-width: 100%; +// height: auto; } div.feed-item-description p:first-child diff --git a/scss/_template_mixins_functions.scss b/scss/_template_mixins_functions.scss new file mode 100644 index 0000000..64e68c0 --- /dev/null +++ b/scss/_template_mixins_functions.scss @@ -0,0 +1,31 @@ +// mixins and functions for this template +// v2.2.0 20241010 +// + +// skins + +@mixin photo-box-shadow($shadow... : 0 0 10px 5px rgba(0,0,0,0.2) ) { + @if $enable-shadows { + $result: (); + + @each $value in $shadow { + @if $value != null { + $result: append($result, $value, "comma"); + } + @if $value == none and length($shadow) > 1 { + @warn "The keyword 'none' must be used as a single argument."; + } + } + + background-color: rgba(255,255,255,0.75); + padding:5px; + border: 1px solid rgba(0,0,0,0.3); + border-radius: 5px; + margin: 5px; + max-width: 100%; + height: auto; + @if (length($result) > 0) { + box-shadow: $result; + } + } +} From 4c8e8e30652ae79f3b222b069cd6bdf3b64606c0 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 10 Oct 2024 07:39:46 +0000 Subject: [PATCH 60/82] 2.2.0 --- scss/_template_css.scss | 2 +- scss/_template_mixins_functions.scss | 2 +- scss/_template_variables.scss | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 02ed9c5..20a1768 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -310,7 +310,7 @@ order: -1; a img { - @include photo-box-shadow(); + @include photo-box-shadow($photo-box-shadow); // background-color: rgba(255,255,255,0.75); // padding:5px; // border: 1px solid rgba(0,0,0,0.3); diff --git a/scss/_template_mixins_functions.scss b/scss/_template_mixins_functions.scss index 64e68c0..3aa1892 100644 --- a/scss/_template_mixins_functions.scss +++ b/scss/_template_mixins_functions.scss @@ -4,7 +4,7 @@ // skins -@mixin photo-box-shadow($shadow... : 0 0 10px 5px rgba(0,0,0,0.2) ) { +@mixin photo-box-shadow($shadow...) { @if $enable-shadows { $result: (); diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss index 9869779..daac5da 100644 --- a/scss/_template_variables.scss +++ b/scss/_template_variables.scss @@ -22,6 +22,10 @@ $activenavbarfg: $gray-600; // was #fff; $specialgreygradientstart: $white; // was #ffffff; $specialgreygradientend: #e6e6e6; +// skins +$photo-box-shadow : 0 0 10px 5px rgba(0,0,0,0.2) !default; + + // BS3 temporary variables $screen-xs-min: breakpoint-min( "sm"); // was $screen-xs; $screen-sm-min: breakpoint-min( "md"); // was $screen-sm; From ff0f59d10ff3649657da9a04edff9105ea2fb958 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 10 Oct 2024 07:46:30 +0000 Subject: [PATCH 61/82] 2.2.0 --- scss/_template_css.scss | 2 +- scss/_template_mixins_functions.scss | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 20a1768..1b0576f 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -318,7 +318,7 @@ order: -1; // box-shadow: 0 0 10px 5px rgba(0,0,0,0.2); // margin: 5px; // max-width: 100%; -// height: auto; + height: auto; } div.feed-item-description p:first-child diff --git a/scss/_template_mixins_functions.scss b/scss/_template_mixins_functions.scss index 3aa1892..11f6307 100644 --- a/scss/_template_mixins_functions.scss +++ b/scss/_template_mixins_functions.scss @@ -5,7 +5,7 @@ // skins @mixin photo-box-shadow($shadow...) { - @if $enable-shadows { +// @if $enable-shadows { $result: (); @each $value in $shadow { @@ -27,5 +27,5 @@ @if (length($result) > 0) { box-shadow: $result; } - } +// } } From f6dff09ba25bf93da3c4c55386f564a83d342142 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 10 Oct 2024 07:53:22 +0000 Subject: [PATCH 62/82] 2.2.0 --- scss/_template_css.scss | 48 ++++------------------------------------- 1 file changed, 4 insertions(+), 44 deletions(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 1b0576f..7fbcf29 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -110,6 +110,10 @@ body>div.container { padding: 0; } +.photo-album .blog-items img { + @include photo-box-shadow($photo-box-shadow); +} + .blog-items { @include make-row(); > * { @@ -134,42 +138,6 @@ body>div.container { } } -//.blog { -/* .blog_inline algemene definities (gestuurd door blog tabblad paginaweergave paginaclass: niets blog is standaard) - heeft definities op alle breedtes, naarmate het scherm breder wordt krijgen meer - spans hun eigenlijke breedte (99% / 12 * ) -1% en margin-right 1%. - (spannr wordt aangestuurd door blog tabblad blogweergave 12 / # kolommen tevens komt er dan een cols-nr in de div eronder ) - en komen meer breedtes voor items-leading beschikbaar (gestuurd door paginaweergave paginaclass: blog lead-cols-2 ) - .blog ook voor kop ul.list-striped komt overeen met div.items-row (maar cols-1 etc kan hier niet gevuld worden - volgende nivo li.cat-list-row0 en li.cat-list-row1 komen overeen met div.span1 span2 enz - volgende nivo ontbreekt bij taglist komt overeen met div.item - volgende nivo span.tag-body (en h3) komt overeen met p -*/ -// .items-leading, -// .items-row, -// .list-striped { -// word-spacing: -0.25em; -// width: 100% -// } - -// .items-leading > div, -// .items-row > div, -// .items-row > div > div, -// .list-striped > li { -// display: inline-block; -// word-spacing: normal; -// vertical-align: top; -// float: none; -// max-width:100%; -// } - -// .item, .span6, .span4, .span3, .span2, .span1, -// .cat-list-row0, .cat-list-row1 { -// width: 100%; -// margin-right: 0px; -// } - -//} .header-inner { display: -ms-flexbox; @@ -311,14 +279,6 @@ order: -1; a img { @include photo-box-shadow($photo-box-shadow); -// background-color: rgba(255,255,255,0.75); -// padding:5px; -// border: 1px solid rgba(0,0,0,0.3); -// border-radius: 5px; -// box-shadow: 0 0 10px 5px rgba(0,0,0,0.2); -// margin: 5px; -// max-width: 100%; - height: auto; } div.feed-item-description p:first-child From b7e83bdcf704757ff6ca6aa58a45c5f792fd80eb Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 10 Oct 2024 09:49:19 +0000 Subject: [PATCH 63/82] 2.2.0 --- scss/_template_css.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 7fbcf29..7e8617e 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -110,7 +110,8 @@ body>div.container { padding: 0; } -.photo-album .blog-items img { +.photo-album img, +.photo-in-album { @include photo-box-shadow($photo-box-shadow); } From 6f557bb564983e72756f6f4b8ef24375bcddb5f6 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:02:40 +0000 Subject: [PATCH 64/82] 2.2.0 Remove extra breakpoint --- README.md | 3 +- rules/compiler.php | 169 +++++++++++++++++++---------------------- scss/mixins/_grid.scss | 122 ----------------------------- templateDetails.xml | 8 +- 4 files changed, 85 insertions(+), 217 deletions(-) delete mode 100644 scss/mixins/_grid.scss diff --git a/README.md b/README.md index bbe3191..5edb875 100644 --- a/README.md +++ b/README.md @@ -12,5 +12,6 @@ This project is licensed under the [GNU GPL], version 3 or later. ## Changelog * 2.2.0.dev improvements rssfoto newsfeeds for J4,J5, remove suport BS3, use latest versions BS4 and BS5, remove some redundant code. original scss files of BS4 and BS5 in folders scss bs4 and bs5. - New scss compiler scssphp/scssphp 1.13.0 and server scssphp/server 1.1.0 as continuation of leafo/scssphp + New scss compiler scssphp/scssphp 1.13.0 and server scssphp/server 1.1.0 as continuation of leafo/scssphp + Remove options for extra/override breakpoints. * 2.1.2 removed hard returns from documentation field because j4.4 + doesn't accept that. diff --git a/rules/compiler.php b/rules/compiler.php index 37aadd5..5b2d08d 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -24,7 +24,7 @@ v 26-12-2021 added Joomla version info to use J4 specific code. 2023-12-07 resolved Unknown constant path_parts (is var $path_parts). 2024-10-03 v2.2.0 New scss compiler scssphp/scssphp 1.13.0 and server scssphp/server 1.1.0 as continuation of leafo/scssphp. - Remove Bootstrap 3, use latest versions 5.3.3 and 4.6.2 of BS 5 and 4. + Remove Bootstrap 3, use latest versions 5.3.3 and 4.6.2 of BS 5 and 4. Remove extra breakpoints */ defined('_JEXEC') or die('caught by _JEXEC'); @@ -170,14 +170,14 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input else { $wsaCssFilename = 'template.min.' . $templatestyleid . '.css';} -$wsaBreakpointes = htmlspecialchars($params->wsaBreakpointes); -$wsaContaineres = $wsaBreakpointes; -$wsaBreakpointxxl = htmlspecialchars($params->wsaBreakpointxxl); -$wsaContainerxxl = htmlspecialchars($params->wsaContainerxxl); -if (! $wsaContainerxxl) {$wsaContainerxxl = $wsaBreakpointxxl; } -$wsaBreakpointxxxl = htmlspecialchars($params->wsaBreakpointxxxl); -$wsaContainerxxxl = htmlspecialchars($params->wsaContainerxxxl); -if (! $wsaContainerxxxl) {$wsaContainerxxxl = $wsaBreakpointxxxl; } +// $wsaBreakpointes = htmlspecialchars($params->wsaBreakpointes); +// $wsaContaineres = $wsaBreakpointes; +// $wsaBreakpointxxl = htmlspecialchars($params->wsaBreakpointxxl); +// $wsaContainerxxl = htmlspecialchars($params->wsaContainerxxl); +// if (! $wsaContainerxxl) {$wsaContainerxxl = $wsaBreakpointxxl; } +// $wsaBreakpointxxxl = htmlspecialchars($params->wsaBreakpointxxxl); +// $wsaContainerxxxl = htmlspecialchars($params->wsaContainerxxxl); +// if (! $wsaContainerxxxl) {$wsaContainerxxxl = $wsaBreakpointxxxl; } if (strpos($menuType, 'navbar-dark') !== false) {$navbartheme = 'navbar-dark';} @@ -351,17 +351,6 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input // standaard bootstrap variables mixins etc. fwrite($st_file, "//\n// standard bootstrap includes v" . $twbs_version . "\n//\n"); -// if($twbs_version == '3') { -// fwrite($st_file, '@import "variables.scss";' . "\n"); -// fwrite($st_file, '@import "mixins/reset-filter.scss";' . "\n"); -// fwrite($st_file, '@import "mixins/vendor-prefixes.scss";' . "\n"); -// fwrite($st_file, '@import "mixins/gradients.scss";' . "\n"); -// fwrite($st_file, '@import "mixins/grid.scss";' . "\n"); -// } else -// { /* verion 4 + */ -// fwrite($st_file, '@import bs"' . $twbs_version . 'variables.scss";' . "\n"); -//fwrite($st_file, '@import "mixins/reset-filter.scss";' . " // nog even uit 3\n"); // nog even uit 3 -//fwrite($st_file, '@import "mixins/gradients.scss";' . " // nog even uit 3\n"); // nog even uit 3 // Custom.scss // Option B: Include parts of Bootstrap @@ -374,78 +363,78 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input fwrite($st_file, "//\n// optional bootstrap includes and override v" . $twbs_version . "\n//\n"); //fwrite($st_file, '@import "wsabs4extra.variables.scss";' . "\n"); -if ($wsaBreakpointes > 0 or $wsaBreakpointxxl > 0 or $wsaBreakpointxxxl > 0) -{ -fwrite($st_file, -'// Grid breakpoints -$grid-breakpoints: ( - xs: 0'); -if ($wsaBreakpointes > 0 ) -{ -fwrite($st_file, -', - es: ' . $wsaBreakpointes . 'px'); -} -fwrite($st_file, -', - sm: 576px, - md: 768px, - lg: 992px, - xl: 1200px'); -if ($wsaBreakpointxxl > 0 ) -{ -fwrite($st_file, -', - xxl: ' . $wsaBreakpointxxl . 'px'); -} -if ($wsaBreakpointxxxl > 0 ) -{ -fwrite($st_file, -', - xxxl: ' . $wsaBreakpointxxxl . 'px'); -} -fwrite($st_file, -' ) ; -@include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); -@include _assert-starts-at-zero($grid-breakpoints); -// Grid containers -$container-max-widths: ( -'); -if ($wsaBreakpointes > 0 ) -{ -fwrite($st_file, -' es: ' . $wsaContaineres . 'px, -'); -} -fwrite($st_file, -' sm: 540px, - md: 720px, - lg: 960px, - xl: 1140px'); -if ($wsaBreakpointxxl > 0 ) -{ -fwrite($st_file, -', - xxl: ' . $wsaContainerxxl . 'px'); -} -if ($wsaBreakpointxxxl > 0 ) -{ -fwrite($st_file, -', - xxxl: ' . $wsaContainerxxxl . 'px'); -} -fwrite($st_file, -' ) ; -@include _assert-ascending($container-max-widths, "$container-max-widths"); -'); +// if ($wsaBreakpointes > 0 or $wsaBreakpointxxl > 0 or $wsaBreakpointxxxl > 0) +// { +// fwrite($st_file, +// '// Grid breakpoints +// $grid-breakpoints: ( +// xs: 0'); +// if ($wsaBreakpointes > 0 ) +// { +// fwrite($st_file, +// ', +// es: ' . $wsaBreakpointes . 'px'); +// } +// fwrite($st_file, +// ', +// sm: 576px, +// md: 768px, +// lg: 992px, +// xl: 1200px'); +// if ($wsaBreakpointxxl > 0 ) +// { +// fwrite($st_file, +// ', +// xxl: ' . $wsaBreakpointxxl . 'px'); +// } +// if ($wsaBreakpointxxxl > 0 ) +// { +// fwrite($st_file, +// ', +// xxxl: ' . $wsaBreakpointxxxl . 'px'); +// } +// fwrite($st_file, +// ' ) ; +// @include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); +// @include _assert-starts-at-zero($grid-breakpoints); +// // Grid containers +// $container-max-widths: ( +// '); +// if ($wsaBreakpointes > 0 ) +// { +// fwrite($st_file, +// ' es: ' . $wsaContaineres . 'px, +// '); +// } +// fwrite($st_file, +// ' sm: 540px, +// md: 720px, +// lg: 960px, +// xl: 1140px'); +// if ($wsaBreakpointxxl > 0 ) +// { +// fwrite($st_file, +// ', +// xxl: ' . $wsaContainerxxl . 'px'); +// } +// if ($wsaBreakpointxxxl > 0 ) +// { +// fwrite($st_file, +// ', +// xxxl: ' . $wsaContainerxxxl . 'px'); +// } +// fwrite($st_file, +// ' ) ; +// @include _assert-ascending($container-max-widths, "$container-max-widths"); +// '); -//fwrite($st_file, '@import "node_modules/bootstrap/scss/reboot";' . "\n"); -//fwrite($st_file, '@import "node_modules/bootstrap/scss/type";' . "\n"); -//fwrite($st_file, '@import "node_modules/bootstrap/scss/images";' . "\n"); -//fwrite($st_file, '@import "node_modules/bootstrap/scss/code";' . "\n"); -fwrite($st_file, '@import "bs' . $twbs_version . '/grid.scss";' . "\n"); +// //fwrite($st_file, '@import "node_modules/bootstrap/scss/reboot";' . "\n"); +// //fwrite($st_file, '@import "node_modules/bootstrap/scss/type";' . "\n"); +// //fwrite($st_file, '@import "node_modules/bootstrap/scss/images";' . "\n"); +// //fwrite($st_file, '@import "node_modules/bootstrap/scss/code";' . "\n"); +// fwrite($st_file, '@import "bs' . $twbs_version . '/grid.scss";' . "\n"); -} +// } // standaard bootstrap variables mixins etc. einde fwrite($st_file, "//\n// other variables\n//\n"); diff --git a/scss/mixins/_grid.scss b/scss/mixins/_grid.scss deleted file mode 100644 index 59551da..0000000 --- a/scss/mixins/_grid.scss +++ /dev/null @@ -1,122 +0,0 @@ -// Grid system -// -// Generate semantic grid columns with these mixins. - -// Centered container element -@mixin container-fixed($gutter: $grid-gutter-width) { - margin-right: auto; - margin-left: auto; - padding-left: floor(($gutter / 2)); - padding-right: ceil(($gutter / 2)); - @include clearfix; -} - -// Creates a wrapper for a series of columns -@mixin make-row($gutter: $grid-gutter-width) { - margin-left: ceil(($gutter / -2)); - margin-right: floor(($gutter / -2)); - @include clearfix; -} - -// Generate the extra small columns -@mixin make-xs-column($columns, $gutter: $grid-gutter-width) { - position: relative; - float: left; - width: percentage(($columns / $grid-columns)); - min-height: 1px; - padding-left: ($gutter / 2); - padding-right: ($gutter / 2); -} -@mixin make-xs-column-offset($columns) { - margin-left: percentage(($columns / $grid-columns)); -} -@mixin make-xs-column-push($columns) { - left: percentage(($columns / $grid-columns)); -} -@mixin make-xs-column-pull($columns) { - right: percentage(($columns / $grid-columns)); -} - -// Generate the small columns -@mixin make-sm-column($columns, $gutter: $grid-gutter-width) { - position: relative; - min-height: 1px; - padding-left: ($gutter / 2); - padding-right: ($gutter / 2); - - @media (min-width: $screen-sm-min) { - float: left; - width: percentage(($columns / $grid-columns)); - } -} -@mixin make-sm-column-offset($columns) { - @media (min-width: $screen-sm-min) { - margin-left: percentage(($columns / $grid-columns)); - } -} -@mixin make-sm-column-push($columns) { - @media (min-width: $screen-sm-min) { - left: percentage(($columns / $grid-columns)); - } -} -@mixin make-sm-column-pull($columns) { - @media (min-width: $screen-sm-min) { - right: percentage(($columns / $grid-columns)); - } -} - -// Generate the medium columns -@mixin make-md-column($columns, $gutter: $grid-gutter-width) { - position: relative; - min-height: 1px; - padding-left: ($gutter / 2); - padding-right: ($gutter / 2); - - @media (min-width: $screen-md-min) { - float: left; - width: percentage(($columns / $grid-columns)); - } -} -@mixin make-md-column-offset($columns) { - @media (min-width: $screen-md-min) { - margin-left: percentage(($columns / $grid-columns)); - } -} -@mixin make-md-column-push($columns) { - @media (min-width: $screen-md-min) { - left: percentage(($columns / $grid-columns)); - } -} -@mixin make-md-column-pull($columns) { - @media (min-width: $screen-md-min) { - right: percentage(($columns / $grid-columns)); - } -} - -// Generate the large columns -@mixin make-lg-column($columns, $gutter: $grid-gutter-width) { - position: relative; - min-height: 1px; - padding-left: ($gutter / 2); - padding-right: ($gutter / 2); - - @media (min-width: $screen-lg-min) { - float: left; - width: percentage(($columns / $grid-columns)); - } -} -@mixin make-lg-column-offset($columns) { - @media (min-width: $screen-lg-min) { - margin-left: percentage(($columns / $grid-columns)); - } -} -@mixin make-lg-column-push($columns) { - @media (min-width: $screen-lg-min) { - left: percentage(($columns / $grid-columns)); - } -} -@mixin make-lg-column-pull($columns) { - @media (min-width: $screen-lg-min) { - right: percentage(($columns / $grid-columns)); - } -} diff --git a/templateDetails.xml b/templateDetails.xml index 80d5acb..3db845b 100644 --- a/templateDetails.xml +++ b/templateDetails.xml @@ -2,14 +2,13 @@ - wsa_bootstrap - 2.1.3.dev - 30-09-2024 + 2.2.0.dev + 10-10-2024 AHC Waasdorp info@waasdorpsoekhan.nl http://www.waasdorpsoekhan.nl @@ -136,7 +135,7 @@ - + --> Date: Thu, 10 Oct 2024 17:27:04 +0000 Subject: [PATCH 65/82] 2.2.0 remove override com_tags --- html/com_tags/index.html | 1 - html/com_tags/tag/default_items.php | 138 ---------------------------- html/com_tags/tag/index.html | 1 - html/layouts/index.html | 1 - html/layouts/joomla/index.html | 1 - scss/_template_css.scss | 6 +- 6 files changed, 4 insertions(+), 144 deletions(-) delete mode 100644 html/com_tags/index.html delete mode 100644 html/com_tags/tag/default_items.php delete mode 100644 html/com_tags/tag/index.html delete mode 100644 html/layouts/index.html delete mode 100644 html/layouts/joomla/index.html diff --git a/html/com_tags/index.html b/html/com_tags/index.html deleted file mode 100644 index 2efb97f..0000000 --- a/html/com_tags/index.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/html/com_tags/tag/default_items.php b/html/com_tags/tag/default_items.php deleted file mode 100644 index aa24d2e..0000000 --- a/html/com_tags/tag/default_items.php +++ /dev/null @@ -1,138 +0,0 @@ -item->readmore ipv $this->item[0]->readmore) - bw 14-04-2017 kleine aanpassingen na vgl v 3.7.0rc2 - bw 30-09-2017 idem na vgl v3.8.0 - bw 7-1-2018 J4 namespaces gebruiken - */ - -defined('_JEXEC') or die; -use Joomla\CMS\Factory; // this is the same as use Joomla\CMS\Factory as Factory -use Joomla\CMS\Uri\Uri; -use Joomla\CMS\HTML\HTMLHelper; -use Joomla\CMS\Language\Text; -use Joomla\CMS\Router\Route; - - -HTMLHelper::addIncludePath(JPATH_COMPONENT . '/helpers'); - -HTMLHelper::_('behavior.core'); -HTMLHelper::_('formbehavior.chosen', 'select'); - -// Get the user object. -$user = Factory::getUser(); - -// Check if user is allowed to add/edit based on tags permissions. -// Do we really have to make it so people can see unpublished tags??? -$canEdit = $user->authorise('core.edit', 'com_tags'); -$canCreate = $user->authorise('core.create', 'com_tags'); -$canEditState = $user->authorise('core.edit.state', 'com_tags'); -$items = $this->items; -$n = count($this->items); - -Factory::getDocument()->addScriptDeclaration(" - var resetFilter = function() { - document.getElementById('filter-search').value = ''; - } -"); - -?> -
- params->get('show_headings') || $this->params->get('filter_field') || $this->params->get('show_pagination_limit')) : ?> -
- params->get('filter_field')) : ?> -
- - - - -
- - params->get('show_pagination_limit')) : ?> -
- - pagination->getLimitBox(); ?> -
- - - - - -
-
- - items === false || $n === 0) : ?> -

- - - -
diff --git a/html/com_tags/tag/index.html b/html/com_tags/tag/index.html deleted file mode 100644 index 2efb97f..0000000 --- a/html/com_tags/tag/index.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/html/layouts/index.html b/html/layouts/index.html deleted file mode 100644 index 94906bc..0000000 --- a/html/layouts/index.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/html/layouts/joomla/index.html b/html/layouts/joomla/index.html deleted file mode 100644 index 94906bc..0000000 --- a/html/layouts/joomla/index.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 7e8617e..e802c1a 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -115,7 +115,8 @@ body>div.container { @include photo-box-shadow($photo-box-shadow); } -.blog-items { +.blog-items, +.com-tags__items .list-group { @include make-row(); > * { @include make-col-ready(); @@ -129,7 +130,8 @@ body>div.container { } @include media-breakpoint-up(md) { -.blog-items { +.blog-items, +.com-tags__items .list-group{ @for $i from 2 through $grid-columns { &.columns-#{$i} { From 2dd8b55bb589dbf0a499085681fe4aa54d9c468d Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:31:07 +0000 Subject: [PATCH 66/82] 2.2.0 --- scss/_template_css.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index e802c1a..cc055f0 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -104,7 +104,8 @@ body>div.container { /* blog process joomla colums-n across for n= 1 to 12 to BS row and classes */ [class^="com-content"][class$="blog"], -.blog-featured { +.blog-featured, +.com-tags__items { @include make-container(); margin: 0; padding: 0; From 1d0b1e3f4bb6310dbf815997a23cc17aaa71aef6 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 10 Oct 2024 17:34:24 +0000 Subject: [PATCH 67/82] 2.2.0 --- scss/_template_css.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index cc055f0..737e838 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -106,7 +106,8 @@ body>div.container { [class^="com-content"][class$="blog"], .blog-featured, .com-tags__items { - @include make-container(); +// @include make-container(); only width 100% remains + width: 100%; margin: 0; padding: 0; From aed843b0f2ae67b18e2ccd7b3d0e621cc8ead683 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:18:09 +0000 Subject: [PATCH 68/82] 2.2.0 added flex-direction row for tag items --- scss/_template_css.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 737e838..1b0568e 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -120,6 +120,7 @@ body>div.container { .blog-items, .com-tags__items .list-group { @include make-row(); + flex-direction:row; > * { @include make-col-ready(); img { max-width: 100%; From 62b993bd451b9f90d78742fef0f4c83d1a9d1975 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:31:37 +0000 Subject: [PATCH 69/82] 2.2.0 wat opgeruimd --- rules/compiler.php | 9 +- scss/_template_css.scss | 302 +--------------------------------- scss/_template_variables.scss | 20 --- 3 files changed, 8 insertions(+), 323 deletions(-) diff --git a/rules/compiler.php b/rules/compiler.php index 5b2d08d..b2896c2 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -120,6 +120,7 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input $iconsPosLeft = htmlspecialchars($params->iconsPosLeft); $iconsPosTop = htmlspecialchars($params->iconsPosTop); $wsaIconsFlex = htmlspecialchars($params->wsaIconsFlex); +$wsaNavbarExpand = htmlspecialchars($params->wsaNavbarExpand); $wsaNavbarRightWidth = htmlspecialchars($params->wsaNavbarRightWidth); $footerWidth = htmlspecialchars($params->footericonsWidth); $footerPosLeft = htmlspecialchars($params->footerPosLeft); @@ -243,18 +244,13 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input fwrite($tv_file, "// " . "\n//\n"); if ($twbs_version > ' ' ) fwrite($tv_file, '$twbs_version: "' . $twbs_version . "\";\n"); - if ($gplusProfile > ' ' ) fwrite($tv_file, '$gplusProfile: "' . $gplusProfile . "\";\n"); - +if ($wsaNavbarExpand > ' ' ) fwrite($tv_file, '$wsaBreakpointExpand: ' . substr($wsaNavbarExpand,15) . ";\n"); if ($fgColor > ' ' ) fwrite($tv_file, '$fgColor: ' . $fgColor . ";\n"); - if ($brandImage > ' ' ) fwrite($tv_file, '$brandImage: ' . $brandImage . ";\n"); if ($brandSize > ' ' ) fwrite($tv_file, '$brandSize: ' . $brandSize . ";\n"); if ($brandWidth > ' ' ) fwrite($tv_file, '$brandWidth: ' . $brandWidth . ";\n"); - - if ($bg0Color > ' ' ) fwrite($tv_file, '$bg0Color: ' . $bg0Color . ";\n"); - if ($bg1Image > ' ' ) fwrite($tv_file, '$bg1Image: ' . $bg1Image . ";\n"); if ($bg1Image_lg > ' ' ) fwrite($tv_file, '$bg1Image_lg: ' . $bg1Image_lg . ";\n"); if ($bg1Image_sm > ' ' ) fwrite($tv_file, '$bg1Image_sm: ' . $bg1Image_sm . ";\n"); @@ -282,6 +278,7 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input if ($wsaNavbarRightWidth > ' ' ) fwrite($tv_file, '$wsaNavbarRightWidth: ' . $wsaNavbarRightWidth . "px;\n"); + fwrite($tv_file, '$menuType: ' . $menuType . ";\n"); fwrite($tv_file, '$navbar-theme: ' . $navbartheme . ";\n"); fwrite($tv_file, '$navbar-bg: ' . $navbarbg . ";\n"); diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 1b0568e..a84965b 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -46,7 +46,6 @@ padding-top:$bg1Top; /* z-index: $bg1Z-index; */ } -@if $twbs_version == 5 { #headerleft { position: relative; float:left; @@ -61,22 +60,8 @@ width: 100%; } } -} // einde bs5 + @if $twbs_version == 4 { -#headerleft { - position: relative; - float:left; - width:$asHeadLeftWidth; - margin-top: $hlMarginTop; - margin-left:$hlMarginLeft; - margin-bottom: $hlMarginBottom; - padding-top:0; - padding-bottom: 0; // $hlHeight; - div.inner { - position: relative; - width: 100%; - } -} .visually-hidden {display:none;} // header language selector joomla 4 use this bs5 selector } // einde bs4 #navbar-right-mod @@ -132,7 +117,7 @@ body>div.container { } } -@include media-breakpoint-up(md) { +@include media-breakpoint-up($wsaBreakpointExpand) { .blog-items, .com-tags__items .list-group{ @for $i from 2 through $grid-columns { @@ -146,9 +131,7 @@ body>div.container { } .header-inner { -display: -ms-flexbox; display: flex; --ms-flex-direction: column; flex-direction: column; .navbar{width: 100%; } @@ -167,25 +150,12 @@ flex-direction: column; position: relative; display: block; -display: -ms-flexbox; display: flex; --ms-flex-direction: $wsaIconsFlex; flex-direction: $wsaIconsFlex; width: 100%; --ms-flex-order: -1; order: -1; } - - -.img-fluid, -.img-fluid-w33, -.img-fluid-w50 - { /* vooruitlopend op bs4 in 3 is dit img-responsive */ - max-width: 100%; - height: auto; -} - .items-leading div .videoWrapper, .videoWrapper { position:relative; @@ -447,29 +417,9 @@ h6 { }/* einde (max-width: $screen-xs-max) */ -@if $twbs_version == 4 { + @include media-breakpoint-up(sm) { // min 576 -.blog { - .span6, .span4, .span3, .span2, .span1, - &.cols-2 .cat-list-row0, &.cols-3 .cat-list-row0, &.cols-4 .cat-list-row0, &.cols-5 .cat-list-row0, &.cols-6 .cat-list-row0, - &.cols-2 .cat-list-row1, &.cols-3 .cat-list-row1, &.cols-4 .cat-list-row1, &.cols-5 .cat-list-row1, &.cols-6 .cat-list-row1 - { - width: $wsa02Col ; -// margin-right: $wsaInnerMargin; - margin-left: auto; - } -} - -.blog.lead-cols-2 { - .items-leading > div { - width: $wsa02Col; -// margin-right: $wsaInnerMargin; - margin-left: auto; - - } - -} .img-fluid-w33 { @@ -479,20 +429,6 @@ h6 { { max-width:50%; } -.tag-category ul -{ - li - { - max-width: $tagListItemWidth; - width: auto; - } - &.category.list-striped li - { - max-width: $tagListItemWidth; - width: auto; - } - -} }/* einde up(sm) */ @include media-breakpoint-up(md) { // min 768 @@ -500,41 +436,12 @@ h6 { float: right; margin-right: -15px; } -.blog { - - .span4, - &.cols-3 .cat-list-row0, - &.cols-3 .cat-list-row1 { - width: $wsa03Col; - } - .span3, .span2, .span1, - &.cols-4 .cat-list-row0, &.cols-5 .cat-list-row0, &.cols-6 .cat-list-row0, - &.cols-4 .cat-list-row1, &.cols-5 .cat-list-row1, &.cols-6 .cat-list-row1 { - width: $wsa04Col; - } - -} -.blog.lead-cols-3 { - .items-leading > div { - width: $wsa03Col; -// margin-right: $wsaInnerMargin; - margin-left: auto; - - } - -} - - - .form-horizontal .control-group { +.form-horizontal .control-group { .control-label { text-align: left; - //@include make-xs-column(2); - } - .controls { - //@include make-xs-column(10); } - } +} @if $iconsPosTop > 0px { .iconssm.navbar-expand-md @@ -556,28 +463,6 @@ margin-top: -40px; @include media-breakpoint-up(lg) { // min 992 -.blog { - .cols-5 .span2, - &.cols-5 .cat-list-row0, - &.cols-5 .cat-list-row1 { - width: $wsa05Col ; - } - - .span2, - &.cols-6 .cat-list-row0, - &.cols-6 .cat-list-row1 { - width: $wsa06Col ; - } - .cols-8 .span1 { - width: $wsa08Col ; - } - .span1 { - width: $wsa12Col ; - } - - - -} @if $iconsPosTop > 0px { .iconssm.navbar-expand-lg @@ -615,181 +500,4 @@ margin-top: -40px; } } -/* einde up(xl) */ -// @include media-breakpoint-up(xxl) { bs4 custom > xl (1200 px) bv 1440 -//} -// @include media-breakpoint-up(xxxl) { bs4 custom > xxl bv 1600 -//} - -} // einde bs4 -@else { // bs3 -@media (min-width: $screen-xs-min) -// bs 3 -{ - -.blog { - .span6, .span4, .span3, .span2, .span1, - &.cols-2 .cat-list-row0, &.cols-3 .cat-list-row0, &.cols-4 .cat-list-row0, &.cols-5 .cat-list-row0, &.cols-6 .cat-list-row0, - &.cols-2 .cat-list-row1, &.cols-3 .cat-list-row1, &.cols-4 .cat-list-row1, &.cols-5 .cat-list-row1, &.cols-6 .cat-list-row1 - { - width: $wsa02Col ; -// margin-right: $wsaInnerMargin; - margin-left: auto; - } -} - -.blog.lead-cols-2 { - .items-leading > div { - width: $wsa02Col; -// margin-right: $wsaInnerMargin; - margin-left: auto; - - } - -} - -.img-fluid-w33 -{ - max-width:33%; -} - .img-fluid-w50 -{ - max-width:50%; -} -.tag-category ul -{ - li - { - max-width: $tagListItemWidth; - width: auto; - } - &.category.list-striped li - { - max-width: $tagListItemWidth; - width: auto; - } - -} -/* einde (min-width: $screen-xs-min) */} -// @include media-breakpoint-up(md) { bs4 -@media (min-width: $screen-sm-min){ -#navbar-right-mod { - float: right; - margin-right: -15px; -} -.blog { - - .span4, - &.cols-3 .cat-list-row0, - &.cols-3 .cat-list-row1 { - width: $wsa03Col; - } - .span3, .span2, .span1, - &.cols-4 .cat-list-row0, &.cols-5 .cat-list-row0, &.cols-6 .cat-list-row0, - &.cols-4 .cat-list-row1, &.cols-5 .cat-list-row1, &.cols-6 .cat-list-row1 { - width: $wsa04Col; - } - -} -.blog.lead-cols-3 { - .items-leading > div { - width: $wsa03Col; -// margin-right: $wsaInnerMargin; - margin-left: auto; - - } - -} - - - - .form-horizontal .control-group { - .control-label { - text-align: left; - //@include make-xs-column(2); - } - .controls { - //@include make-xs-column(10); - } - } -.iconssm.navbar-expand-sm -{ /* icons social media boven logo absolute vanaf 'navbar-expand-..' */ - position: absolute; - top: $iconsPosTop; - left: $iconsPosLeft; - width: $iconsWidth; - max-width: 100%; -} - -}/* einde (min-width: $screen-sm-min) */ - -// @include media-breakpoint-up(lg) { bs4 -@media (min-width: $screen-md-min ) { /* desktop (width >= 992px) */ - -.blog { - .cols-5 .span2, - &.cols-5 .cat-list-row0, - &.cols-5 .cat-list-row1 { - width: $wsa05Col ; - } - - .span2, - &.cols-6 .cat-list-row0, - &.cols-6 .cat-list-row1 { - width: $wsa06Col ; - } - .cols-8 .span1 { - width: $wsa08Col ; - } - .span1 { - width: $wsa12Col ; - } - - - -} -.iconssm.navbar-expand-md -{ /* icons social media boven logo absolute vanaf 'navbar-expand-..' */ - position: absolute; - top: $iconsPosTop; - left: $iconsPosLeft; - width: $iconsWidth; - max-width: 100%; -} - -} -/* einde @media $screen-md-min */ - -// @include media-breakpoint-up(xl) { bs4 1200 px -@media (min-width: $screen-lg-min ) { /* desktop (width >= 1200px) */ - -.iconssm.navbar-expand-lg -{ /* icons social media boven logo absolute vanaf 'navbar-expand-..' */ - position: absolute; - top: $iconsPosTop; - left: $iconsPosLeft; - width: $iconsWidth; - max-width: 100%; -} - -} -/* einde @media $screen-lg-min */ -@media (min-width: $screen-xl-min ) { /* desktop (width >= 992px) */ - -.iconssm.navbar-expand-xl -{ /* icons social media boven logo absolute vanaf 'navbar-expand-..' */ - position: absolute; - top: $iconsPosTop; - left: $iconsPosLeft; - width: $iconsWidth; - max-width: 100%; -} - -} -/* einde @media $screen-xl-min */ -// @include media-breakpoint-up(xxl) { bs4 custom > xl (1200 px) bv 1440 -//} -// @include media-breakpoint-up(xxxl) { bs4 custom > xxl bv 1600 -//} -} // einde bs3 diff --git a/scss/_template_variables.scss b/scss/_template_variables.scss index daac5da..c97add8 100644 --- a/scss/_template_variables.scss +++ b/scss/_template_variables.scss @@ -89,9 +89,6 @@ $bg1Z-index: auto; $bg2Z-index: auto; /* uit asha-s */ -// $asBlogLeadingWidth: 75%; -// $asBlogItemWidth: 23.5%; -$tagListItemWidth: 75%; $tagItemTitleDisplay: none; $tagItemSearchDisplay: none; $asMinWidthItem: 256px; @@ -102,12 +99,6 @@ $as2ColHalfWidth: $as2ColFullWidth / 2; $as3ColFullWidth: 360px; $as3ColHalfWidth: $as3ColFullWidth / 2; - - - -//$asBlogItemWidth: 12.5%; - -$tagListItemWidth: 30.0%; $wrapperBorderRadius: 10px; // variabelen voor .blog_inline @@ -129,14 +120,3 @@ $wsa10Col : (100% - (11 * $wsaInnerMargin)) / 10 ; $wsa11Col : (100% - (12 * $wsaInnerMargin)) / 11 ; $wsa12Col : (100% - (13 * $wsaInnerMargin)) / 12 ; $span1 : $wsa12Col; - - -//.test01 { -// width:$screen-xs-min; -// height: $screen-sm-min; -// padding-top: $screen-md-min; -// padding-right: $screen-lg-min; -// padding-left: $screen-xl-min; -// padding-bottom: $screen-xxl-min ; - -//} From 854bd5f11476540d2e5ddef5e4e69fceac79fa76 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:34:30 +0000 Subject: [PATCH 70/82] 2.2.0 BreakpointExpand added --- rules/compiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/compiler.php b/rules/compiler.php index b2896c2..7909cb7 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -245,7 +245,7 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input if ($twbs_version > ' ' ) fwrite($tv_file, '$twbs_version: "' . $twbs_version . "\";\n"); if ($gplusProfile > ' ' ) fwrite($tv_file, '$gplusProfile: "' . $gplusProfile . "\";\n"); -if ($wsaNavbarExpand > ' ' ) fwrite($tv_file, '$wsaBreakpointExpand: ' . substr($wsaNavbarExpand,15) . ";\n"); +if ($wsaNavbarExpand > ' ' ) fwrite($tv_file, '$wsaBreakpointExpand: ' . substr($wsaNavbarExpand,14) . ";\n"); if ($fgColor > ' ' ) fwrite($tv_file, '$fgColor: ' . $fgColor . ";\n"); if ($brandImage > ' ' ) fwrite($tv_file, '$brandImage: ' . $brandImage . ";\n"); if ($brandSize > ' ' ) fwrite($tv_file, '$brandSize: ' . $brandSize . ";\n"); From 44e9d51fccc04471a8116851667b435c62294eaf Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Fri, 11 Oct 2024 14:08:46 +0000 Subject: [PATCH 71/82] 2.2.0 remove navbar expand xxxl ad xs --- language/en-GB/en-GB.tpl_wsa_bootstrap.ini | 4 ++-- language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini | 5 ++--- templateDetails.xml | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/language/en-GB/en-GB.tpl_wsa_bootstrap.ini b/language/en-GB/en-GB.tpl_wsa_bootstrap.ini index 5d50bee..2321653 100644 --- a/language/en-GB/en-GB.tpl_wsa_bootstrap.ini +++ b/language/en-GB/en-GB.tpl_wsa_bootstrap.ini @@ -61,12 +61,12 @@ WSA_CONTAINERXXXL_HINT="1520" WSA_NAVBAREXPAND_LABEL="Navbar expand:" WSA_NAVBAREXPAND_DESCRIPTION="Navbar expand from width" +WSA_NAVBAREXPAND_XS="Extra small" WSA_NAVBAREXPAND_SM="Small" WSA_NAVBAREXPAND_MD="Medium" WSA_NAVBAREXPAND_LG="Large" WSA_NAVBAREXPAND_XL="Extra large" -WSA_NAVBAREXPAND_XXL="X Extra large" -WSA_NAVBAREXPAND_XXXL="XX Extra large" +WSA_NAVBAREXPAND_XXL="X Extra large (only in BS5)" WSA_NAVTEXT_LABEL="Navtext(right):" WSA_NAVTEXT_DESCRIPTION="Text or Html right in navbar" diff --git a/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini b/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini index d51ab1f..85eb16b 100644 --- a/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini +++ b/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini @@ -62,13 +62,12 @@ WSA_CONTAINERXXXL_HINT="1520" WSA_NAVBAREXPAND_LABEL="Navbar expand:" WSA_NAVBAREXPAND_DESCRIPTION="Navigatie balk openen vanaf breedte" +WSA_NAVBAREXPAND_XS="Extra small" WSA_NAVBAREXPAND_SM="Small" WSA_NAVBAREXPAND_MD="Medium" WSA_NAVBAREXPAND_LG="Large" WSA_NAVBAREXPAND_XL="Extra large" -WSA_NAVBAREXPAND_XXL="X Extra large" -WSA_NAVBAREXPAND_XXXL="XX Extra large" - +WSA_NAVBAREXPAND_XXL="X Extra large (alleen in BS5)" WSA_NAVTEXT_LABEL="Navtext(rechts):" WSA_NAVTEXT_DESCRIPTION="Tekst of Html rechts in navbar" diff --git a/templateDetails.xml b/templateDetails.xml index 3db845b..4626297 100644 --- a/templateDetails.xml +++ b/templateDetails.xml @@ -165,12 +165,12 @@ label="WSA_NAVBAREXPAND_LABEL" description="WSA_NAVBAREXPAND_DESCRIPTION" > + -
Date: Fri, 11 Oct 2024 14:12:00 +0000 Subject: [PATCH 72/82] 2.2.0 rmoved xs doesn't work --- templateDetails.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/templateDetails.xml b/templateDetails.xml index 4626297..b964b98 100644 --- a/templateDetails.xml +++ b/templateDetails.xml @@ -165,7 +165,6 @@ label="WSA_NAVBAREXPAND_LABEL" description="WSA_NAVBAREXPAND_DESCRIPTION" > - From 8ac932bcc720e9eb78ba484e3429de8de6c3a6f5 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Sat, 12 Oct 2024 08:56:22 +0000 Subject: [PATCH 73/82] 2.2.0 navabar expand => desktopexpand --- index.php | 17 ++++++------ language/en-GB/en-GB.tpl_wsa_bootstrap.ini | 31 ++++++---------------- language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini | 31 ++++++---------------- rules/compiler.php | 4 +-- scss/_template_css.scss | 14 +++++----- templateDetails.xml | 16 +++++------ 6 files changed, 43 insertions(+), 70 deletions(-) diff --git a/index.php b/index.php index fe12fab..139a55c 100644 --- a/index.php +++ b/index.php @@ -43,7 +43,8 @@ and removed conditional inclusion BS stylesheet an javascript 01-10-2024 2.1.3 make content wider to display 3 columns in rssfoto newsfeed 02-10-2024 2.2.0 Remove support for BS (Bootstrap) 3, remove redundant span* classes inherited from grid Bootstrap 2 and used in Joomla 3, - which are replaced by col* classes since BS3 and Joomla 4. Updated to latest versions of BS4 (4.6.2) and BS5 (5.3.3) javascript and css and assosited libraries. + which are replaced by col* classes since BS3 and Joomla 4. Updated to latest versions of BS4 (4.6.2) and BS5 (5.3.3) javascript and css and assosited libraries. + navbarexpand => desktopexpand */ // copied from cassiopeia use Joomla\CMS\Factory; @@ -98,10 +99,10 @@ else { $wsaCssFilename = 'template.min.' . $templatestyleid . '.css';} -$twbs_version = htmlspecialchars($this->params->get('twbs_version', '4')); +$twbs_version = htmlspecialchars($this->params->get('twbs_version', '5')); $wsaTime = htmlspecialchars($this->params->get('wsaTime','')); $wsaTime = strtr($wsaTime, array(' '=> 't', ':' => '' )); -$wsaNavbarExpand = htmlspecialchars($this->params->get('wsaNavbarExpand', 'navbar-expand-md')); +$wsaDesktopExpand = htmlspecialchars($this->params->get('wsaDesktopExpand', 'lg')); ?> @@ -195,8 +196,8 @@ // Adjusting content width if ($this->countModules('position-7') && $this->countModules('position-8')) { - $spanc = "col-md-6" ; - $spans = "col-md-3"; + $spanc = 'col-' . $wsaDesktopExpand . '-6' ; + $spans = 'col-' . $wsaDesktopExpand . '-3'; } elseif (!$this->countModules('position-7') && !$this->countModules('position-8')) @@ -205,8 +206,8 @@ } else { - $spanc = "col-md-9"; - $spans = "col-md-3"; + $spanc = 'col-' . $wsaDesktopExpand . '-9'; + $spans = 'col-' . $wsaDesktopExpand . '-3'; } $hi_mods = ($this->countModules('position-0')? ' hipos0': '') . ($this->countModules('icons')? ' hiicons': '') @@ -281,7 +282,7 @@ class="site-grid site countModules('icons')) : ?> -
+ diff --git a/language/en-GB/en-GB.tpl_wsa_bootstrap.ini b/language/en-GB/en-GB.tpl_wsa_bootstrap.ini index 2321653..77ad4ae 100644 --- a/language/en-GB/en-GB.tpl_wsa_bootstrap.ini +++ b/language/en-GB/en-GB.tpl_wsa_bootstrap.ini @@ -43,30 +43,15 @@ WSA_LTR="Left to right" WSA_RTL="Right to left" WSA_DISPLAYSITENAME_LABEL="Display sitename:" WSA_DISPLAYSITENAME_DESCRIPTION="Display sitename in menubar." -WSA_BREAKPOINTES_LABEL="Breakpoint es:" -WSA_BREAKPOINTES_DESCRIPTION="Extra Breakpoint and Container es smaller than sm (576px)" -WSA_BREAKPOINTES_HINT="320" -WSA_BREAKPOINTXXL_LABEL="Breakpoint xxl:" -WSA_BREAKPOINTXXL_DESCRIPTION="Extra Breakpoint xxl larger than xl (1200px)" -WSA_BREAKPOINTXXL_HINT="1400" -WSA_BREAKPOINTXXXL_LABEL="Breakpoint xxxl:" -WSA_BREAKPOINTXXXL_DESCRIPTION="Extra Breakpoint xxxl larger than xxl" -WSA_BREAKPOINTXXXL_HINT="1600" -WSA_CONTAINERXXL_LABEL="Container xxl:" -WSA_CONTAINERXXL_DESCRIPTION="Maxwidth Container xxl larger than xl (1140px)" -WSA_CONTAINERXXL_HINT="1320" -WSA_CONTAINERXXXL_LABEL="Container xxxl:" -WSA_CONTAINERXXXL_DESCRIPTION="Maxwidth Container xxxl larger than xxl" -WSA_CONTAINERXXXL_HINT="1520" -WSA_NAVBAREXPAND_LABEL="Navbar expand:" -WSA_NAVBAREXPAND_DESCRIPTION="Navbar expand from width" -WSA_NAVBAREXPAND_XS="Extra small" -WSA_NAVBAREXPAND_SM="Small" -WSA_NAVBAREXPAND_MD="Medium" -WSA_NAVBAREXPAND_LG="Large" -WSA_NAVBAREXPAND_XL="Extra large" -WSA_NAVBAREXPAND_XXL="X Extra large (only in BS5)" +WSA_DESKTOPEXPAND_LABEL="Desktop layout breakpoint:" +WSA_DESKTOPEXPAND_DESCRIPTION="Desktop layout from breakpoint" +WSA_DESKTOPEXPAND_XS="Extra small" +WSA_DESKTOPEXPAND_SM="Small" +WSA_DESKTOPEXPAND_MD="Medium" +WSA_DESKTOPEXPAND_LG="Large" +WSA_DESKTOPEXPAND_XL="Extra large" +WSA_DESKTOPEXPAND_XXL="X Extra large (only in BS5)" WSA_NAVTEXT_LABEL="Navtext(right):" WSA_NAVTEXT_DESCRIPTION="Text or Html right in navbar" diff --git a/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini b/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini index 85eb16b..84b9580 100644 --- a/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini +++ b/language/nl-NL/nl-NL.tpl_wsa_bootstrap.ini @@ -44,30 +44,15 @@ WSA_RTL="Rechts naar links" WSA_DISPLAYSITENAME_LABEL="Toon sitenaam:" WSA_DISPLAYSITENAME_DESCRIPTION="Toon sitenaam in menubalk." -WSA_BREAKPOINTES_LABEL="Breakpoint es:" -WSA_BREAKPOINTES_DESCRIPTION="Extra Breakpoint en Container es kleiner dan sm (576px)" -WSA_BREAKPOINTES_HINT="320" -WSA_BREAKPOINTXXL_LABEL="Breakpoint xxl:" -WSA_BREAKPOINTXXL_DESCRIPTION="Extra Breakpoint xxl groter dan xl (1200px)" -WSA_BREAKPOINTXXL_HINT="1400" -WSA_BREAKPOINTXXXL_LABEL="Breakpoint xxxl:" -WSA_BREAKPOINTXXXL_DESCRIPTION="Extra Breakpoint xxxl groter dan xxl" -WSA_BREAKPOINTXXXL_HINT="1600" -WSA_CONTAINERXXL_LABEL="Container xxl:" -WSA_CONTAINERXXL_DESCRIPTION="Maxwidth Container xxl groter dan xl (1140px)" -WSA_CONTAINERXXL_HINT="1320" -WSA_CONTAINERXXXL_LABEL="Container xxxl:" -WSA_CONTAINERXXXL_DESCRIPTION="Maxwidth Container xxxl groter dan xxl" -WSA_CONTAINERXXXL_HINT="1520" -WSA_NAVBAREXPAND_LABEL="Navbar expand:" -WSA_NAVBAREXPAND_DESCRIPTION="Navigatie balk openen vanaf breedte" -WSA_NAVBAREXPAND_XS="Extra small" -WSA_NAVBAREXPAND_SM="Small" -WSA_NAVBAREXPAND_MD="Medium" -WSA_NAVBAREXPAND_LG="Large" -WSA_NAVBAREXPAND_XL="Extra large" -WSA_NAVBAREXPAND_XXL="X Extra large (alleen in BS5)" +WSA_DESKTOPEXPAND_LABEL="Desktop layout breakpoint:" +WSA_DESKTOPEXPAND_DESCRIPTION="Bureaubladindeling vanaf breekpunt" +WSA_DESKTOPEXPAND_XS="Extra small" +WSA_DESKTOPEXPAND_SM="Small" +WSA_DESKTOPEXPAND_MD="Medium" +WSA_DESKTOPEXPAND_LG="Large" +WSA_DESKTOPEXPAND_XL="Extra large" +WSA_DESKTOPEXPAND_XXL="X Extra large (alleen in BS5)" WSA_NAVTEXT_LABEL="Navtext(rechts):" WSA_NAVTEXT_DESCRIPTION="Tekst of Html rechts in navbar" diff --git a/rules/compiler.php b/rules/compiler.php index 7909cb7..3d64ae7 100644 --- a/rules/compiler.php +++ b/rules/compiler.php @@ -120,7 +120,7 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input $iconsPosLeft = htmlspecialchars($params->iconsPosLeft); $iconsPosTop = htmlspecialchars($params->iconsPosTop); $wsaIconsFlex = htmlspecialchars($params->wsaIconsFlex); -$wsaNavbarExpand = htmlspecialchars($params->wsaNavbarExpand); +$wsaDesktopExpand = htmlspecialchars($params->wsaDesktopExpand); $wsaNavbarRightWidth = htmlspecialchars($params->wsaNavbarRightWidth); $footerWidth = htmlspecialchars($params->footericonsWidth); $footerPosLeft = htmlspecialchars($params->footerPosLeft); @@ -245,7 +245,7 @@ public function test(\SimpleXMLElement $element, $value, $group = null, $input if ($twbs_version > ' ' ) fwrite($tv_file, '$twbs_version: "' . $twbs_version . "\";\n"); if ($gplusProfile > ' ' ) fwrite($tv_file, '$gplusProfile: "' . $gplusProfile . "\";\n"); -if ($wsaNavbarExpand > ' ' ) fwrite($tv_file, '$wsaBreakpointExpand: ' . substr($wsaNavbarExpand,14) . ";\n"); +if ($wsaDesktopExpand > ' ' ) fwrite($tv_file, '$wsaDesktopExpand: ' . $wsaDesktopExpand . ";\n"); if ($fgColor > ' ' ) fwrite($tv_file, '$fgColor: ' . $fgColor . ";\n"); if ($brandImage > ' ' ) fwrite($tv_file, '$brandImage: ' . $brandImage . ";\n"); if ($brandSize > ' ' ) fwrite($tv_file, '$brandSize: ' . $brandSize . ";\n"); diff --git a/scss/_template_css.scss b/scss/_template_css.scss index a84965b..34ee5da 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -97,8 +97,8 @@ body>div.container { padding: 0; } -.photo-album img, -.photo-in-album { +.photo-in-album, +.com-tags__items .list-group img { @include photo-box-shadow($photo-box-shadow); } @@ -117,9 +117,9 @@ body>div.container { } } -@include media-breakpoint-up($wsaBreakpointExpand) { +@include media-breakpoint-up($wsaDesktopExpand) { .blog-items, -.com-tags__items .list-group{ +.com-tags__items .list-group { @for $i from 2 through $grid-columns { &.columns-#{$i} { @@ -128,6 +128,9 @@ body>div.container { } } +.com-tags__items .list-group { + @include row-cols(3); + } } .header-inner { @@ -232,7 +235,6 @@ order: -1; margin-bottom: 0px; text-align: left; } -/* new test */ ol, ul, .com-newsfeeds-newsfeed__items { @include make-row(); @@ -245,7 +247,7 @@ order: -1; @include media-breakpoint-up(sm) { @include make-col(6); } - @include media-breakpoint-up(lg) { + @include media-breakpoint-up($wsaDesktopExpand) { @include make-col(4); } diff --git a/templateDetails.xml b/templateDetails.xml index b964b98..080b39b 100644 --- a/templateDetails.xml +++ b/templateDetails.xml @@ -161,15 +161,15 @@ hint="WSA_BREAKPOINTXXXL_HINT" /> --> - - - - - - + + + + + Date: Sat, 12 Oct 2024 09:17:13 +0000 Subject: [PATCH 74/82] 2.2.0 --- scss/_template_css.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 34ee5da..18e66e7 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -108,6 +108,8 @@ body>div.container { flex-direction:row; > * { @include make-col-ready(); + border: 0; + margin: 0; img { max-width: 100%; height:auto; } From 188d3123feab231c4893d87fb3b387c2682523d7 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Sat, 12 Oct 2024 12:57:49 +0000 Subject: [PATCH 75/82] 2.2.0 --- scss/_template_css.scss | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 18e66e7..2971715 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -98,6 +98,8 @@ body>div.container { } .photo-in-album, +.photo-album .blog-items img, +.blog-items.photo-album img, .com-tags__items .list-group img { @include photo-box-shadow($photo-box-shadow); } From 9de9213877c0f3f90404d007d1f3e994cf62c17d Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:03:38 +0000 Subject: [PATCH 76/82] 2.2.0 begin combining rssfoto newsfeed and blog-items and tag items photos --- scss/_template_css.scss | 140 +++++++++++++++++++--------------------- 1 file changed, 65 insertions(+), 75 deletions(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 2971715..0cc9b91 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -89,6 +89,7 @@ body>div.container { /* blog process joomla colums-n across for n= 1 to 12 to BS row and classes */ [class^="com-content"][class$="blog"], +[class*="rssfoto"] .newsfeed, .blog-featured, .com-tags__items { // @include make-container(); only width 100% remains @@ -100,12 +101,14 @@ body>div.container { .photo-in-album, .photo-album .blog-items img, .blog-items.photo-album img, -.com-tags__items .list-group img { +.com-tags__items .list-group img, +[class*="rssfoto"] .com-newsfeeds-newsfeed__items img { @include photo-box-shadow($photo-box-shadow); } .blog-items, -.com-tags__items .list-group { +.com-tags__items .list-group, +.com-newsfeeds-newsfeed__items { @include make-row(); flex-direction:row; > * { @@ -121,9 +124,18 @@ body>div.container { } } +/* Desktop Layout menu expand, multi columns work */ @include media-breakpoint-up($wsaDesktopExpand) { +// default desktop layout columns +.com-tags__items ul { + @include row-cols(3); +} + +// desktop lay-out with columns-n class .blog-items, -.com-tags__items .list-group { +.com-tags__items .list-group, +.com-newsfeeds-newsfeed__items + { @for $i from 2 through $grid-columns { &.columns-#{$i} { @@ -132,10 +144,7 @@ body>div.container { } } -.com-tags__items .list-group { - @include row-cols(3); - } -} +} // End Desktop Layout .header-inner { display: flex; @@ -145,7 +154,55 @@ flex-direction: column; .navbar>.container, .navbar>.container-fluid { align-items: flex-start; } -} +} + +/* adaptations for newsfeeds */ +/* rss fotos of flickr suffix _rssfoto */ +/* rss fotos of flickr met suffix _rssfoto */ +/* rss flickr images (ul li p a img) */ +[class*="rssfoto"] .newsfeed { + + h2, .com-newsfeeds-newsfeed__feed-image + { + margin: 0; + font-weight: bold; + font-family: Helvetica,Arial,sans-serif; + font-size: 1.5em; + padding-left: 0px; + margin-bottom: 10px; + text-align: left; + } + + h3 + { + font-size: 1.3em; + line-height: 1.3em; + padding-left: 0px; + margin-bottom: 0px; + text-align: left; + } + li + { + @include make-col-ready(); + list-style-type: none; + overflow: hidden; + + div.feed-item-description p:first-child + { /* make unwanted image header text from newsfeed invisible */ + font-size: 4%; + color: transparent; + a + { + font-size: 2500%; + color: $link-color; + } + } + + } + +} /* end rssfoto newsfeed */ + + .icon-cog, .icons .icon-cog @@ -210,73 +267,6 @@ order: -1; } /* einde tijdelijk toegvoegd voor bs 3 */ -/* adaptations for newsfeeds */ -/* rss fotos of flickr suffix _rssfoto */ -/* rss fotos of flickr met suffix _rssfoto */ -/* rss flickr images (ul li p a img) */ -[class*="rssfoto"] .newsfeed { - @include make-container(); - margin: 0; - padding: 0; - width: auto; - - h2, .com-newsfeeds-newsfeed__feed-image - { - margin: 0; - font-weight: bold; - font-family: Helvetica,Arial,sans-serif; - font-size: 1.5em; - padding-left: 0px; - margin-bottom: 10px; - text-align: left; - } - - h3 - { - font-size: 1.3em; - line-height: 1.3em; - padding-left: 0px; - margin-bottom: 0px; - text-align: left; - } - ol, ul, .com-newsfeeds-newsfeed__items - { - @include make-row(); - padding:0; - } - li - { - @include make-col-ready(); - - @include media-breakpoint-up(sm) { - @include make-col(6); - } - @include media-breakpoint-up($wsaDesktopExpand) { - @include make-col(4); - } - - list-style-type: none; - overflow: hidden; - - a img - { - @include photo-box-shadow($photo-box-shadow); - } - - div.feed-item-description p:first-child - { /* make unwanted image header text from newsfeed invisible */ - font-size: 4%; - color: transparent; - a - { - font-size: 2500%; - color: $link-color; - } - } - - } - -} /* end rssfoto newsfeed */ .tag-category fieldset { /* tot joomla het zoekveld goed verbergt */ From 872aa9eedc4084f80a00a194df72febfe313da54 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Tue, 15 Oct 2024 13:58:49 +0000 Subject: [PATCH 77/82] 2.2.0 rss combined with tag-item-list and blog-list --- scss/_template_css.scss | 137 +++++++++++++++++++--------------------- 1 file changed, 64 insertions(+), 73 deletions(-) diff --git a/scss/_template_css.scss b/scss/_template_css.scss index 0cc9b91..a776e97 100644 --- a/scss/_template_css.scss +++ b/scss/_template_css.scss @@ -27,7 +27,7 @@ // but an extra class in the page header, ul may be used in stead of ol and Pias is stopped. So .newsfeed_rssfoto is approximately // replaced by by ._rssfoto .newsfeed. At the same time make more use of scss possibillities use css attribute match selectors and // remove unnecessary selectors. -// 20241007 2.2.0 remove BS3 and replace some variables with BS4 BS5 standard +// 20241007 2.2.0 remove BS3 and replace some variables with BS4 BS5 standard. rss combined with tag-item-list and blog-list. /* =========================== alle schermbreedtes Write your general styles eerst voor alle schermbreedtes, @@ -96,7 +96,6 @@ body>div.container { width: 100%; margin: 0; padding: 0; - } .photo-in-album, .photo-album .blog-items img, @@ -115,6 +114,8 @@ body>div.container { @include make-col-ready(); border: 0; margin: 0; + list-style-type: none; + overflow:hidden; img { max-width: 100%; height:auto; } @@ -122,46 +123,10 @@ body>div.container { &[class*="columns"] { @include row-cols(1); } - -} -/* Desktop Layout menu expand, multi columns work */ -@include media-breakpoint-up($wsaDesktopExpand) { -// default desktop layout columns -.com-tags__items ul { - @include row-cols(3); -} - -// desktop lay-out with columns-n class -.blog-items, -.com-tags__items .list-group, -.com-newsfeeds-newsfeed__items - { - @for $i from 2 through $grid-columns { - - &.columns-#{$i} { - @include row-cols($i); - } - } - } -} // End Desktop Layout -.header-inner -{ -display: flex; -flex-direction: column; - .navbar{width: 100%; - } - .navbar>.container, .navbar>.container-fluid { - align-items: flex-start; - } -} - -/* adaptations for newsfeeds */ -/* rss fotos of flickr suffix _rssfoto */ -/* rss fotos of flickr met suffix _rssfoto */ +/* adaptations for newsfeeds with photos (class rssfoto). */ /* rss flickr images (ul li p a img) */ [class*="rssfoto"] .newsfeed { - h2, .com-newsfeeds-newsfeed__feed-image { margin: 0; @@ -172,7 +137,6 @@ flex-direction: column; margin-bottom: 10px; text-align: left; } - h3 { font-size: 1.3em; @@ -183,10 +147,6 @@ flex-direction: column; } li { - @include make-col-ready(); - list-style-type: none; - overflow: hidden; - div.feed-item-description p:first-child { /* make unwanted image header text from newsfeed invisible */ font-size: 4%; @@ -197,12 +157,43 @@ flex-direction: column; color: $link-color; } } - } - } /* end rssfoto newsfeed */ - +/* Desktop Layout menu expand, multi columns */ +@include media-breakpoint-up($wsaDesktopExpand) { +// default desktop layout columns +.com-tags__items .list-group, +.com-newsfeeds-newsfeed__items { + @include row-cols(3); +} +// desktop lay-out with columns-n class +@for $i from 2 through $grid-columns { + .columns-#{$i} {.blog-items, + .com-tags__items .list-group, + .com-newsfeeds-newsfeed__items { + @include row-cols($i); + } + } + .blog-items, + .com-tags__items .list-group, + .com-newsfeeds-newsfeed__items { + &.columns-#{$i} { + @include row-cols($i); + } + } +} +} // End Desktop Layout +.header-inner +{ +display: flex; +flex-direction: column; + .navbar{width: 100%; + } + .navbar>.container, .navbar>.container-fluid { + align-items: flex-start; + } +} .icon-cog, .icons .icon-cog @@ -273,32 +264,32 @@ order: -1; display: $tagItemSearchDisplay; } -.tag-category ul -{ /* tag-list inline maken in plaats van opsomming */ - padding-left: 0; - - li - { - display: inline-block; - position: static; - vertical-align: top; - max-width: 100%; - margin-right: $marginArea; - margin-bottom: $marginArea; - } - &.category.list-striped li /* element rij alleen in tag-lijst, vaste breedte */ - { - background-color: transparent; - max-width: 100%; - width: $asMinWidthItem; - - } - - li h3 - { - display: $tagItemTitleDisplay; - } -} +//.tag-category ul +//{ /* tag-list inline maken in plaats van opsomming */ +// padding-left: 0; +// +// li +// { +// display: inline-block; +// position: static; +// vertical-align: top; +// max-width: 100%; +// margin-right: $marginArea; +// margin-bottom: $marginArea; +// } +// &.category.list-striped li /* element rij alleen in tag-lijst, vaste breedte */ +// { +// background-color: transparent; +// max-width: 100%; +// width: $asMinWidthItem; +// +// } +// +// li h3 +// { +// display: $tagItemTitleDisplay; +// } +//} body { font-family: Verdana, Arial, sans-serif; From b584fee65622cae7e9764b85c075348c649d95d1 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Wed, 16 Oct 2024 09:51:41 +0000 Subject: [PATCH 78/82] 2.2.0 removed double loading jquery in BS4 --- README.md | 2 ++ index.php | 8 ++++---- templateDetails.xml | 30 ++---------------------------- 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 5edb875..b75faeb 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,6 @@ This project is licensed under the [GNU GPL], version 3 or later. original scss files of BS4 and BS5 in folders scss bs4 and bs5. New scss compiler scssphp/scssphp 1.13.0 and server scssphp/server 1.1.0 as continuation of leafo/scssphp Remove options for extra/override breakpoints. + Implement class .columns-n in component at page level and desktoplay-out for tagged-items, category-blog, newsfeed, and featured-articles. + For category-blog and featured-articles also in blog-layout ((leading) article class and #columns). * 2.1.2 removed hard returns from documentation field because j4.4 + doesn't accept that. diff --git a/index.php b/index.php index 139a55c..a1dc08f 100644 --- a/index.php +++ b/index.php @@ -44,7 +44,7 @@ 01-10-2024 2.1.3 make content wider to display 3 columns in rssfoto newsfeed 02-10-2024 2.2.0 Remove support for BS (Bootstrap) 3, remove redundant span* classes inherited from grid Bootstrap 2 and used in Joomla 3, which are replaced by col* classes since BS3 and Joomla 4. Updated to latest versions of BS4 (4.6.2) and BS5 (5.3.3) javascript and css and assosited libraries. - navbarexpand => desktopexpand + navbarexpand => desktopexpand. removed double loading jquery in BS4 */ // copied from cassiopeia use Joomla\CMS\Factory; @@ -137,8 +137,8 @@ // break; case "4" : { $wa->registerStyle('bootstrap.css', 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css', ['version'=>'4.6.2'], ['integrity' => 'sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N', 'crossorigin' => 'anonymous'],[]) - ->registerScript('jquery.js', 'https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js', ['version'=>'3.5.1'], ['integrity' => 'sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj', 'crossorigin' => 'anonymous', 'defer' => TRUE],[]) - ->registerScript('bootstrap.js', 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js', ['version'=>'4.6.2'], ['integrity' => 'sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct', 'crossorigin' => 'anonymous', 'defer' => TRUE],['jquery.js']) +// ->registerScript('jquery', 'https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js', ['version'=>'3.5.1'], ['integrity' => 'sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj', 'crossorigin' => 'anonymous', 'defer' => TRUE],[]) + ->registerScript('bootstrap.js', 'https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js', ['version'=>'4.6.2'], ['integrity' => 'sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct', 'crossorigin' => 'anonymous', 'defer' => TRUE],['jquery']) ; } } @@ -177,7 +177,7 @@ break; case "4" : { $this->addScript('https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js', array('version'=>'3.5.1'), - array('id'=>'jquery.js', 'integrity' => 'sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj', 'crossorigin' => 'anonymous')); + array('id'=>'jquery', 'integrity' => 'sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj', 'crossorigin' => 'anonymous')); $this->addScript('https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js', array('version'=>'4.6.2'), array('id'=>'bootstrap.min.js', 'integrity' => 'sha384-Fy6S3B9q64WdZWQUiU+q4/2Lc9npb8tCaSX9FK7E8HnRr0Jz8D6OP9dO5Vg3Q9ct', 'crossorigin' => 'anonymous')); } diff --git a/templateDetails.xml b/templateDetails.xml index 080b39b..9324659 100644 --- a/templateDetails.xml +++ b/templateDetails.xml @@ -8,7 +8,7 @@ wsa_bootstrap 2.2.0.dev - 10-10-2024 + 16-10-2024 AHC Waasdorp info@waasdorpsoekhan.nl http://www.waasdorpsoekhan.nl @@ -135,32 +135,6 @@ - - + From 3e7be227f14f42dd11f0146988e126f0fca42019 Mon Sep 17 00:00:00 2001 From: Bram Waasdorp <11373174+bramwaas@users.noreply.github.com> Date: Thu, 17 Oct 2024 16:50:44 +0000 Subject: [PATCH 79/82] 2.2.0 navbar-expand in default lay-out --- html/mod_menu/default.php | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/html/mod_menu/default.php b/html/mod_menu/default.php index b097ed0..16bf3b5 100644 --- a/html/mod_menu/default.php +++ b/html/mod_menu/default.php @@ -18,6 +18,7 @@ * 30-12-2021 overbodige container-fluid bij eerder verwijderde navbar-inner verwijderd vanwege onnodige padding. * 31-1-2022 referentie naar 'default_'.$item->type verbeterd, zodat deze ook bij gebruik in ander template werkt * entries voor seperator en heading gekopieerd van mod_menu + * 17-10-22 2.2.0 wsaDesktopExpand replaces breakpoint of wsaNavbarExpand */ \defined('_JEXEC') or die; @@ -42,7 +43,7 @@ if ($twbs_version == 3) { $menuType = str_replace(array("light", "dark", "bg-"), array("default", "inverse", ""), $menuType); } -$wsaNavbarExpand = htmlspecialchars($app->getTemplate(true)->params->get('wsaNavbarExpand', 'navbar-expand-md')); +$wsaDesktopExpand = htmlspecialchars($app->getTemplate(true)->params->get('wsaDesktopExpand', 'xl')); $wsaNavtext = ($app->getTemplate(true)->params->get('wsaNavtext')); $moduleTag = $params->get('module_tag', 'div'); @@ -84,7 +85,7 @@ function wsa_load($position, $style = 'none') - < class="navbar " role="navigation"> + < class="navbar navbar-expand- " role="navigation"> " ") : ?> @@ -101,25 +102,11 @@ function wsa_load($position, $style = 'none') \n"; ?> - - -