I try to learn scss list with mixins.
I wrote a simple mixin which add a background-url regarding the variables in a list.
It's written in a _mixins.scss file :
$path: "../images/";
#mixin dynamic-bg($path, $type, $ext) {
#each $source in $source-list {
&[data-bg="#{$source}"] {
background: url($path + $source + '_' + $type + '.' + $ext) no-repeat;
}
}
}
I call it in another file, and "describe" the list content just before :
a {
$source-list: "alpha", "beta", "gamma"
#include dynamic-bg($path, "logo", "png");
}
It should result in CSS like this :
a[data-bg="alpha"] {
background: url("../images/alpha_logo.png") no-repeat;
}
a[data-bg="beta"] {
background: url("../images/beta_logo.png") no-repeat;
}
a[data-bg="gamma"] {
background: url("../images/gamma_logo.png") no-repeat;
}
But I get this error :
Undefined variable: "$source-list"
It works fine if I add the list content before the mixin in _mixins.scss, but if so I can't re-use it over and over just by modifying the list's content.
Am I missing something?
Thanks in advance,
AW
It works fine if I add the list content before the mixin in _mixins.scss, but if so I can't re-use it over and over just by modifying the list's content.
When calling the mixin your list is out of scope, because you defined it within the a { ... } part. To make the list visible to your mixin you would have to define the list outside (not necessarily before the mixin, but at least before you call the mixin).
$path: "../images/";
#mixin dynamic-bg($path, $type, $ext) {
#each $source in $source-list {
&[data-bg="#{$source}"] {
background: url($path + $source + '_' + $type + '.' + $ext) no-repeat;
}
}
}
$source-list: "alpha", "beta", "gamma";
a {
#include dynamic-bg($path, "logo", "png");
}
$source-list: "new1", "new2";
strong {
#include dynamic-bg($path, "logo", "png");
}
compiles to:
a[data-bg="alpha"] {
background: url("../images/alpha_logo.png") no-repeat;
}
a[data-bg="beta"] {
background: url("../images/beta_logo.png") no-repeat;
}
a[data-bg="gamma"] {
background: url("../images/gamma_logo.png") no-repeat;
}
strong[data-bg="new1"] {
background: url("../images/new1_logo.png") no-repeat;
}
strong[data-bg="new2"] {
background: url("../images/new2_logo.png") no-repeat;
}
If you put the list inside of the a for the reason that no other definition should be able to make use of it, you'd better go for an additional (optional) mixin parameter:
#mixin dynamic-bg($path, $type, $ext, $sources: $source-list) {
#each $source in $sources {
&[data-bg="#{$source}"] {
background: url($path + $source + '_' + $type + '.' + $ext) no-repeat;
}
}
}
$source-list: "default-1", "default-2";
a {
$source-list: "alpha", "beta", "gamma";
#include dynamic-bg($path, "logo", "png", $source-list);
}
strong {
#include dynamic-bg($path, "logo", "png");
}
compiles to:
a[data-bg="alpha"] {
background: url("../images/alpha_logo.png") no-repeat;
}
a[data-bg="beta"] {
/* ... */
strong[data-bg="default-1"] {
background: url("../images/default-1_logo.png") no-repeat;
}
strong[data-bg="default-2"] {
/* ... */
or just like the following with a required parameter and no additional $source-list variable:
#mixin dynamic-bg($path, $type, $ext, $source-list) {
#each $source in $source-list {
&[data-bg="#{$source}"] {
background: url($path + $source + '_' + $type + '.' + $ext) no-repeat;
}
}
}
a {
#include dynamic-bg($path, "logo", "png", ("alpha", "beta", "gamma"));
}
strong {
#include dynamic-bg($path, "logo", "png", ("strong-1", "strong-2"));
}
Related
I'm making changes to website front and I need to change the "sidebar(vertical_categories)" so that it doesn't open to side, but that it always open under the chosen category(category_list_large).
I've tried to change the CSS stylesheet, so that it could be done with as few changes as possible to the Click -function. I tried that classes .category_expanded_container and .category_list_large were in the same grid_area, but I didn't get it to work. I add some pictures from the old and new layout, so it's easier to understand. Any help is welcome, thanks for advance.
Old layout
New layout, how it should appear after changes
Here is the Class for Category
class CategoryListViewer {
private $categoryTree = [];
private $prevItemDepth = NULL;
public function __construct($categoryTree) {
$this->categoryTree = $categoryTree;
}
public function show() {
echo '<div class="category_list">';
foreach ($this->categoryTree as $item) {
$this->showCategoryItem($item);
}
echo '</div>';
}
private function showCategoryItem($item) {
if ($item->isImage()) {
$body = '<img src="'.$item->getImage().'" border="0" alt="'.$item->getName().'">';
} else {
$body = $item->getName();
}
if ($item->getDepth() == 1) {
$is_category_header = count($item->getSubcategories()) > 0 ? true : false;
$cat_head_class = $is_category_header ? 'category_list_header' : '';
$cat_head_text_class = $is_category_header ? 'category_list_header_text' : '';
if ($item->isLink()) {
echo '<div class="category_list_large '.$cat_head_class.'"><a class="category_list_color" href="'.$item->getLink().'"><div class="category_link '.$cat_head_text_class.'">'.$body.'</div></a>';
} else {
echo '<div class="category_list_large category_list_color '.$cat_head_class.'"><div class="category_nonlink category_list_color '.$cat_head_text_class.'">'.$body.'</div>';
}
if ($is_category_header) {
echo '<div class="category_side_box category_expand" data-category-expanded="false">';
echo '<i class="icon-chevron-right icon-1x category_list_color"></i>';
echo '</div>';
}
echo '</div>';
if (count($item->getSubcategories()) > 0) {
echo '<div class="category_list_sub_container" data-template="true">';
foreach ($item->getSubcategories() as $i) {
$this->showCategoryItem($i);
}
echo '</div>';
}
} elseif ($item->getDepth() == 2) {
echo '<div class="category_list_sub category_link">'.$body.'</div></div>';
}
}
}
Here is click -function
$('.category_expand').live('click', function(){
let expanded = $(this).attr('data-category-expanded') === 'true' ? true : false;
let content = $(this).parent('.category_list_header').next('.category_list_sub_container');
let header_text = $(this).parent('.category_list_header').find('.category_list_header_text').text();
let container = $('.vertical_categories')[0];
let offset = $(this).position().top;
let offset_div = $('<div class="subcategory_offset"></div>');
$(offset_div).css('width','100%').css('height','calc('+offset+'px - 5.1em)');
$('.category_expand.active').toggleClass('active', false);
if ($('.category_expanded_header').length > 0){
let old_header = $('.expanded_header_text').text();
$('.category_expanded_container').remove();
toggleCategoryShroud(false);
if (old_header === header_text){
return false;
}
}
let expanded_container = $('<div class="category_expanded_container"></div>');
let expanded_header = $('<div class="category_expanded_header"><span class="expanded_header_text">'+header_text+'</span></div>');
$(expanded_header).appendTo(expanded_container);
$(content).clone().attr('data-template','false').prepend(offset_div).appendTo(expanded_container);
$(expanded_container).appendTo(container);
toggleCategoryShroud(true);
$(this).toggleClass('active', true);
});
And here is CSS stylesheet
.vertical_categories{
position:fixed;
top: 0;
left: 0;
padding-left: 10%;
margin-left: -10%;
overflow-y: auto;
box-shadow: 0 0 0.75em rgba(0,0,0,0.2);
z-index: 320;
transition: all 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);
display: grid;
grid-template-rows: 5em auto;
grid-auto-flow: column;
grid-template-areas: "toggle subcategory_container" "category_list subcategory_container";
height: 100%;
}
.category_expanded_container{
grid-area: subcategory_container;
display: grid;
grid-template-areas:
"header"
"list";
grid-template-columns: auto;
grid-template-rows: min-content auto;
overflow-y: auto;
}
.category_list_large{
display: grid;
grid-template-columns: auto min-content;
}
How to create a print stylesheet which can override the dynamic styles created by css modules ?
Using CSS modules, classnames render with unique names like so :
<button class="buttons_style_primary-button__3T" type="submit"> Submit</button>
In my print stylesheet I have the following, which has no effect :
#media print {
button {
display: none;
}
}
I can get it to work by adding !important to the button style, but I will have many print styles and I don't want to do this for each style attribute. Is there an alternative ?
I'm also using React if there happens to be a React specific approach here.
Wound up doing the following :
Use !important for globals that need to override local values:
/* app.css */
#media print {
#page {
margin: 1cm;
}
* {
color: #000 !important;
}
}
Put component specific overrides into a style.css for each component:
/* style.css */
.my-class {
composes: rounded-corners from 'shared/ui.css';
margin: 0 0 60px 0;
background-color: white;
}
#media print {
.my-class {
page-break-inside: avoid;
font-size: 10px;
}
}
/* my-component.jsx */
import style from './style.css';
const MyComponent = () => {
return (
<div className={style.myClass}>
....
</Link>
);
};
There's also a third option which I haven't really tried.
You should be able to apply both the top-level override classname with your local classname using the classNames library:
import app from 'app.css';
import styles from './style.ss'
const MyComponent = () => {
return (
<div className={classNames(style.local, app.global)}>
....
</Link>
);
};
( this third option is just off the top of my head, I don't know if it will work )
Instead of this:
#media print {
.button {
display: none;
}
}
Try this:
.button{
#media print {
display: none;
}
}
how to create a custom combo like above?
here i just did a small hack to the component.by this way you can add any html element to the selection item in combo.
Ext.define('AMShiva.ux.custom.Combo', {
extend: 'Ext.form.field.ComboBox',
alias: 'widget.ux_combo',
colorField: 'color',//to get color value
displayField: 'text',
valueField:'value',
initComponent: function () {
var me = this;
// dropdown item template
me.tpl = Ext.create('Ext.XTemplate',
'<tpl for=".">',
'<div class="x-boundlist-item">',
'<span style="background-color: {' + me.colorField + '};" class="color-box-icon"></span>{' + me.displayField + '}',
'</div>',
'</tpl>'
);
me.callParent(arguments);
// here change the selection item html
me.on('change',
function(element, newValue) {
var inputEl = element.inputCell.child('input');
var data = element.getStore().findRecord(element.valueField, newValue);
if (data) {
inputEl.applyStyles('padding-left:26px');
var parent = inputEl.parent(),
spanDomEle = parent.child('span');
if (!spanDomEle) {
Ext.DomHelper.insertFirst(parent, { tag: 'span', cls: 'color-box-icon' });
var newSpanDomEle = parent.child('span');
newSpanDomEle.applyStyles('background-color: ' + data.get(element.colorField) + ';float: left;position: absolute;margin: 3px 2px 2px 4px;');
} else {
spanDomEle.applyStyles('background-color:' + data.get(element.colorField));
}
}
});
}
});
sample store:
var store = Ext.create('Ext.data.Store', {
fields: ['value', 'text', 'color']
});
css:
.color-box-icon {
width: 16px;
height: 16px;
margin: 0px 4px 0px -3px;
padding: 0px 8px;
}
Is there another way to do this kind of thing?
I wonder if there is a better solution (or if my solution is even right), to create if statement like behavior with variables and guards.
Goal:
If variable is set to true, compile the code (works)
If variable is set to anything else, ignore the code (default, works)
Keep initial code position (dosnt work, is merged wherever .responsive (#responsive); is called)
My Code:
#responsive: true;
.responsive(true){
a {
color: red;
}
}
.responsive(true) {
b {
color: blue;
}
}
.responsive (#responsive);
I am not completely sure I understand what you say doesn't work.
But if I do ... there are two things connected to this that you have to bare in mind in LESS:
scope matters - not order (you can define a variable/mixin after you call it, as long as you deine it in the same scope or a scope that is accessible)
the mixin gets rendered where you call it not where you define it
that said - if you really want to use the same guard in multiple places to do different things, you would need to define multiple mixins (each place would get another mixin), and if you want to render it in the place you define it, you would just need to call it immediately after (or before) you define it. Something like this:
#responsive: true;
test1 {
color:green;
}
.a() when (#responsive){
a {
color: red;
}
}
.a;
test2 {
color:green;
}
.b() when (#responsive) {
b {
color: blue;
}
}
.b;
the output will be:
test1 {
color: green;
}
a {
color: red;
}
test2 {
color: green;
}
b {
color: blue;
}
So the mixins .a() and .b() are returned if #responsive is set to true, if not you get:
test1 {
color: green;
}
test2 {
color: green;
}
I hope this is kinda what you wanted.
I ended up using this:
#responsive: true;
section.content {
.responsive () when (#responsive) {
#media (min-width: 768px) {
float: right;
width: 80%;
}
#media (min-width: 980px) {
width: 60%;
}
}
.responsive;
}
aside.left {
.responsive () when (#responsive) {
#media (min-width: 768px) {
float: left;
width: 20%;
}
}
.responsive;
}
I am using Cytoscape for network visualization.
I have found this example of grouped nodes that you can expand and contract.
My question is, is it possible to highlight nodes and then dynamically add/remove them to a group on an ad-hoc basis?
I am yet to find an examples online of someone actually trying this and all the examples I have found like the aforementioned already have the groups predefined in the initial data load.
You can use the drag and drop extension of cytoscape.
Also, there is the clipboard extension, where you can select multiple elements via ctrl + mousedrag.
var cy = window.cy = cytoscape({
container: document.getElementById('cy'),
style: [{
selector: 'node',
style: {
'label': 'data(id)'
}
},
{
selector: 'node:parent',
style: {
'label': ''
}
},
{
selector: 'edge',
style: {
'curve-style': 'bezier',
'target-arrow-shape': 'triangle'
}
},
{
selector: '.cdnd-grabbed-node',
style: {
'background-color': 'red'
}
},
{
selector: '.cdnd-drop-sibling',
style: {
'background-color': 'red'
}
},
{
selector: '.cdnd-drop-target',
style: {
'border-color': 'red',
'border-style': 'dashed'
}
}
],
elements: {
nodes: [{
data: {
id: 'a'
}
},
{
data: {
id: 'b'
}
},
{
data: {
id: 'c'
}
},
{
data: {
id: 'd',
parent: 'p'
}
},
{
data: {
id: 'p'
}
}
],
edges: [
]
}
});
var cdnd = cy.compoundDragAndDrop();
var removeEmptyParents = false;
var isParentOfOneChild = function(node) {
return node.isParent() && node.children().length === 1;
};
var removeParent = function(parent) {
parent.children().move({
parent: null
});
parent.remove();
};
var removeParentsOfOneChild = function() {
cy.nodes().filter(isParentOfOneChild).forEach(removeParent);
};
// custom handler to remove parents with only 1 child on drop
cy.on('cdndout', function(event, dropTarget) {
if (removeEmptyParents && isParentOfOneChild(dropTarget)) {
removeParent(dropTarget);
}
});
// custom handler to remove parents with only 1 child (on remove of drop target or drop sibling)
cy.on('remove', function(event) {
if (removeEmptyParents) {
removeParentsOfOneChild();
}
});
// toggle check handler
document.getElementById('remove-1ch-parents').addEventListener('click', function() {
removeEmptyParents = !removeEmptyParents;
if (removeEmptyParents) {
removeParentsOfOneChild();
}
});
body {
font-family: helvetica neue, helvetica, liberation sans, arial, sans-serif;
font-size: 14px;
}
#cy {
position: absolute;
left: 0;
top: 0;
bottom: 0;
right: 0;
z-index: 1;
}
h1 {
opacity: 0.5;
font-size: 1em;
font-weight: bold;
}
#options {
z-index: 2;
position: absolute;
right: 0;
top: 0;
margin: 0.5em;
}
<head>
<title>cytoscape-compound-drag-and-drop demo</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-compound-drag-and-drop#1.0.0/cytoscape-compound-drag-and-drop.min.js"></script>
</head>
<body>
<h1>cytoscape-compound-drag-and-drop</h1>
<div id="cy"></div>
<div id="options">
<input id="remove-1ch-parents" type="checkbox" value="false" />
<label for="remove-1ch-parents">Remove parents with only one child</label>
</div>
</body>
The question itself is not that clear requirenment-wise, so if there is still something unclear, please edit it to be more precise (and maybe your code so that we can use that as a base. THX