How to do width transition in Tailwind CSS? - vuejs2

When I try to do a transition using the default "w-#" options in Tailwind, my transitions don't apply. When I hard code in my own classes for width, it works fine. Is there something weird with Tailwinds CSS and how it handles width that would cause this?
Here's the HTML text. The main part here is the dynamic class "sidebarWidth" which switches when the button is clicked. The transition-all, slowest and ease are all things I extended in Tailwind.
<nav class="text-white absolute md:relative flex-col min-h-full bg-black mt-24 md:mt-12 transition-all transition-slowest ease" :class="sidebarWidth">
Here's the JS code in the computed properties of the Vue component
sidebarWidth: function() {
if (this.$store.getters.isSidebarCollapsed) {
return "w-14 invisible md:visible";
} else {
return "w-64";
}
}
If I swap out w-14 and w-64 for the following classes, it works great.
<style scoped>
.width1 {
width: 100px;
}
.width2 {
width: 400px;
}
</style>
I basically want my sidebar nav to slide in when I click a button. In mobile, the sidebar nav is hidden and I want it to slide out. In the desktop, it should be a small nav and then slide out to a full screen nav. It works, but the slide transition doesn't work. Also, the margin change between mobile and desktop does animate properly.

You need to perform a few steps to activate the behaviour you are looking for.
The first one is about extending you Tailwind theme via tailwind.config.js. You need to add the transitionProperty for width.
module.exports = {
...
theme: {
...
extend: {
...
transitionProperty: {
'width': 'width'
},
},
},
}
The changes above create the transition-width class. Simply apply this one to your nav tag. In your specific case you can overwrite the transition-all class.
<nav class="text-white absolute md:relative flex-col min-h-full bg-black mt-24 md:mt-12 transition-width transition-slowest ease" :class="sidebarWidth">
The last step is quite easy: ensure that Tailwind is recreating the CSS. Afterwards you should see a smooth width transition in your project.
Background to the Problem
By default, the width and height transitions are not activated in Tailwind CSS. Here is the CSS that will be applied when using transition class.
transition-property: background-color, border-color, color, fill, stroke, opacity, box-shadow, transform;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
Like you can see width and height are missing in transition-property.
You can find more information about it in the Tailwind documentation.

