How to create a clickable q-card with hover effect? - vue.js

We're using Quasar Framework with Vue.js. Consider the following q-card that is clickable:
<div class="q-pa-md row items-start q-gutter-md cursor-pointer">
<q-card class="my-card" clickable #click="GetSapRoster">
<q-card-section class="bg-primary text-white">
<div class="text-h6">SAP Truck Roster</div>
<div class="text-subtitle2">Get the truck planning</div>
</q-card-section>
</q-card>
</div>
How is it possible to achieve the same effect for a q-card as with a q-btn?
At the moment when using the class cursor-pointer it only fixes the mouse pointer but not the shading effect like a q-btn has.

You can use v-ripple + q-hoverable + q-focus-helper to simulate a button.
For example:
<q-card v-ripple class="my-box cursor-pointer q-hoverable">
<span class="q-focus-helper"></span>
<q-card-section>
...
</q-card-section>
</q-card>

Related

JAMStack: how to impelement E-Mail Services or simple reactive variables?

I'm currently working on a marketing website for a client. Because SSR would be over-engineered and I'm curious about JAMStack, I decided to make a static website using Nuxt, because I'm already familiar with it.
So I managed to implement Tailwind, which works fine, also when the static site is generated and live on Github pages for example. Now I want to add a feature like a send e-mail form or a menu with a toggle icon.
The simplest solution I could think of for the menu would be a reactive variable and conditional rendering using tailwind. This works fine on localhost using npm run dev, but I can't figure out how to implement this on the generated static site.
I couldn't even manage to fire a click event to a defined method in the script tag.
That's how I would do the burger menu with nuxt SRR, how can I implement something like this in static generated nuxt?
<template>
<div>
<nav
class="flex p-5 items-center fixed w-full border-b-4 border-green bg-white z-50 duration-300 transform justify-between">
<div>
<div><img src="logo.png" class="max-h-6 md:max-h-10" /></div>
</div>
<div class="w-10 h-5 flex flex-col relative cursor-pointer" id="nav-menu" #click="menuOpen = !menuOpen">
<div class="w-full h-1 bg-green absolute duration-200 transform "
:class="[menuOpen ? 'rotate-45 translate-y-2' : 'burger-hover1']" id="menu-first"></div>
<div class="w-full h-1 bg-green absolute bottom-0 duration-200 transform "
:class="[menuOpen ? '-rotate-45 -translate-y-2' : 'burger-hover2']" id="menu-second"></div>
</div>
</nav>
<Transition>
<div v-if="menuOpen" class="fixed w-screen h-screen bg-white pt-20 z-30 space-y-10 text-xl text-center">
<div class="mt-20" #click="menuOpen = !menuOpen">
<nuxt-link to="/">Start</nuxt-link>
</div>
<div #click="menuOpen = !menuOpen">
<nuxt-link to="/partner">Partner</nuxt-link>
</div>
<div #click="menuOpen = !menuOpen">
<nuxt-link to="/kontakt">Kontakt</nuxt-link>
</div>
<div #click="menuOpen = !menuOpen">
<nuxt-link to="/impressum">Impressum</nuxt-link>
</div>
</div>
</Transition>
</div>
</template>
<script>
export default {
name: 'Navbar',
data() {
return {
menuOpen: false
}
}
}
</script>
That's how it looks on localhost. When the static site is hosted, it won't toggle the menu.

Vue Sidebar Transition with tailwind leaving not works

I am trying to get it work sidebar related to this link
Entering works but leaving not works on both overlay and slide back.
<div class="fixed inset-0 flex z-40 lg:hidden" role="dialog" aria-modal="true" v-show="mobileMenuOpen">
<transition
enter-class="opacity-0"
enter-active-class="transition-opacity ease-linear duration-300"
enter-to-class="opacity-100"
leave-class="opacity-0"
leave-active-class="transition-opacity ease-linear duration-300"
leave-to-class="opacity-0"
>
<div class="fixed inset-0 bg-black bg-opacity-25" aria-hidden="true" v-show="mobileMenuOpen" #click="closeMobileMenu"></div>
</transition>
<transition
enter-active-class="transition ease-in-out duration-300 transform"
enter-class="-translate-x-full"
enter-to-class="translate-x-0"
leave-class="translate-x-0"
leave-active-class="transition ease-in-out duration-300 transform"
leave-to-class="-translate-x-full"
appear
> sidebar code
Your starting state for leave is opacity-0 try changing it to opacity-100
...
leave-class="opacity-100"
...
v-leave: Starting state for leave. Added immediately when a leaving transition is triggered, removed after one frame.

Vue/Nuxt - Mouseleave triggers from child element

Currently trying to build a portion of my site that when text is hovered over, a modal box appears below it (so people can hover over it). This would keep the modal present until they move their mouse outside of this.
The issue I face is as soon as my mouse moves from the text to the modal, the model dismisses (as it seems the mouseleave event is triggered).
<div class="relative" #mouseover="guestDropdown = true" #mouseout="guestDropdown = false">
<p class="flex items-center justify-between mt-4 text-xs font-medium leading-4 text-gray-600">
<span>Input:</span>
<span class="cursor-pointer text-deepskyblue-500">Hover</span>
</p>
<div class="absolute right-0 z-20 mt-2 -mx-3 bg-white border rounded" v-show="guestDropdown">
<p class="px-3 py-2">Some modal!</p>
</div>
</div>
Thank you.
It's hard to say without more code and reproducible example but mouseover/mouseout trigger on descendants which is probably something you don't want in this case. You can use mouseenter/mouseleave instead - those doesn't trigger on descendants and doesn't bubble...

