How can I make sematic-ui-react Tab responsive? - semantic-ui

I'm developing a react application and I recently start to use semantic ui react module.
Unfortunately I'm not able to make the Tab object responsive...
A really simple script to show this is:
import React from 'react'
import { withRouter } from 'react-router-dom'
import {Tab} from 'semantic-ui-react';
// import NavSection from './NavSection'
var sections = ["SectionA","SectionB","SectionC","SectionD","SectionE","SectionF"]
const NavigatorHeader = () => (
<div>
<h1>Navigator</h1>
<div>
<Tab menu={{ pointing: true }} panes={getPanes(sections)} />
</div>
</div>
)
export default withRouter(NavigatorHeader)
function getPanes(sections){
return sections.map( function(section){
return {
menuItem: section,
render: () =>
<Tab.Pane attacched="false">
<div>
<p>
Some Text that we can change tab from tab. E.g. with the title: <b>{section}</b>
</p>
</div>
</Tab.Pane>
}
})
}
The tabs look great, inline, but if I reduce the screen they just overflow, while I was expecting they would have moved to a second line.
Look like that this is coming from the Selenium-ui css I'm using (https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.1/semantic.min.css). Current version is 2.3.1 but if I go back to use a version before 2.0.0, it was responsive.. is there a way to obtain the same behavior with the new version?
Thanks,
Michele.
Thanks,
Michele.

Based on the previous answer I found an easier way to achieve this.
I defined a CSS with the values suggested:
.wrapped{
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
and then just passed that additional class to the menu
<Tab menu={{ pointing: true, className: "wrapped" }} panes={getPanes(sections)} />
That solved the problem without any additional javascript.

Here is a solution that I created some time ago in regular Semantic. It behaves like Bootstrap and does not require a second set of menu items. It requires just a tiny bit of JS and CSS.
The JS:
$(function() {
// Set up to handle wrapping of tab menu (tab actuator) items
$(window).resize(function() {
checkIfWrapped();
});
checkIfWrapped(); // Make sure the function is fired upon document ready
});
// Detect whether a Semantic UI tabular menu is wrapped
function checkIfWrapped() {
var pos_top_1st = $('.tabular.menu .item').first().position().top;
$('.tabular.menu .item:not(first-child)').each(function() {
var pos_top = $(this).position().top;
if (pos_top > pos_top_1st) {
$(this).parent().addClass('wrapped');
return;
} else if (pos_top == pos_top_1st) {
$(this).parent().removeClass('wrapped');
}
});
The HTML structure. (Note that placing the .tabular.menu .item-s inside a div within the overall .tabular.menu allows the use of a separate .right.menu within the .tabular.menu if desired) :
<div id="tabs-menu" class="ui top attached tabular menu">
<div id="qj-tabs">
<div class="tab item"></div>
<div class="tab item"></div>
<div class="tab item"></div>
</div>
<div class="right menu">
<a class="tab item"><i class="add icon"></i> Add Job</a>
<a class="tab item"><i class="copy icon"></i> Copy Item</a>
</div>
</div>
<div class="botttom attached tab segment"></div>
<div class="botttom attached tab segment"></div>
</div>
The CSS:
#qj-tabs {
display: flex !important; /* Will not work unless defined as display: flex */
flex-direction: row !important;
flex-wrap: wrap !important;
}
#tabs-menu .wrapped .item {
border-radius: 5px !important;
border: 1px lightgray solid !important; /* Just styling for the default theme here */
margin: 0 2px 2px 0 !important;
}
#tabs-menu .wrapped .active.item {
background-color: lightgray;
}