You can make your own transition property like in tailwind.config.js :
Multiple properties :
module.exports = {
theme: {
extend: {
transitionProperty: {
multiple: "width , height , backgroundColor , border-radius"
}
}
}
One property :
module.exports = {
theme: {
extend: {
transitionProperty: {
width: "width"
}
}
}

Related

How to change whole layout page in Vuetify

In my layout project I want to change layout color.
layout/default.vue
<v-app>
....
</v-ap>
I need to change v-app color, but this doesn't work:
<v-app color="secondary">
How can I do it?
note: I just want to use a Vuetify variable, like primary, secondary, accent, etc., and not CSS code.
i found it
in layout page i added this
#app {
background-color: var(--v-background-base) !important;
}
and in the nuxt config , in vuetify config
themes: {
light: {
background :'#eee'
},
dark :{
background :'#fff'
}
}

Vue router in-out page transition: transition in a new route while old route remains visible

To illustrate what I'm trying to achieve but also discuss and learn about each mechanism separately, I split the issue into two independent challenges:
1. Keep previous route visible until new route has transitioned in
Whether the transition is sliding, what I'm trying here, or just fading; mode in-out doesn't work as I would expect it, namely that the existing route stays visible until the next route has finished its transition (e.g. overlaid itself over the previous one), exactly as illustrated here in the last example of this section https://v2.vuejs.org/v2/guide/transitions.html#Transition-Modes, showing two buttons with in-out mode. Instead no transition is happening but it just flips the routes statically at half of the given transition time.
Is there any caveat with routes and an obvious reason why this wouldn't work the same way, e.g. that a single router-view can only hold one at the time and therefore in-out is not possible?
EDIT 1:
I figured out that in-out would actually only work with position:absolute on both elements, otherwise they will not overlay. Any idea how I could elegantly include such a behavior, potentially setting that absolute position during router-transition only?
Current hack that has the visual slide-up modal effect (mode: in-out) I'm looking for: adding style="position:absolute; z-index:2100" to the dialog route. Then I would need to change the underlying transition once it's shown in order to have the reverse hide effect (mode: out-in).
Also see EDIT 2 below.
2. Creating a modal-like page (route) which opens above another existing page when navigated to
I tried to hack that behavior by adding a second router-view in App.vue
<router-view />
<router-view name="dialog" />
The particular component is added to my routes like this
{
path: 'records/new',
components: {
dialog: () => import('layouts/NewRecord.vue')
},
children: [
{
name: 'new-record',
path: '',
component: () =>
import('src/pages/NewRecord.vue')
}
]
}
I'm not sure whether this approach even makes sense but I couldn't make it work properly. The aim would be to just overlay another router-view name="dialog whenever a "dialog"-path is pushed, so while it can be animated (slide-up) the other router-view stays visible below. In the end I guess I'm facing the same issue here: once the route changes, the initial router-view discards its component because the path does not match the current location anymore.
Either way, there are people out there with more experience and expertise so I hope I could illustrate what I'm trying to achieve and I'm just curious and thankful to read your inputs.
EDIT 2
I could make it work the way I wanted with simply one , wrapped in a custom page-transition component. It is quite a hack though AND I needed to add position: absolute to may page-layouts, to all of them actually (both the "leaving" and the "entering" component need position: absolute) when showing the dialog component. I'm sure there's a better way but I haven't found it so far.
Custom page-transition component:
<template>
<transition :name="name" :mode="mode">
<slot/>
</transition>
</template>
<script lang="ts">
import { Component, Watch } from 'vue-property-decorator'
import Vue from 'vue'
import { Route } from 'vue-router'
#Component({
components: {}
})
export default class PageTransition extends Vue {
NAME_FADE = 'fade'
NAME_SLIDE_UP = 'slide-up'
NAME_SLIDE_DOWN = 'slide-down'
MODE_OUT_IN = ''
MODE_IN_OUT = 'in-out'
name = this.NAME_FADE
mode = this.MODE_OUT_IN
#Watch('$route', { immediate: true, deep: true })
onRouteChanged(newVal: Route, oldVal: Route) {
if (newVal.meta.transition === 'dialog') {
this.name = this.NAME_SLIDE_UP
this.mode = this.MODE_IN_OUT
} else if (oldVal && oldVal.meta.transition === 'dialog') {
this.name = this.NAME_SLIDE_DOWN
// shift next page in immediately below dialog
this.mode = this.MODE_IN_OUT
} else {
// default
this.name = this.NAME_FADE
this.mode = this.MODE_OUT_IN
}
}
}
</script>
<style lang="scss" scoped>
.fade-enter, .fade-leave-to {
opacity: 0;
}
.fade-enter-active, .fade-leave-active {
transition: all 0.1s ease;
}
// start of enter element
.slide-up-enter {
transform: translateY(60%);
opacity: 0;
}
.slide-up-enter-active {
transition: all 0.3s ease-out;
z-index: 2100;
}
// start of leave element
.slide-up-leave, .slide-up-leave-active {
opacity: 0;
}
// start of leave element
.slide-down-leave {
z-index: 2100;
}
.slide-down-leave-to {
transform: translateY(60%);
opacity: 0;
z-index: 2100;
}
.slide-down-leave-active {
transition: all 0.3s ease-in;
}
// start of enter element
.slide-down-enter {
opacity: 0;
}
.slide-down-enter-active {
/* show immediately behind existing page (lower z-index) */
transition: all 0s;
}
</style>
I have a similar task. I was able to complete it using fixed containers and z-index shuffle. I met a number of issues related to scroll and vertical alignment, and, in my case, solving it using absolute position during router-transition only was not possible.
Here's the demo: https://kasheftin.github.io/vue-router-in-out-slide-scroll.
Also, I had to use localStorage to keep & restore page scroll position.
In my case page content has to be vertically aligned. That's why I could not use one global scrollable container (e.g. <body>). In-out mode transition works rather simple - it just appends the content, adds some classes and then removes the first child. That means in the middle there're two page containers side by side, and if one of them is tall (and forces the body to have scroll), then the other one appears in the middle of the body and has wrong vertical alignment.
So I just wrapped every page with fixed scrollable container. Assume we have a List and an Item pages, and the last should slide from the right and overlay the list. Then, the right-to-left animation is very simple:
.slide-right-enter-active {
transition: transform 1s ease;
.slide-right-enter {
transform: translateX(100%);
}
Left-to-right animation (overlay disappearing) has the wrong z-index. During the animation we have the following in the DOM:
<transition>
<Item />
<List />
</transition>
By default List will be shown over the Item, but it has to be below. So there're the rules:
.slideable-page {
position: fixed;
overflow: auto;
z-index: 2;
}
.slide-left-enter {
z-index: 1;
}
.slide-left-enter-active {
z-index: 1;
}
.slide-left-leave-active {
transition: transform 1s ease;
z-index: 3;
}
.slide-left-leave-to {
transform: translateX(100%);
}
For question 1: Have you added the CSS with it? The transition by itself only handles timing, you need to add the CSS for the transition to work (example: https://v2.vuejs.org/v2/guide/transitions.html#Transitioning-Single-Elements-Components).
.fade-enter-active, .fade-leave-active {
transition: opacity .5s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
opacity: 0;
}
For question 2:
I don't know if I understood correctly your situation, but if I did, here is what I would do, using nested routes.
layouts/NewRecord.vue
<template>
<router-view name="dialog"></dialog>
</template>
Routes
const routes = {
path: 'records/new',
component: () => import('layouts/NewRecord.vue'),
children: [
{
path: 'dialog',
components: {
dialog: () => import('src/pages/NewRecord.vue'),
},
},
],
}

Can the <transition> element be used to animate individual page elements in a nuxtjs application?

Can someone tell me if the transition element can be used on page elements for animations in nuxt? I have seen the doc regarding page transitions, but I want to animate a number of different page elements. What I have so far does not appear to be working.
In a simple Header component, I have this:
<template>
<transition name="menu-popover">
<ul class="MenuPopover">
<li>Payments</li>
<li>Subscriptions</li>
<li>Connect</li>
</ul>
</transition>
And in the style tag of that component:
<style scoped>
.menu-popover-enter {
opacity: 0;
transform: rotateY(50deg);
}
.menu-popover-enter-to {
opacity: 1;
transform: rotateY(0deg);
}
.menu-popover-enter-active {
transition: opacity, transform 200ms ease-out;
}
Solution 1:
Look into the Nuxt Guide: Page Transition, it introduces how to implement the transition for each page (or specific pages Nuxt API: Page Transition) step by step very well.
Solution 2 (not recommend, but if really prefer to uses <nuxt /> inside one <transition> manually):
Steps:
put <nuxt> inside <transition>, like <transition name="test"><nuxt v-show="pageShow"/></transition>
add css class for transition effects,
css will be like:
.test-enter {
opacity: 0;
transform: rotateY(50deg);
}
.test-leave-to {
opacity: 0;
transform: rotateY(100deg);
}
.test-enter-active,.test-leave-active {
transition: all 2s ease-out;
}
add one handler for router navigator (or like button click event which will trigger route change).
The handler will be like below:
changePage: function (newUrl) {
this.pageShow = false //hide current page to trigger the transtion for `leave` current page
setTimeout(()=> {
this.pageShow = true //show new page, it will trigger the transition for `enter` new page
this.$router.replace(newUrl) //with new url
}, 2000) // delay 2s (after the transition of previous page finishes)
}

MapBox (mapbox-gl-vue) renders the map on only 50% of the width of the container

I am trying MapBox with Vue 2 and I cannot make the map take the full width of the container. It only renders on 50% of the width of the container.
I have included the files in the head of my index.html as follows:
<script src='https://api.mapbox.com/mapbox-gl-js/v0.40.0/mapbox-gl.js'></script>
<link href='https://api.mapbox.com/mapbox-gl-js/v0.40.0/mapbox-gl.css' rel='stylesheet' />
I want the map in a component (Map.vue, I am using vue-router), so here is the code in Map.vue:
Script:
import Mapbox from 'mapbox-gl-vue';
export default {
components: {
'mapbox': Mapbox
}
}
Template:
<mapbox access-token="pk.eyJ1Ijoic3BlZW5pY3Q....."
:map-options="{
style: 'mapbox://styles/mapbox/streets-v9',
center: [-96, 37.8],
zoom: 3
}"
:geolocate-control="{
show: true,
position: 'top-left'
}"
:scale-control="{
show: true,
position: 'top-left'
}"
:fullscreen-control="{
show: true,
position: 'top-left'
}">>
</mapbox>
Style:
#map {
width: 100%;
height: 600px;
position: absolute;
margin:0;
z-index:1;
}
I have tried everything I know in the CSS id but it only renders the map in the right half of the width of the container, in the left one only the logo and the controls are displayed while the rest of the area is empty.
To solve the problem, I just had to delete "text-align: center;" from #app in App.vue.
For more details, check the issue I had opened here:
https://github.com/phegman/vue-mapbox-gl/issues/11
It looks like to me, there is something dynamic with the div or the div is rendered later after the instantiation. I have not used vue, however.
I have had this problem with tabs and div rendered after the page load such as in tabs or triggered by JavaScript.
If you use map.invalidateSize(); where map is the object instantiated. This will redraw the map. Try and put this after the window is loaded to test the code. Then perhaps it can be converted into the correct Vue implementation.
window.addEventListener("load", function(){
map.invalidateSize();
});;

