Vuetify RTL style - vue.js

I am new to vuetify. I need rtl v-text-field with top-right caption on it. How is that possible? I could not do that in inspector. This what i have for a now:
Any help would be appreciated

Added features in v1.1.0:
Vuetify supports RTL (right to left) languages through the rtl prop during bootstrap. This value is dynamic and will apply custom styles to change the orientation of your components.
To enable config level RTL support, add the rtl property to the Vuetify instance options:
import Vue from 'vue'
import Vuetify from 'vuetify'
Vue.use(Vuetify, {
rtl: true
})
You can change this value anytime by directly modifying the $vuetify.rtl property from within your application.

If you are using the latest nuxt.js with vuetify you can add this in nuxt.config.js
buildModules: [
['#nuxtjs/vuetify', { rtl: true }],
...
],

For Vue 2.x, the way to set RTL to true is a bit different:
// src/plugins/vuetify.js
import Vue from 'vue'
import Vuetify from 'vuetify/lib'
Vue.use(Vuetify)
export default new Vuetify({
rtl: true,
})
or, as before, you can modify the rtl value on the vuetify object: this.$vuetify.rtl = true

there is no RTL support for vuetify right now.
but you can create your own CSS and change what you need.
first of all:
add dir=rtl to your app
and add this styles:
textarea:focus, input:focus, button:focus { outline: none !important; }
.list__tile__title {
text-align: right;
}
.toolbar__title {
margin-right: 16px;
}
.input-group--text-field label {
position: absolute;
top: 18px;
right: 0;
}
.input-group label {
text-align: right;
-webkit-transform-origin: top right;
transform-origin: top right;
}
.input-group.input-group--selection-controls label{
right: 32px;
left: auto;
}
.input-group.input-group--selection-controls .icon--selection-control {
left: auto;
right: 0;
}
.input-group--selection-controls__ripple {
-webkit-transform: translate3d(12px,-52%,0);
transform: translate3d(12px,-52%,0);
left: auto;
right: 0;
}
it's not complete. but fix some issues

You should use reverse property for input components. Also, don't forget to change the text direction of input. Here is an example:
input{
direction: rtl;
}
.v-list-item__content{
text-align: right
}
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
</head>
<body>
<div id="app">
<v-app>
<v-content>
<v-container>
<v-row>
<v-col cols="4" right order="2">
<v-select
reverse
outlined
:items="drinks"
label="نوشیدنی"
>
</v-select>
</v-col>
<v-col order="1">
<v-text-field
reverse outlined
label="توضیحات"
placeholder="شرایط نوشیدنی مطلوب شما"
>
</v-text-field>
</v-col>
</v-row>
</v-container>
</v-content>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<script>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data: {
drinks: ['چای', 'قهوه']
}
})
</script>
</body>
</html>

Related

Rendering nested components

I am starting to learn VueJS by building a simple website.
Right now I have made three components:
Header
Navigation
Topbar
I want to render navigation and topbar inside header, so I can call the header component inside every page (I haven't found a way to make a "layout" or something, that every page uses).
Header.vue
<template>
<header id="topNav">
<topbar />
<navigation />
</header>
</template>
<script lang="ts">
import Vue from 'vue'
import navigation from '../navigation/navigation.vue'
import Topbar from '../topbar/topbar.vue'
export default Vue.extend({
components: { Topbar, navigation },
})
</script>
<style scoped>
#topNav {
background-color: #fff;
-webkit-box-shadow: 0 0 35px 0 rgb(154 161 171 / 15%);
box-shadow: 0 0 35px 0 rgb(154 161 171 / 15%);
position: fixed;
left: 0;
right: 0;
top: 0;
z-index: 1001;
padding: 0 12px;
}
</style>
Topbar
<template>
<div id="topBar">
<h2>this is the topbar</h2>
</div>
</template>
<script lang="ts">
import Vue from 'vue'
export default Vue.extend({})
</script>
<style scoped>
#topBar {
border-bottom: 1px solid #dee2e6;
height: 70px;
padding: 0 10px;
z-index: 100;
position: fixed;
left: 0;
right: 0;
}
</style>
And when I call it on for example my home page (index.vue) nothing renders.
<template>
<main>
<header />
<div id="page-content">
<h1>Home</h1>
</div>
</main>
</template>
<script lang="ts">
import Vue from 'vue'
import Header from '../components/header/header.vue'
export default Vue.extend({
name: 'Home',
components: { Header },
})
</script>
I've tried reading the documentation and search around, but haven't been able to figure out what I'm doing wrong.
Since the question is tagged with a Nuxt tag, I'll recommend looking into Nuxt layouts: https://nuxtjs.org/docs/concepts/views#layouts
There is a default named default that you could use by creating the file /layouts/default.vue and passing the components inside of it.
You can of course change that with a layout: 'yolo' if you want another 'yolo` layout.
Pro tip: you don't need to import the components yourself in Nuxt.
You have named your component header, which is a standard html element. Therefore the browser will probably just try to render a standard <header> element instead of your component.
Therefore it is advised to always use multi word component names. See docs here. You can use eslint in your code editor to help you spot these mistakes.
PS: if you are learning vue from the start, I would advise you to use the composition api with the script setup approach, as it makes things easier and provide the opportunity to write clearer code as components grow.