This is what i did some weeks ago in regular Semanitic-ui.
! function($) {
var WinReszier = (function() {
var registered = [];
var inited = false;
var timer;
var resize = function(ev) {
clearTimeout(timer);
timer = setTimeout(notify, 100);
};
var notify = function() {
for (var i = 0, cnt = registered.length; i < cnt; i++) {
registered[i].apply();
}
};
return {
register: function(fn) {
registered.push(fn);
if (inited === false) {
$(window).bind('resize', resize);
inited = true;
}
},
unregister: function(fn) {
for (var i = 0, cnt = registered.length; i < cnt; i++) {
if (registered[i] == fn) {
delete registered[i];
break;
}
}
}
};
}());
var TabDrop = function(element, options) {
this.element = $(element);
var $this = this;
this.dropdown = $('<div class="ui item right dropdown" data-popup data-content="' + options.text + '" data-position="bottom center">' +
options.icon +
'<div class="menu"></div>' +
'</div>').appendTo($this.element);
this.click = function() {
$this.element.removeClass("pointing");
$this.element.find("a.item").not(this).removeClass("active");
};
this.reverseclick = function(el) {
$this.element.find(".item.right.dropdown .menu a.item").removeClass("active selected");
$this.element.addClass("pointing");
};
WinReszier.register($.proxy(this.layout, this));
this.layout();
$(".ui.dropdown").dropdown();
$("[data-popup]").popup();
};
TabDrop.prototype = {
constructor: TabDrop,
layout: function() {
var $main = this;
var $this = this.element;
var $drpdwn = this.dropdown;
var $fullwidth = $this.width() - 25;
this.element
.append($drpdwn.find('.ui.item.right'))
.find('a.item')
.not('.item.right.dropdown')
.each(function() {
var $blockLenght = parseInt($(this).width());
var $space = $fullwidth - $blockLenght;
if ($space > $blockLenght) {
$(this).click($main.reverseclick)
if ($drpdwn.find('.menu a').length > 0) {
var $reverse = $drpdwn.find('.menu a:first-child');
$reverse.click($main.reverseclick).removeClass("selected")
$reverse.insertBefore($drpdwn);
}
} else {
var $dropItem = $(this)
$dropItem.click($main.click)
$drpdwn.find('.menu').append($dropItem);
}
$fullwidth = $space;
});
}
};
$.fn.tabdrop = function(option) {
return this.each(function() {
var $this = $(this),
data = $this.data('tabdrop'),
options = typeof option === 'object' && option;
if (!data) {
$this.data('tabdrop', (data = new TabDrop(this, $.extend({},
$.fn.tabdrop.defaults, options))));
}
if (typeof option == 'string') {
data[option]();
}
});
};
$.fn.tabdrop.defaults = {
text: 'More',
icon: '<i class="icon align justify m-0"></i>'
};
$.fn.tabdrop.Constructor = TabDrop;
}(window.jQuery);
var Tabs = {
tabDrop: function() {
setTimeout(function() {
$('.tabdrop').tabdrop({
text: 'More Configuration'
});
}, 1000)
}
};
$(document).on("ready", function() {
$('.menu .item').tab();
Tabs.tabDrop();
$(window).resize(function() {
Tabs.tabDrop();
});
});
<link href="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.3/semantic.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.3.3/semantic.min.js"></script>
<div class="ui top attached pointing menu tabdrop">
<a class="item" data-tab="tab1">Tab Item 1</a>
<a class="item" data-tab="tab2">Tab Item 2</a>
<a class="item" data-tab="tab3">Tab Item 3</a>
<a class="item" data-tab="tab4">Tab Item 4</a>
<a class="item" data-tab="tab5">Tab Item (A very long tab title)</a>
</div>

Related

Show a navbar when scroll down Angular

I want to display a div that contains a navbar when I scroll down. Knowing that on the page I have a power bi report embeded
html :
<div class="divNav " (scroll)="onWindowScroll($event)">
...
</div>
<div class="report">
<iframe [src]="this.linkReport" frameborder="0" allowFullScreen="true"></iframe>
</div>
css:
other class ...
.scroll-down
{
visibility: visible;
}
ts:
#HostListener('window:scroll', ['$event'])
onWindowScroll(e) {
let menu = document.querySelector(".divNav");
let scrollDown = "scroll-down";
window.addEventListener("scroll", () => {
const currentScroll = window.pageYOffset;
if (currentScroll > 100) {
menu.classList.add(scrollDown);
return;
}
})
}
I think HostListener is already the event handler.
I thik currently you add an Eventlistener each time a scroll event is fired?
try:
#HostListener('window:scroll', ['$event'])
onWindowScroll($event) {
const currentScroll = window.pageYOffset;
if (currentScroll > 100) {
let menu = document.querySelector(".divNav");
menu.classList.add("scroll-down");
}
})

is it possible to sort div's with css by condition

