Transform for child element by parent element tailwind - css

I want transform child element rotate if parent element have class open. Example in css
ul li.open > a > .sidebar-collapse-icon {
-webkit-transform: rotate(-180deg);
-ms-transform: rotate(-180deg);
transform: rotate(-180deg);
}
How can I do it in tailwind?

Couldn't find the exact solution on Tailwind documentation. So tried this hack (instead of open, use group class):
<ul>
<li class="group">
<a>
<span class="sidebar-collapse-icon group-only:-rotate-180"></span>
</a>
</li>
</ul>

You should control css through JavaScript. Tailwind CSS is not relevant by question. I work with her and love this lib.
For example if you use:
Vanilla (pure) JavaScript:
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
.container {
height: 200px;
width: 200px;
}
</style>
</head>
<body>
<div class="container"></div>
<script>
const el = document.querySelector('.container')
if (el) {
el.style.backgroundColor = 'red'
}
</script>
</body>
</html>
React (Hooks):
import React, { useState } from 'react'
export default function MyComponent() {
const [isOpen, setIsOpen] = useState(false)
if (!isOpen) {
return null
}
return (<div className="some-tailwind-class"></div>)
}
Vue if-show directive:
<template>
<div if-show="!isOpen" class="some-tailwind-class"></div>
</template>
<script>
export default {
data() {
return {
isOpen: false;
}
}
}
</script>
Vue v-if directive:
<template>
<div if-show="!isOpen" class="some-tailwind-class"></div>
</template>
<script>
export default {
data() {
return {
isOpen: false;
}
}
}
</script>

Related

how to add Vue props value to background-image

I'm new in VueJS and I get confused to change background image from Vue props value.
I've created simple table from 'vue3-easy-data-table'.
BaseTable.vue:
<template>
<EasyDataTable>
...
</EasyDataTable>
</template>
<script setup lang="ts">
changeImg: {
type: String,
}
})
</script>
<style>
.vue3-easy-data-table__message {
background-image: url("`${v-bind("changeImg")}`");
/* background-image: var(--image-url); */
/* background-image: url('#/assets/img/noDataMultiplierOnCity.svg'); */
}
</style>
View.vue:
<template>
<BaseTable
:changeImg= "image"
/>
</template>
<script lang="ts" setup>
const image : string = "'#/assets/img/noDataMultiplierOnCity.svg'"
</script>
I've tried solution from this link https://stackoverflow.com/questions/42872002/in-vue-js-component-how-to-use-props-in-css but no gain.
Already tried as in the comments in the code, in this case I can just style the component in style tag cause the class is from 'vue3-easy-data-table' (maybe have another way to apply style to it?)
I want to make the background image from BaseTable so it can be reused in other file.
I hope I understood you right and this example will help you
template:
<div :style="styleExample" />
script:
let styleExample = { 'width': props.examplePro }
One way to solve this is to use an inline reactive style. For example you could give your script a method that convers the prop into a style, one that holds the image and any other defining features:
<template>
<EasyDataTable :style="backgroundStyles(image)">
...
</EasyDataTable>
</template>
<script setup>
changeImg: {
type: String,
}
})
const backgroundStyles = (img) => {
return {
'background-image': `url(${img})`,
'background-size': 'cover'
}
}
</script>
code:
App.vue
<script setup>
import { ref } from 'vue'
import BaseTable from './BaseTable.vue'
import BaseTable2 from './BaseTable2.vue'
const msg = ref('Hello World!')
const imageUrl = ref("https://cdn.mos.cms.futurecdn.net/SWx64q2g3wax53Xz5H4QjS-970-80.jpg.webp");
</script>
<template>
<h1>{{ msg }}</h1>
<input v-model="msg">
<BaseTable :image="imageUrl"/>
<hr>
<BaseTable2 :image="imageUrl"/>
</template>
BaseTable.vue
<template>
<div class="bkgrnd" :style="backgroundStyles(image)">
<h2>
Base Table
</h2>
<ul v-for="index in 8" :key="index">
<li>Index: {{ index }}</li>
</ul>
</div>
</template>
<script setup>
const props = defineProps(['image'])
const backgroundStyles = (img) => {
return {
'background-image': `url(${img})`,
'background-size': 'cover'
}
}
</script>
<style scoped>
.bkgrnd {
color: white;
font-style: bold;
}
</style>
Solution using the prop in the CSS
Another way to do this can be to avoid inline styles and instead display the background image in the <style> CSS code. To do this, I would use a computed property to create a URL from the prop, something like:
const computedUrl = computed(() => {
return `url(${props.image})`;
});
Code example,
BaseTable2.vue
<template>
<div class="bkgrnd">
<h2>
Base Table 2
</h2>
<ul v-for="index in 8" :key="index">
<li>Index: {{ index }}</li>
</ul>
</div>
</template>
<script setup>
import { computed } from 'vue';
const props = defineProps(['image'])
const computedUrl = computed(() => {
return `url(${props.image})`;
});
</script>
<style scoped>
.bkgrnd {
color: white;
font-style: bold;
background-image: v-bind(computedUrl);
}
</style>
Both examples can be found at the Vue SFC Playground