The proper way to use hover event handler in Vue.js

I am self-learning Vue.js and need help.
I am practicing event handlers now. I want the red box to become 100px wider when I hover over it. It works fine when I replace hover with click, But does not work with hover.
Appreciate it if you can point out what is wrong whit my code.
<!DOCTYPE HTML>
<html>
<head>
<title>v-on Event Handlers</title>
<meta charset="UTF-8">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.redbox {
width: 100px;
height: 100px;
background: red;
}
.redboxwide {
width: 200px;
height: 100px;
background: red;
}
</style>
</head>
<body>
<div id="app">
<div v-bind:class="{redbox:!redboxhover, redboxwide:redboxhover}" v-on:hover="redbox();">Hover over me</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
redboxhover: false
},
methods: {
redbox: function () {
this.redboxhover = !this.redboxhover;
}
}
});
</script>
</body>
</html>
You need to use v-on:mouseover instead of v-on:hover.
Also you might need v-on:mouseleave for cleanup.
Here you could find more info about existing Events and mouseover
Use #mouseover like this:
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.redbox {
width: 100px;
height: 100px;
background: red;
}
.redboxwide {
width: 200px;
height: 100px;
background: red;
}
</style>
<div id="app">
<div v-bind:class="{redbox:!redboxhover, redboxwide:redboxhover}" #mouseover="redbox();">Hover over me</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
redboxhover: false
},
methods: {
redbox: function() {
this.redboxhover = !this.redboxhover;
}
}
});
</script>
With the help of #tauzN and #Alex Kosh, I changed my code to the following. I added both #mouseover and #mouseleave.
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.redbox {
width: 100px;
height: 100px;
background: red;
}
.redboxwide {
width: 200px;
height: 100px;
background: red;
}
</style>
<div id="app">
<div v-bind:class="{redbox:!redboxhover, redboxwide:redboxhover}" #mouseover="redbox();" #mouseleave="!redbox();">Hover over me</div>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
redboxhover: false
},
methods: {
redbox: function() {
this.redboxhover = !this.redboxhover;
}
}
});
</script>

Trouble with Vue methods

doing some Vue.js challenges for school and having trouble with a function that should trigger on a hover.
I need the div with the class 'redBox' to grow 10 pixels taller each time it is hovered over.
Here's my code:
<html>
<head>
<title>v-on Event Handlers</title>
<meta charset="UTF-8">
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<style>
.box{width:200px; height:200px; background:green; border:2px solid black; text-align:center; line-height:200px; color:white;}
.hidden{display:none;}
.redBox{width: 100px; height: 100px; background-color: red; margin: 2em;}
</style>
</head>
<body>
<div id="app">
<div v-bind:class="{box:true, hidden:boxHidden}">{{message}}</div>
<button v-on:click="showhide();">{{buttonText}}</button>
<div class="redBox" v-on:hover="hoverGrow();"></div>
</div>
<script>
var app = new Vue({
el: '#app',
data:{
boxHeight:200,
boxHidden : false,
message : 'Make me disappear!',
buttonText : "Hide",
hovered: false,
},
methods:{
showhide : function(){
console.log(this.boxHidden);
if(this.boxHidden){
this.boxHidden=false;
this.buttonText="Hide";
}else{
this.boxHidden=true;
this.buttonText="Show";
}
},
hoverBox : function(){
this.boxHeight = boxHeight + 10;
}
}
});
Any tips as to why this doesn't work? Right now nothing happens when I hover over the square.
Try using v-on:mouseover instead of v-on:hover. Also your function appears to be named hoverBox not hoverGrow. So v-on:mouseover="hoverBox();" should work in your redBox div.