I'm working on my React with Nodejs Project.
the project is a flights application where user can follow/unfollow the vacation he wants, and when he follows it - it supposed to be shown first (vacations are Card Divs in Bootstrap.)
im in a very advanced stage of the project and i wanted to know if is there any way to sort Div's by css (if input is checked or something) because if not im gonna have to start it all from the beginning.
import React, { Component } from 'react';
import Switch from "react-switch";
import apiUrl from './apiUrl';
class Vacation extends Component {
state = {
checked: false,
vacation: '',
followdvac: [],
drawfirst: [],
drawlast: []
}
handleChange(checked, e) {
debugger;
var VacationID = e.target.parentElement.parentElement.id
this.setState({ checked });
if (checked === true) {
this.Follow(VacationID)
}
else if (checked === false) {
this.NotFollow(VacationID)
}
}
async Follow(VacationID) {
let follow = {
vacid: VacationID
}
let response = await fetch(`${apiUrl}/follow?userid=` + this.props.userid, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(follow)
}); debugger
let jsonData = await response.json();
debugger;
console.log(jsonData)
}
async NotFollow(VacationID) {
let follow = {
vacid: VacationID
}
let response = await fetch(`${apiUrl}/unfollow?userid=` + this.props.userid, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify(follow)
}); debugger
let jsonData = await response.json();
debugger;
console.log(jsonData)
}
render() {
return (
<div class="col-sm-4 mt-4">
<div class="card">
<img class="card-img-top" src="http://www.boostinspiration.com/wp-content/uploads/2011/07/Sun_Photo_01.jpg?__SQUARESPACE_CACHEVERSION=1311474935879" alt="Card image cap" />
<div class="card-body">
<h5 class="card-title">{this.props.data.name}</h5>
<p class="card-text">{this.props.data.description}</p>
</div>
<div class="card-footer">
<h4><b>From: </b>{this.props.data.start} </h4>
<h4><b>To: </b>{this.props.data.end}</h4>
<small class="text-muted"><h3><b>Price: </b>{this.props.data.price}$</h3></small>
<label id={JSON.stringify(this.props.id)} className="Float">
<span ></span>
<b>Follow</b>:<Switch onChange={this.handleChange.bind(this)} checked={this.state.checked} />
</label>
</div>
</div>
<br />
</div>
)
}
async componentDidMount() {
let AllFollowed = []
let AllUnfollow = []
let Response = await fetch(`${apiUrl}/userfollow?id=` + this.props.userid);
let Followed = await Response.json();
// let Response1 = await fetch(`${apiUrl}/byorder?id=` + this.props.userid);
// let Followed1 = await Response.json();
this.setState({ followdvac: Followed });
// console.log(Followed1)
let VACATIONS = this.props.Vacations
let Fol = this.state.followdvac
VACATIONS.map(v => {
let Filter = Fol.FollowArr.filter(f=>f==v.id)
if (Filter.length == 0 ){
AllUnfollow.push(v)
}
else{
AllFollowed.push(v)
}
})
this.setState({drawfirst:AllFollowed, drawlast:AllUnfollow})
this.MarkChecked()
}
MarkChecked() {
var id = this.props.id
debugger;
for (let i = 0; i < this.state.followdvac.FollowArr.length; i++) {
if (this.state.followdvac.FollowArr[i] === id) {
debugger;
this.setState({ checked: true })
}
}
}
}
export default Vacation;
the card is Mapped from a Vacation array...
and i need to sort it by the checked inputs. (even though it is already mapped)
If you use React it is a common pratice to sort an array of elements and then reflect it on render.
If you still want to go with CSS for any reason, checkout this snippet:
ul {
display: flex;
flex-direction: column;
}
ul li:first-child {
order: 5;
}
ul li:nth-child(2) {
order: 4;
}
ul li:nth-child(3) {
order: 3;
}
ul li:nth-child(4) {
order: 2;
}
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
ref: Is it possible to change the order of list items using CSS3?

AngularJs native slide toggle for nested submenues doesn't update height correctly