Vuejs and Slick Carousel - problem with v-for can't add element in carousel

I'm using vue-slick component but I have some problem with the v-for loop.
This is my code:
<slick
ref="slick"
:options="slickOptions"
class="float-left full-width slider-ingredients">
<div
v-for="ingredient in available_prots_source"
:key="ingredient.id"
#click="onSelectIngredient(ingredient.id, 'prots')"
class="slider-ingredient-item">
<div class="float-left ingredient-image">
<div class="content">
<img :src="ingredient.image" width="200" height="200" class="float-left cover-fit">
</div>
</div>
<h4 class="float-left full-width text-center ingredient-name">
{{ingredient.name}}
</h4>
<span class="float-left full-width text-center ingredient-details">
dettagli
</span>
</div>
</slick>
The problem is that my div is added outside the slick container. If I add a <div> just after the <slick> opening tag it render correctly but sees just one element even if my v-for add 4 or 5 elements.
What am I doing wrong?
How can I use slick with v-for loops?
from the official README (see method reInit in the README.md
// Helpful if you have to deal with v-for to update dynamic lists
this.$nextTick(() => {
this.$refs.slick.reSlick();
});

Is it possible to concatenate class properties in vuejs?

General Question: I was wondering if I can concatenate class properties based on condition. See pseudo-code in the v-forline.
My use-case: I want to align all images that have an even index at the right side.
If I use flex flex-row-reverse for the parent section I get the images aligned on the right. But I don't know how to construct the class in such a way that I do not have to repeat the code for the child elements.
<section
v-for="(quote, index) of $frontmatter.quotes :class="lg:flex my-4 mx-12 overflow-auto" + {even: index % 2, odd: !(index % 2)}"
>
<img
class="quote-image right rounded-full h-64 w-64 flex items-center justify-center shadow-md mx-auto lg:ml-16 lg:mr-10 mt-12"
:src="$withBase(quote.image)"
/>
<div class="px-8 pt-6">
<h3 class="text-primary font-bold mb-4">
{{ quote.title }}
</h3>
<p>
{{ quote.text }}
</p>
</div>
</section>
And call the class extension something like:
.even {
flex-row-reverse
}
Currently,I use this structure - however, I am not happy with that, as I have to repeat my code for the child elements...
<section
v-for="(quote, index) of $frontmatter.quotes"
class= "my-16 mx-24 overflow-auto"
>
<div v-if="index % 2"
class="lg:flex flex-row-reverse">
<img
class="quote-image rounded-full h-64 w-64 flex items-center justify-center shadow-md mx-auto lg:ml-16 lg:mr-10 mt-12"
:src="$withBase(quote.image)"
/>
<div class="px-8 pt-6">
<blockquote>
<h2 class="text-primary font-bold mb-4">
{{ quote.title }}
</h2>
</blockquote>
<p class="quote-text">
{{ quote.text }}
</p>
</div>
</div>
<div v-else
class="lg:flex">
<img
class="quote-image rounded-full h-64 w-64 flex items-center justify-center shadow-md mx-auto lg:ml-16 lg:mr-10 mt-12"
:src="$withBase(quote.image)"
/>
<div class="px-8 pt-6">
<blockquote>
<h2 class="text-primary font-bold mb-4">
{{ quote.title }}
</h2>
</blockquote>
<p class="quote-text">
{{ quote.text }}
</p>
</div>
</div>
</section>
It should look something like:
First, just to clarify the question I'm trying to answer. Given the following code:
<div v-if="index % 2" class="lg:flex flex-row-reverse">
... children ...
</div>
<div v-else class="lg:flex">
... identical children ...
</div>
Is there a way to avoid the v-if and conditionally add the flex-row-reverse class instead?
You've got a number of options here. Firstly, the attributes class and style have special behaviour that allows you to specify both a bound and static copy of the same attribute. You can't do that for other attributes. e.g.
<div
class="lg:flex"
:class="{ 'flex-row-reverse': index % 2 }"
>
So the class lg:flex is added as a static class whereas, flex-row-reverse is added conditionally. Vue will combine them as appropriate to create the class attribute of the finished DOM nodes.
There are a number of other ways this could be written. Here are a couple to ponder:
<div :class="{ 'lg:flex': true, 'flex-row-reverse': index % 2 }">
<div :class="['lg:flex', { 'flex-row-reverse': index % 2 }]">
Arrays can be nested arbitrarily deep. Plain strings will be treated as classes to add. Objects will be treated as collections of conditional classes with the class name as the property name and the condition the property value.
All of this is using Vue's support for conditionally adding classes. However, a bound expression is just arbitrary JavaScript so you could apply the conditionality using normal JavaScript syntax instead of having Vue do it for you.
This is generally clunkier. This has to be a single expression so you can't use if/else. However, you can use ?: instead:
<div :class="'lg:flex' + (index % 2 ? ' flex-row-reverse' : '')">
The official documentation for these various ways to build classes is here:
https://v2.vuejs.org/v2/guide/class-and-style.html#Binding-HTML-Classes
Since you are using classes, not <b-img> props, perhaps the class you need is float-right instead of right
<img v-if="index % 2"
class="quote-image float-right rounded-full h-64 w-64 shadow-md mx-auto lg:ml-16 lg:mr-10 mt-12"
:src="$withBase(quote.image)"
/>