Font Awesome not rendering in Vue built Web Component

I have a Vue component that I'm compiling into a web component using the following build command:
npm run build -- --target wc --name projName src\components\server-config.vue
I'm missing something though in my Vue file cause the web component won't render the font awesome icons. Here is what it looks like when I, "npm run serve"
This is what it looks like after I compile it into a web component and open it in demo.html:
I see several issues:
Fonts are different
Missing Eye button for peeking the password
Checkbox box is missing (though if you mouse over it you still get a glow effect)
Eye icon is missing. (Just included as a test outside of Vuetify)
How can I properly include fonts into my component? Here is my current vue file:
<template>
<div style="text-align: center; font-family: sans-serif">
<v-text-field label="Password" class="mx-4" v-model="password" :type="showPass ? 'text' : 'password'" #click:append="showPass = !showPass" :append-icon="showPass ? 'far fa-eye' : 'far fa-eye-slash'"></v-text-field>
<v-checkbox class="mx-4" v-model="useIntegratedAuthentication" label="Use Integrated Authentication" ></v-checkbox>
<div>
<i class="far fa-eye"></i>
<span>My eye here</span>
</div>
</div>
</template>
<style scoped>
#import '../../node_modules/vuetify/dist/vuetify.min.css';
#import 'https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900';
#import 'https://cdn.jsdelivr.net/npm/#mdi/font#latest/css/materialdesignicons.min.css';
</style>
<script src="https://kit.fontawesome.com/XXXXXXXXX.js" crossorigin="anonymous"></script>
<script lang="ts">
import { VTextField, VCheckbox } from 'vuetify/lib';
import vuetify from '#/plugins/vuetify';
import Vue from 'vue';
export default Vue.extend({
vuetify,
components: {
VTextField, VCheckbox
},
data() {
return {
showPass: false,
password: '',
useIntegratedAuthentication: false
};
}
})
</script>
Figured out a workable solution. You need to load the font-faces inside a script tag after the component is mounted:
mounted() {
const css = `
#font-face {
font-family: 'Font Awesome 5 Free';
font-style: normal;
font-weight: 400;
font-display: block;
src: url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-brands-400.eot);
src: url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-brands-400.woff2) format("woff2"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-brands-400.woff) format("woff"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-brands-400.ttf) format("truetype"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-brands-400.svg#fontawesome) format("svg")
}
#font-face {
font-family: 'Font Awesome 5 Free';
font-style: normal;
font-weight: 400;
font-display: block;
src: url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-regular-400.eot);
src: url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-regular-400.woff2) format("woff2"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-regular-400.woff) format("woff"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-regular-400.ttf) format("truetype"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-regular-400.svg#fontawesome) format("svg")
}
#font-face {
font-family: 'Font Awesome 5 Free';
font-style: normal;
font-weight: 900;
font-display: block;
src: url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-solid-900.eot);
src: url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-solid-900.woff2) format("woff2"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-solid-900.woff) format("woff"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-solid-900.ttf) format("truetype"), url(https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.2/webfonts/fa-solid-900.svg#fontawesome) format("svg")
}`;
// if our style is already injected we do not need to inject it a second time
if (!document.getElementById('myCustomInjectedStyle')) {
const head = document.head || document.getElementsByTagName('head')[0];
const style = document.createElement('style');
style.id = 'myCustomInjectedStyle';
style.type = 'text/css';
style.innerText = css;
head.appendChild(style);
}
},
I never got material designs to work for the checkbox so I updated my vuetify.ts file to always use font awesome.
import Vue from 'vue'
import Vuetify from 'vuetify/lib/framework'
Vue.use(Vuetify)
export default new Vuetify({
icons: {
iconfont: 'fa'
}
})
Use font awesome globally
Add in yuor project/public/index.html head tag
<link rel="stylesheet" ref="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP" crossorigin="anonymous">
And use the tags from their site in your component. like <i class="fab fa-adn"></i>