I'm implementing the a slide toggle for a nested menu in AngularJS. I've been using the code from the following page: https://blog.assaf.co/native-slide-toggle-for-angularjs-1-4-x/
I'm having only one problem with it though. I'm trying to implement this on a sidenav menu with nested submenues, built with <ul> and <li> elements. After having toggled a menu item that has submenu, and I later toggle the submenu of that same menu button, the <ul> element of that menu button doesn't slide in. The height remains the same.
Also, if I keep the submenu closed, and open only the top menu item, the height of the <ul> element remains the same when I toggle the submenu, meaning that the submenu doesn't show until I toggle it open (though remaining invisible), then close the top menu button, then open it again.
Please see it in action here:
https://codepen.io/marcus-edensky/pen/MBoWZJ
Here's my JavaScript code:
app.controller('myCtrl', function($scope, $mdSidenav) {
});
app.animation('.slide-toggle', ['$animateCss', function($animateCss) {
var lastId = 0;
var _cache = {};
function getId(el) {
var id = el[0].getAttribute("data-slide-toggle");
if (!id) {
id = ++lastId;
el[0].setAttribute("data-slide-toggle", id);
}
return id;
}
function getState(id) {
var state = _cache[id];
if (!state) {
state = {};
_cache[id] = state;
}
return state;
}
function generateRunner(closing, state, animator, element, doneFn) {
return function() {
state.animating = true;
state.animator = animator;
state.doneFn = doneFn;
animator.start().finally(function() {
if (closing && state.doneFn === doneFn) {
element[0].style.height = '';
}
state.animating = false;
state.animator = undefined;
state.doneFn();
});
}
}
return {
addClass: function(element, className, doneFn) {
if (className == 'ng-hide') {
var state = getState(getId(element));
var height = (state.animating && state.height) ?
state.height : element[0].offsetHeight;
var animator = $animateCss(element, {
from: {height: height + 'px'},
to: {height: '0px'}
});
if (animator) {
if (state.animating) {
state.doneFn =
generateRunner(true,
state,
animator,
element,
doneFn);
return state.animator.end();
}
else {
state.height = height;
return generateRunner(true,
state,
animator,
element,
doneFn)();
}
}
}
doneFn();
},
removeClass: function(element, className, doneFn) {
if (className == 'ng-hide') {
var state = getState(getId(element));
var height = (state.animating && state.height) ?
state.height : element[0].offsetHeight;
var animator = $animateCss(element, {
from: {height: '0px'},
to: {height: height + 'px'}
});
if (animator) {
if (state.animating) {
state.doneFn = generateRunner(false,
state,
animator,
element,
doneFn);
return state.animator.end();
}
else {
state.height = height;
return generateRunner(false,
state,
animator,
element,
doneFn)();
}
}
}
doneFn();
}
};
}]);
(function() {
var app = angular.module('app', ['ngAnimate']);
app.animation('.slide-toggle', ['$animateCss', function($animateCss) {
return {
addClass: function(element, className, doneFn) {
if (className == 'ng-hide') {
var animator = $animateCss(element, {
to: {height: '0px'}
});
if (animator) {
return animator.start().finally(function() {
element[0].style.height = '';
doneFn();
});
}
}
doneFn();
},
removeClass: function(element, className, doneFn) {
if (className == 'ng-hide') {
var height = element[0].offsetHeight;
var animator = $animateCss(element, {
from: {height: '0px'},
to: {height: height + 'px'}
});
if (animator) {
return animator.start().finally(doneFn);
}
}
doneFn();
}
};
}]);
})();
Here's the HTML - a simple :
<ul class="menu-toggle-list">
<li><a md-ink-ripple ng-init="showMenu2 = true" ng-click="showMenu2 = !showMenu2" class="md-button menuSub">Tours</a>
<ul ng-show="showMenu2" class="slide-toggle">
<li><a md-ink-ripple ng-init="showMenu3 = true" ng-click="showMenu3 = !showMenu3" class="md-button menuSub">Group tours</a>
<ul ng-show="showMenu3" class="slide-toggle">
<li><a md-ink-ripple href="URL/TOURS/GROUP-TOURS/PLANNING/" class="md-button">Planning</a></li>
<li><a md-ink-ripple href="URL/TOURS/GROUP-TOURS/TYPES/" class="md-button">Types</a></li>
</ul>
</li>
</ul>
</li>
<li><a md-ink-ripple ng-init="showMenu6 = true" ng-click="showMenu6 = !showMenu6" class="md-button menuSub">Users</a>
<ul ng-show="showMenu6" class="slide-toggle">
<li><a md-ink-ripple href="URL/TOURS/GROUP-TOURS/" class="md-button">Staff</a></li>
<li><a md-ink-ripple href="URL/TOURS/GROUP-TOURS/" class="md-button">Clients</a></li>
</ul>
</li>
</ul>
Here's the CSS:
.slide-toggle {
overflow: hidden;
transition: all 0.25s;
}
The parent still holds the height after the animation. You have to remove it.
Add element[0].style.height = 'auto' after animation is done.In the generateRunner function at line 36 after the if
function generateRunner(closing, state, animator, element, doneFn) {
return function () {
state.animating = true;
state.animator = animator;
state.doneFn = doneFn;
animator.start().finally(function () {
if (closing && state.doneFn === doneFn) {
element[0].style.height = '';
}
element[0].style.height = 'auto'; // <----- HERE
state.animating = false;
state.animator = undefined;
state.doneFn();
});
}
}
Hope this helps. Good luck!

