How to rewrite SASS map-merge, map-get in LESS - sass

Can you help me to write some code for create sprite template in Less via gulp spritesmith?
I have sprite.template.mustache with Sass functions and mixins:
$icons: (0:0)
{{#items}}
$icons: map-merge($icons,({{name}}: (X: {{px.offset_x}}, Y:{{px.offset_y}}, W: {{px.width}}, H: {{px.height}}, TW: {{px.total_width}}, TH: {{px.total_height}}, IMG: '{{{escaped_image}}}')))
{{/items}}
{{#options.functions}}
// Gets an attribute from the sass map
#function icon-attr($icon, $attr)
$icon: map-get($icons, $icon)
#return map-get($icon, $attr)
#mixin sprite($iconName)
background-image: url(icon-attr($iconName, IMG))
width: icon-attr($iconName, W)
height: icon-attr($iconName, H)
background-position: icon-attr($iconName, X) icon-attr($iconName, Y)
#mixin sprite-position($iconName)
background-position: icon-attr($iconName, X) icon-attr($iconName, Y)
#mixin sprite-retina($iconName)
background-image: url(icon-attr($iconName, IMG))
$width: icon-attr($iconName, W)
$height: icon-attr($iconName, H)
width: $width/2
height: $height/2
$x: icon-attr($iconName, X)
$y: icon-attr($iconName, Y)
background-position: $x/2 $y/2
$tw: icon-attr($iconName, TW)
$th: icon-attr($iconName, TH)
background-size: $tw/2 $th/2
{{/options.functions}}
I have some trouble with rewriting functions: "map-merge" and "map-get" to Less.
I know that there are no such functions in LESS, but I also know that there are own arrays that can be configured.

Here is the result that I got:
{{#items}}
#{{name}}: {{px.offset_x}}, {{px.offset_y}}, {{px.width}}, {{px.height}}, {{px.total_width}}, {{px.total_height}}, '{{{escaped_image}}}';
{{/items}}
// #{{name}} - name of the img.
{{#options.functions}}
.icon-attr(#icon){
#url: extract(#icon, 7);
#width: extract(#icon, 3);
#height: extract(#icon, 4);
#positionX: extract(#icon, 1);
#positionY: extract(#icon, 2);
#total_width: extract(#icon, 5);
#total_height: extract(#icon, 6);
}
{{/options.functions}}
.sprite(#icon){
.icon-attr(#icon);
display: inline-block;
background-image: url(#url);
width: #width;
height: #height;
background-position: #positionX #positionY;
}
.sprite-position(#icon){
.icon-attr(#icon);
background-position: #positionX #positionY;
}
.sprite-retina(#icon){
.icon-attr(#icon);
background-image: url(#url);
#width_retina: #width;
#height_retina: #height;
width: #width_retina/2;
height: #height_retina/2;
#x: #positionX;
#y: #positionY;
background-position: #x/2 #y/2;
#tw: #total_width;
#th: #total_height;
background-size: #tw/2 #th/2;
}
Example of use:
.icon-search {
.sprite(#search);
}

For a complex map-like data structures manipulation see Lists Less plugin.
But for this particular snippet you don't in fact need any complex structures and thus extra plugins/functions. Plain mixins can serve as a map and its functions in this case just perfect.
Minimal illustrative example:
// declare icon map, each item is injected via {{#items}} template:
.icon(foo) {
#x: 11;
#y: 22;
// etc.
}
.icon(bar) {
#x: 33;
#y: 44;
// etc.
}
// using the map:
.sprite-retina(#icon-name) {
// expand icon properties into this scope:
.icon(#icon-name);
// use the propertes:
x: #x;
y: #y;
// etc.
}

Related

Represent a three.js GUI button with an icon

I want to communicate a "Go Left" button, in a three.js application, by using a left-arrow icon (instead of just labelling it "left")
Many of the three.js examples use dat.GUI to set up GUI control (e.g. button, slider). In all these examples the buttons show up as rectangular boxes
Is it possible to represent a dat.GUI button with an icon? (or at least place a background image behind the button?)
Otherwise, are there other GUI alternatives that are easy to use with three.js?
EDIT:
I'm having trouble to embed the css code inside javascript.
I added the code below and when I click on the button it displays in the console "BEG setStyle", i.e. the function setStyle() is executed.
But I don't see a change in the color or the background image of the "Nukeem all!" button.
#prisoner849 Can you help me with this?
Thanks
var gui = new dat.GUI(),
var obj = {
add:function()
{
console.log("clicked")
updateTheta();
this.setStyle();
},
setStyle:function()
{
console.log("BEG setStyle")
this.color = "#00ff00";
this.backgroundImage = "url('https://cdn4.iconfinder.com/data/icons/6x16-free-application-icons/16/Radiation.png')";
}
};
gui.add(obj, 'add').name('Nukeem all!');
Thanks.
TheJim01 is right. You can do the trick with CSS.
Here is just a rough concept:
var gui = new dat.GUI();
var obj = {
add: function() {
alert("clicked!")
}
};
gui.add(obj, "add").name("Nuke'em all!");
gui.add(obj, "add").name("I'm Fine!");
gui.add(obj, "add").name("Harmony");
var fourth = gui.add(obj, "add").name("CSS is awesome!");
var fourthStyle = fourth.domElement.previousSibling.style;
fourthStyle.backgroundImage = 'url(https://cdn1.iconfinder.com/data/icons/hawcons/32/700035-icon-77-document-file-css-16.png)';
fourthStyle.backgroundRepeat = 'no-repeat';
fourthStyle.backgroundPosition = 'left';
fourthStyle.backgroundColor = 'white';
fourthStyle.color = 'black';
console.log(fourthStyle);
.function:nth-child(1) .property-name {
background-image: url('https://cdn4.iconfinder.com/data/icons/6x16-free-application-icons/16/Radiation.png');
background-repeat: no-repeat;
background-position: right;
background-color: gray;
color: yellow;
}
.function:nth-child(2) .property-name {
background-image: url('https://cdn4.iconfinder.com/data/icons/6x16-free-application-icons/16/OK.png');
background-repeat: no-repeat;
background-position: center;
background-color: teal;
color: aqua;
}
.function:nth-child(3) .property-name {
background-image: url('https://cdn4.iconfinder.com/data/icons/6x16-free-application-icons/16/In-yang.png');
background-repeat: no-repeat;
background-position: left;
background-color: pink;
color: red;
text-align: right;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.1/dat.gui.min.js"></script>

extend Compass breakpoint mixin to avoid duplicates

I am using Compass mixin to create media queries for retina like in example:
header {
height: $header-image-height;
text-align: center;
position: relative;
#include breakpoint($standard-resolution) {
background:
linear-gradient(
rgba(0, 0, 0, 0.1),
rgba(0, 0, 0, 0.1)
),
url(../../img/dist/xxx.jpg) center center no-repeat;
}
#include breakpoint($retina-resolution) {
background:
linear-gradient(
rgba(0, 0, 0, 0.1),
rgba(0, 0, 0, 0.1)
),
url(../../img/dist/xxx_2x.jpg) center center no-repeat;
background-size: 1176px auto;
}
color: $header-color;
#extend %montserrat-bold;
}
It works well. But if I put the same mixin into another element, I will get duplicated output of #media at the end - one for each element:
#media screen and (max-resolution: 1.9999dppx), screen and (-webkit-max-device-pixel-ratio: 1.9999), screen and (max--moz-device-pixel-ratio: 1.9999), screen and (max-resolution: 191.9904dpi) {
header {
background: linear-gradient(rgba(0, 0, 0, 0.1), rgba(0, 0, 0, 0.1)), url(../../img/dist/xxx.jpg) center center no-repeat;
}
}
And the same output for another elements. Is there any way I could somehow make placeholder from this mixin, so all elements would be under the same single #media directive?
I found a good solution to avoid duplicate code on the output.
First of all there is a good tool to manage breakpoints called maps:
$breakpoints: (
'retina':
//here put all your breakpoints
)
Second instead of putting breakpoint inside each target element, it is better to put #include directive to the root and inside it put all your elements with new directive respond to like this (I have created separate file for this):
_retina.scss:
#include respond-to(retina) {
element1 {}
.element2 {}
}
End not duplicated code))) I hope it will help somebody. By the way I have discovered that Compass sucks((( I wont use it anymore.

Updating variables created by lighten/darken functions by modifying the original base color afterwards

I'm currently trying to create a mix-in that will let me build buttons with hover values using the darken and lighten color functions in sass. My code for some reason is spitting out white and black for the background color instead of the hex value of a returned color. Here it is on code pen: http://codepen.io/malikabee/pen/vEQZOv
$btn_color: #fff;
$btn_alpha: 1;
$btn_color_amount: 100%;
$color_funcs: (
'darken': darken($btn_color, $btn_color_amount),
'lighten': lighten($btn_color, $btn_color_amount),
'transparentize': transparentize($btn_color, $btn_alpha)
);
#mixin _btn_color($base_color, $amount, $hover){
background: $base_color;
a:hover,
a:focus{
#each $func_name, $color_func in $color_funcs{
#if($func_name == $hover){
$btn_color: $base_color;
$btn_color_amount: $amount;
background-color: $color_func;
}
}
}
}
.btn{
display: inline-block;
vertical-align: bottom;
text-align: center;
border-radius: 10px;
text-decoration: none;
}
.btn_blue{
#include _btn_color(#3c3c3c, 10%, 'darken');
}
Once you get past this block of code, the expressions don't exist anymore, only the value they evaluated to does:
$color_funcs: (
'darken': darken($btn_color, $btn_color_amount),
'lighten': lighten($btn_color, $btn_color_amount),
'transparentize': transparentize($btn_color, $btn_alpha)
);
Changing $btn_color after this point does nothing. Sass cannot to go back in time and re-run those expressions because they've already been evaluated using the original color (black).
What you can do instead is use the call function.
#mixin _btn_color($base_color, $amount, $func){
background: $base_color;
a:hover,
a:focus{
background-color: call($func, $base_color, $amount);
}
}
.btn_blue{
#include _btn_color(blue, 10%, 'darken');
color: white;
}

Create square divs using susy-grid

Is it possible to have #include span(3 of 12) return in pixels instead of a %?
I'm trying to create square elements, and I want the height of this element to be equal to its width.
.myElement {
width: span(3 of 12)
height: span(3 of 12)
}
Of course this causes height to be a %, which is really a % of its parent container, so it is not equal to the width! Any ideas?
Not impossible at all — just tricky (if you want a fluid square).
// Static width/height is simple
.square-a {
#include span(2 static);
height: span(2 static);
}
// Fluid takes a bit more work
.square-b {
#include span(2);
height: 0;
// %-Padding is always relative to parent width
padding-top: span(2);
position: relative;
// Inner element positioned to fit space
span {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
}
Here's a demo of both.

Extract body class for use in Scss

I am learning Sass but a bit stuck trying to work something out. I'd like to have a unique background image and header image on different pages. How can I perhaps extract the body class name form the markup and interpret that in scss?
Essentially I require some way to prevent having to do this (which is totally the point of scss right?!)
body.page1 {
background: url(../img/bkg-page1.png) left top repeat-x;
header {
background: url(../img/header-page1.png) center top no-repeat;
height: 320px;
}
}
body.page2 {
background: url(../img/bkg-page2.png) left top repeat-x;
header {
background: url(../img/header-page2.png) center top no-repeat;
height: 320px;
}
}
I realise using variables is the right direction, but not sure how to relay the markup class to the scss.
Any pointers would be most appreciated.
What you're looking for is an #each loop:
#each $class in (page1, page2, page3) {
body.#{$class} {
background: url(../img/bkg-#{$class}.png) left top repeat-x;
header {
background: url(../img/header-#{$class}.png) center top no-repeat;
height: 320px;
}
}
}
This assumes that the class name corresponds to the image name, as indicated in your sample.
body.page1 {
background: url(../img/bkg-page1.png) left top repeat-x;
}
body.page1 header {
background: url(../img/header-page1.png) center top no-repeat;
height: 320px;
}
body.page2 {
background: url(../img/bkg-page2.png) left top repeat-x;
}
body.page2 header {
background: url(../img/header-page2.png) center top no-repeat;
height: 320px;
}
body.page3 {
background: url(../img/bkg-page3.png) left top repeat-x;
}
body.page3 header {
background: url(../img/header-page3.png) center top no-repeat;
height: 320px;
}
You could use a #for loop instead (which eliminates the need for the list of class names) if your class names are always going to have numbers at the end of their name.

Resources