how to get a slot content in the css content property of a pseudo ;:before element (or :;after) in a web component?

Well, I think that the question is in the title :
in a web component, with shadowRoot, I want to use a slot text-content inside the content property of a pseudo ::before or ::after element.
This could make me gain much lines.
Would you have an idea, a proposal, a solution ?
You can achieve this with the use of CSS custom properties as the source for the content of ::before and ::after and the slotchange event:
<!DOCTYPE html>
<html lang="en">
<head>
<title>WC</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script>
class XTest extends HTMLElement {
constructor() {
super();
// add shadow dom and insert template content
const shadowRoot = this.attachShadow({ mode: "open" });
const template = document.getElementById("x-test-template");
const templateContent = template.content;
shadowRoot.appendChild(templateContent.cloneNode(true));
}
connectedCallback() {
// get all the named slots
const slots = this.shadowRoot.querySelectorAll("slot[name]");
[...slots].forEach(slot => {
// add a listener to run when the slot changes
slot.addEventListener("slotchange", event => {
// get the slot name
const name = event.target.name;
// get the slot content
const text = event.target.assignedNodes()[0].textContent;
// update the custom property
this.style.setProperty(`--content-${name}`, `'${text}'`);
});
});
}
}
customElements.define("x-test", XTest);
</script>
</head>
<body>
<template id="x-test-template">
<style>
:host {
display: inline-block;
position: relative;
font-size: 2rem;
padding: 2rem;
}
:host::before,
:host::after {
content: "";
position: absolute;
top: 0;
font-size: 1rem;
}
:host::before {
/* set the pseudo selector content to the custom property */
content: var(--content-before, "");
left: 0;
}
:host::after {
/* set the pseudo selector content to the custom property */
content: var(--content-after, "");
right: 0;
}
slot[name] {
display: none;
}
</style>
<!-- slot for ::before -->
<slot name="before"></slot>
<!-- default slot -->
<slot></slot>
<!-- slot for ::after -->
<slot name="after"></slot>
</template>
<x-test>
<span slot="before">B</span>
<span>Hello</span>
<span slot="after">A</span>
</x-test>
</body>
</html>
#lamplightdev
Thank you for your answer.
I was looking for something wich doesn't exist yet.
So I have chose a solution with css var and a setter to set it :
class extends HTMLElement {
set content(val) {
this.setAttribute('data-content',val);
}
constructor() {
...
and, of course :
:host::before {
content: attr(data-content);
...
This seems to be the lighter solution I may imagine.
I'd like to suggest to web's standards developpers to create a new css function : slot(name) witch, with attr(...), var(...) and calc(...), could help the use of pseudo elements inside a web component.
Could someone show me the way to present this proposal ???
I do apologize for my poor english language (I'm french, nobdy's perfect).

VUE component ignoring CSS

I have the following VUE component:
<template>
<div>
<div class="bottom-footer">
{{msg}}
</div>
</div>
</template>
<script>
export default {
name: 'LayoutFooter',
data () {
return {
msg: 'my test'
}
},
mounted () {
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
.bottom-footer {
height: 200px;
background-color: #A7BFE8;
}
</scoped>
VUE is completely ignoring my scoped CSS. When page is rendered its simply not applied. There are no console errors. Ive tried removing the scoped attribute and its still ignored. Any ideas why VUE is doing this?
<style scoped>
.bottom-footer {
height: 200px;
background-color: #A7BFE8;
}
</style>
you need to close style

CSS Style Positioning Issue

I have created one AngularJs directive to clear the input field. I want the "close" icon to be placed inside the respective input element. But its going out of input field.
Here is the plnkr -
https://plnkr.co/edit/WHjRviyuYfFVfg2TnVUP?p=preview
Note: Please check the plnkr preview by resizing it.
var app = angular.module("myApp", []);
app.controller("MyController", function($scope) {
$scope.fname = "Hello!!"
$scope.lname = "World";
})
.directive('clearField', function($compile) {
return {
restrict: 'A',
scope: {
model: '=ngModel'
},
link: function(scope, element, attr) {
// Add wrapper to the element
scope.model = (scope.model == undefined) ? "" : scope.model;
element.wrap('<span class="wrapper"></span>')
.addClass('pr14')
.after('<span class="clear">×</span>');
var clearInputElement = angular.element(element.next());
clearInputElement.bind('click', function() {
scope.$apply(scope.model = "");
});
scope.$watch('model', function() {
if (scope.model.length > 0) {
clearInputElement.css("visibility", "visible");
} else {
clearInputElement.css("visibility", "hidden");
}
});
}
}
});
.wrapper {
position: relative;
display: inline-block
}
.pr14 {
padding-right: 17px;
}
.clear {
position: absolute;
right: 7px;
color: grey;
font-size: 17px;
}
.clear:hover {
cursor: pointer;
color: blue;
}
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script data-require="angularjs#1.5.8" data-semver="1.5.8" src="https://opensource.keycdn.com/angularjs/1.5.8/angular.min.js"></script>
<script src="script.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body ng-controller="MyController">
<label>Name: </label>
<input type="text" ng-model="fname" clear-field>
<textarea ng-model="lname" id="" cols="30" rows="10" clear-field></textarea>
</body>
</html>
As input tags are not container tag, you need to wrap input tag and close tag in a div.
var app = angular.module("myApp", []);
app.controller("MyController", function($scope) {
$scope.fname = "Hello!!"
$scope.lname = "World";
})
.directive('clearField', function($compile) {
return {
restrict: 'A',
scope: {
model: '=ngModel'
},
link: function(scope, element, attr) {
// Add wrapper to the element
scope.model = (scope.model == undefined) ? "" : scope.model;
element.wrap('<span class="wrapper"></span>')
.addClass('pr14')
.after('<span class="clear">×</span>');
var clearInputElement = angular.element(element.next());
clearInputElement.bind('click', function() {
scope.$apply(scope.model = "");
});
scope.$watch('model', function() {
if (scope.model.length > 0) {
clearInputElement.css("visibility", "visible");
} else {
clearInputElement.css("visibility", "hidden");
}
});
}
}
});
.wrapper {
position: relative;
}
.pr14 {
padding-right: 17px;
}
.clear {
position: absolute;
right: 7px;
color: grey;
font-size: 17px;
}
.clear:hover {
cursor: pointer;
color: blue;
}
.wrap{position:relative;}
<!DOCTYPE html>
<html lang="en" ng-app="myApp">
<head>
<meta charset="UTF-8" />
<title>Document</title>
<script data-require="angularjs#1.5.8" data-semver="1.5.8" src="https://opensource.keycdn.com/angularjs/1.5.8/angular.min.js"></script>
<script src="script.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body ng-controller="MyController">
<div class="wrap">
<label>Name: </label>
<input type="text" ng-model="fname" clear-field>
</div>
<br>
<div class="wrap">
<textarea ng-model="lname" id="" cols="30" rows="10" clear-field></textarea>
</div>
</body>
</html>
Change your .wrapper class like this:
.wrapper {
position: relative;
display: inline-block;
}

Preventing fancybox returning to top of page

In my website, I am using fancybox 2.1.5. when I open an image and close it I return to the top of the page unintentionally. The problem can be seen in the following minimal example
<!DOCTYPE html>
<head>
<style media="screen" type="text/css">
body {
height: 100%;
}
html {
height: 100%;
}
</style>
<link rel="stylesheet" type="text/css" href="css/jquery.fancybox.css?v=2.1.5" media="screen" />
</head>
<body>
<a href=#>
<img src="http://placehold.it/1000x600">
</a>
<a class="fancybox" href="img/Gallery/500x600.gif">
<img src="http://placehold.it/500x600">
</a>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.fancybox.js?v=2.1.5"></script>
<script>
$(document).ready(function() {
$('.fancybox').fancybox();
});
</script>
</body>
</html>
You will see that if you open and close the second image you will find yourself at the top of the page.
It appears that if I delete the initial style in the head
<style media="screen" type="text/css">
body {
height: 100%;
}
html {
height: 100%;
}
</style>
The problem disappears. if I erase only the body style or the html style the problem also disappears. In order for the problem to appear both body and html heights must be to 100%
Unfortunately I don't understand why this is happening. Can someone please explain?
Note: I have found solutions and hacks to this problem but I would like to understand why this is happening
Update: seems not to work if you trigger the Fancybox while on a URL that points to a tag with an ID (e.g., "https://example.com/#currentsection"). When you exit the Fancybox, it doesn't go to the top of the page, but does scroll to the top of the tag with the ID, even if you've set the autoFocus and placeFocusBack options to false. Strangely, it still works if your URL is pointed at #top.
Original answer
I found that when using Fancybox in Next.js, binding or configuring Fancybox with autoFocus set to false fixed this. It then seems that placeFocusBack property (default: true) will apply. Set it up like so:
npm install --save #fancyapps/ui
components/fancybox-wrapper.js:
// Fancybox UI wrapper for lightbox
// Thanks to https://fancyapps.com/docs/ui/fancybox/react
import React, { useEffect } from "react";
import { Fancybox as NativeFancybox } from "#fancyapps/ui/dist/fancybox.esm.js";
function Fancybox(props) {
const delegate = props.delegate || "[data-fancybox]";
useEffect(() => {
const opts = props.options || {};
NativeFancybox.bind(delegate, opts);
return () => {
NativeFancybox.destroy();
};
}, []);
return <>{props.children}</>;
}
export default Fancybox;
pages/_app.js:
import Fancybox from "../components/fancybox-wrapper";
import "#fancyapps/ui/dist/fancybox.css";
import { SSRProvider } from "#react-aria/ssr";
function MyApp({ Component, pageProps }) {
return (
<SSRProvider>
<Fancybox options={{ infinite: false, autoFocus: false }}>
<Component {...pageProps} />
</Fancybox>
</SSRProvider>
);
}
export default MyApp;
You can use native helper of fancy box to fix returning to top of page problem.
$('.fancybox').fancybox({
padding: 0,
helpers: {
overlay: {
locked: false
}
}
});
reference : http://davekiss.com/prevent-fancybox-from-jumping-to-the-top-of-the-page/

Resources