Vue <transition-group> is not triggering when using v-move class?

I've been trying to get <transition-group> to work but I just can't figure it out. Upon clicking the box, the element will change its position - which is suppose to trigger v-move class. This is the specific part of Vue documentation that I'm looking at.
Here is the link to my test app
<style>
.test-group-leave-to{
opacity: 0;
}
.test-group-move{
transition: transform 5s;
}
</style>
<body>
<div id='app'>
<test-comp></test-comp>
</div>
<script>
let arrary = ['1','2','3','4','5','6','7','8','9'];
new Vue({
el: "#app",
components: {
"test-comp":{
template: `
<div style='display:inline-block;'>
<transition-group name='test-group'>
<div
class='box'
v-for='(all,ind) in arr'
:key='all'
#click='del(ind, $event)'>{{ all }}</div>
</transition-group>
</div>
`,
data(){
return {
arr: arrary
}
},
methods: {
del(ind, e){
e.target.style.left = '100px';
this.arr.splice(ind,1);
}
}
}
}
});
</script>
A bit different approach in order to achieve smoother animations:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.19/lodash.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Balsamiq+Sans:wght#400;700&family=Indie+Flower&family=Nunito+Sans:wght#400;600;700;800;900&display=swap" rel="stylesheet">
<style>
body{
position: relative;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
font-family: 'Nunito', sans-serif;
}
.outer-box {
position: relative;
width: 100%;
padding: 5px 10px;
transition: all 1s;
}
.box{
border: 1px solid blue;
text-align: center;
width: 50px;
height: 50px;
user-select: none;
}
.animate_move-enter, .animate_move-leave-to {
opacity: 0;
transform: translateX(100px);
}
.animate_move-leave-active {
position: absolute;
}
</style>
</head>
<body>
<div id='app'>
<test-comp></test-comp>
</div>
<script>
let arrary = ['1','2','3','4','5','6','7','8','9'];
new Vue({
el: "#app",
components: {
"test-comp":{
template: `
<div>
<transition-group name='animate_move'>
<div v-for='(all,ind) in arr' :key='all' class="outer-box">
<div class='box' #click='del(ind, $event)'>{{ all }}</div>
</div>
</transition-group>
</div>
`,
data(){
return {
arr: arrary
}
},
methods: {
del(ind, e){
this.arr.splice(ind,1);
}
}
}
}
});
</script>
</body>
</html>
This way you can avoid jumping blocks after they are removed.
I suggest to use List Entering/Leaving Transitions instead of move transition and you should remove e.target.style.left = '100px'; :
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.19/lodash.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Balsamiq+Sans:wght#400;700&family=Indie+Flower&family=Nunito+Sans:wght#400;600;700;800;900&display=swap" rel="stylesheet">
<style>
body {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
margin: 0;
font-family: 'Nunito', sans-serif;
}
.box {
position: relative;
border: 1px solid blue;
margin: 10px;
text-align: center;
width: 50px;
height: 50px;
user-select: none;
}
.test-group-enter-active,
.test-group-leave-active {
transition: all 1s;
}
.test-group-enter,
.test-group-leave-to {
opacity: 0;
transform: translateX(100px);
}
</style>
</head>
<body>
<div id='app'>
<test-comp></test-comp>
</div>
<script>
let arrary = ['1', '2', '3', '4', '5', '6', '7', '8', '9'];
new Vue({
el: "#app",
components: {
"test-comp": {
template: `
<div style='display:inline-block;'>
<transition-group name='test-group'>
<div
class='box'
v-for='(all,ind) in arr'
:key='all'
#click='del(ind, $event)'>{{ all }}</div>
</transition-group>
</div>
`,
data() {
return {
arr: arrary
}
},
methods: {
del(ind, e) {
//e.target.style.left = '100px';
this.arr.splice(ind, 1);
}
}
}
}
});
</script>
</body>
</html>