Specify/Set width and height on a react-boostrap modal

How can I apply a dynamic width and height to a react-bootstrap modal window?
I have checked the react-bootstrap docs here but could not figure out how to do that.
Actually the value of width and height props would be dynamic (could be any values) as this will be a reusable component in my app (to be used on many pages) thus can't apply width/height through some CSS class.
'bsSize' property as mentioned in docs also not working, although predefined sizes of xs, md, lg is not what I exactly want, rather I need width and height to be set on modal via props.
Here is my sample JSX code:
var MyWindow = React.createClass({
getInitialState() {
return { show: true };
},
close() {
this.setState({ show: false });
},
open() {
this.setState({ show: true });
},
save() {
},
render: function () {
var Button = ReactBootstrap.Button,
Modal = ReactBootstrap.Modal,
ModalBody = ReactBootstrap.ModalBody,
ModalHeader = ReactBootstrap.ModalHeader,
ModalFooter = ReactBootstrap.ModalFooter,
ModalTitle = ReactBootstrap.ModalTitle;
return (
<Modal show={this.state.show} onHide={this.close}>
<ModalHeader closeButton>
<ModalTitle>My Cool Window</ModalTitle>
</ModalHeader>
<ModalBody>
<h4>Text in a modal</h4>
<p>Duis mollis, est non commodo luctus</p>
</ModalBody>
<ModalFooter>
<Button onClick={this.close}>Cancel</Button>
<Button bsStyle="primary" onClick={this.save}>Save</Button>
</ModalFooter>
</Modal>
);
}
});
React.render(<MyWindow width={700} height={400} />, mountNode);
According to its documentation, you have to customize your own css class to achieve the style you want via modal's prop dialogClassName.
So we might have my.jsx code below:
<Modal dialogClassName="my-modal">
</Modal>
With my.css below:
.my-modal {
width: 90vw /* Occupy the 90% of the screen width */
max-width: 90vw;
}
Then you will have your custmized modal!
.my-modal{
min-width: 50%
}
Works for me!!!
The other mentioned solution only works for setting the width.
For editing the height, you need to add your custom css class to the contentClassName attribute.
For Example:
<Modal contentClassName="modal-height"></Modal>
Css Class:
.modal-height {
height: 70%;
}
For editing the width you need to add your custom css class to the dialogClassName attribute.
For Example:
<Modal dialogClassName="modal-width"></Modal>
Css Class:
.modal-width {
width: 70%;
}
Possible Issues:
Sometimes you will have to use !important to over-ride bootstrap imposed CSS, so experiment with that as well.
Credits: Found the solution here.