ionic conditional text color

I want to show different color for the name of a person if he is Present or Absent.
working in ion view
<ion-view view-title="{{employee.firstName }}">
<ion-content has-header="true" padding="true">
<div ng-style="{{employee.tStatus}} === 'Present' ? { color:'green' } : { color:'red'}"> {{employee.name }}</div>
</ion-content>
</ion-view>
And its not working in any way
Any recommendation please
HTML
<ion-view view-title="{{employee.firstName }}">
<ion-content has-header="true" padding="true">
<div ng-class="{'green':employee.tStatus == 'Present','color: red':employee.tStatus == 'Absent'}">{{employee.name }}
</div>
</ion-content>
</ion-view>
SO Demo
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.employee = {
tStatus: 'Present',
name: 'Sameed'
}
});
.green {
color: green;
}
.red {
color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myCtrl">
<div ng-class="{'green':employee.tStatus == 'Present','color: red':employee.tStatus == 'Absent'}">{{employee.name }}
</div>
</div>
You could use a function which gives the right color:
var app = angular.module('app', []);
app.controller('employeeCtrl', function($scope) {
$scope.employee = {
tStatus: 'Absent',
name: 'Foo'
};
$scope.getColorClass = function(employee)
{
switch(employee.tStatus)
{
case 'Present':
return "green";
case 'Absent':
default:
return "red";
}
};
});
it becomes in handy to pass the emploee in to it. if you want to add more classes, you can just modify your function inside your controller.
you can also add multiple classes. separate them with a space while returning.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="app" ng-controller="employeeCtrl">
<div ng-class="getColorClass(employee)">
{{employee.name}}
</div>
</div>
and in your css define the classes
.red {
color: red;
}
.green {
color: green;
}
var app = angular.module('app', []);
app.controller('employeeCtrl', function($scope) {
$scope.employee = {};
$scope.employee.tStatus = 'Absent';
$scope.employee.name = "Foo";
$scope.getColorClass = function(employee) {
switch (employee.tStatus) {
case 'Present':
return "green";
case 'Absent':
default:
return "red";
}
};
});
.red {
color: red;
}
.green {
color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<div ng-app="app" ng-controller="employeeCtrl">
<div ng-class="getColorClass(employee)">
{{employee.name}}
</div>
</div>

Polymer 1.0 styling not working

I want to create category list with sub category. The sub category will open when user clicks on the parent category. This is like a multi level menu tree.
The functionality works fine, but the style for the child nodes is not applying. The reason is that I create the sub menu dynamically and I cannot set the style rules.
Here is my code:
<template>
<div id="cat_menu">
<!--<category-service id="service" categories="{{categories}}"></category-service>-->
<iron-ajax id="ajax"
auto
url="../api/index.php"
method="POST"
last-response="{{categories}}"
params='{"tag":"get_cat_list"}'
handleAs="json">
</iron-ajax>
<template is="dom-repeat" items="{{categories.cat_list}}" filter="getParent" id="t">
<paper-fab mini id="fab_{{item.category_id}}" icon="edit" class="p_fab"></paper-fab>
<paper-menu id="{{item.category_id}}" class="cat_item" on-click="selectAction">
<span >{{item.category_name}}</span>
</paper-menu>
</template>
<div>
</template>
selectAction: function (e, detail) {
var str = '';
if (detail) {
var selectedItem = e.currentTarget;
//Polymer.dom(selectedItem).childNodes[1].innerHTML = '';
for (var i = 0; i < this.categories.cat_list.length; i++) {
//var item = new Object;
var item = this.categories.cat_list[i];
if (selectedItem.id == item.parent_id) {
var container = document.createDocumentFragment();
var paper_submenu = document.createElement('paper-menu');
paper_submenu.id = item.category_id;
paper_submenu.innerText = item.category_name;
paper_submenu.className = 'cat_item';
//paper_submenu.classList.add('cat_item');
paper_submenu.onclick = 'selectAction';
Polymer.dom(selectedItem.childNodes[1]).appendChild(paper_submenu);
Polymer.updateStyles();
}
}
}
}
CSS Style:
.cat_item {
border: 1px solid #acdcd8;
margin: 5px;
background-color: rgb(255, 255, 255);
padding-left: 10px;
}
The element cannot see this class cat-item. Can someone please help me solve this?

Resources