"""Simple card with title, subtitle and image."""
# Author(s): Davide.De-Marchi@ec.europa.eu
# Copyright © European Union 2022-2023
#
# Licensed under the EUPL, Version 1.2 or as soon they will be approved by
# the European Commission subsequent versions of the EUPL (the "Licence");
#
# You may not use this work except in compliance with the Licence.
#
# You may obtain a copy of the Licence at:
# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
# Unless required by applicable law or agreed to in writing, software
# distributed under the Licence is distributed on an "AS IS"
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
# express or implied.
#
# See the Licence for the specific language governing permissions and
# limitations under the Licence.
import ipyvuetify as v
import traitlets
[docs]class card(v.VuetifyTemplate):
"""
Simple card displaying title, subtitle and an image.
Parameters
----------
width : str, optional
Width of the card (default is '400px')
color : str, optional
Background color of the card (default is 'white')
dark : bool, optional
If True the title and subtitle texts are displayed in white color, if False they are displayed in black (default is False)
ripple : bool, optional
If True the click on the card is highlighted (default is False)
elevation : int, optional
Elevation of the card over the background of the page (default is 3)
title : str, optional
Title of the card (default is 'Title')
subtitle : str, optional
Subtitle of the card (default is 'Subtitle')
icon : str, optional
URL of the image to display as an icon before the card title (default is '')
iconsize : str, optional
Size of the area where the icon is displayed (default is '32px')
image : str, optional
URL of the image to display in the right side of the card (default is '')
imagesize : str, optional
Size of the area where the image is displayed (default is '190px')
on_click : function, optional
Python function to call when the user clicks on the card. The function will receive no parameters. (default is None)
argument : any, optional
Argument to pass to the on_click python function (default is None)
responsive : bool, optional
If True, the font size is automatically changed according to the page size (default is False)
fontsizemultiplier : float, optional
Multiply factor for changing the standard size of the font used for title and subtitle (default is 1.0)
backgroundimageurl : str, optional
URL of the optional image to display as background of the card (default is '')
tooltip : str, optional
Text to display as tooltip of the whole card (default is '')
titletooltip : str, optional
Text to display as tooltip of the card title (default is '')
focusedopacity : float, optional
Opacity of the card background when the card is clicked (has focus). Default is 0.1
textcolor : str, optional
Color of the text (default is 'black')
titleweight : int, optional
Font weight for the title (default is 700)
subtitleweight : int, optional
Font weight for the subtitle (default is 400)
Example
-------
Creation of a card to display text and an image::
from vois.vuetify import card
from ipywidgets import widgets
from IPython.display import display
output = widgets.Output()
def on_click():
with output:
print('clicked!')
subtitle = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi...'
width = 600
c = card.card(elevation=5, width='600px', title='Sample dataset', subtitle=subtitle,
image='https://cdn.vuetifyjs.com/images/cards/halcyon.png', on_click=on_click)
display(c)
display(output)
.. figure:: figures/card.png
:scale: 100 %
:alt: card widget
Example of a card with text and an image
"""
width = traitlets.Unicode('400px').tag(sync=True)
height = traitlets.Unicode('').tag(sync=True)
color = traitlets.Unicode('white').tag(sync=True)
dark = traitlets.Bool(False).tag(sync=True)
ripple = traitlets.Bool(False).tag(sync=True) # Ripple flag (if True the click on the card is highlighted)
disabled = traitlets.Bool(False).tag(sync=True)
elevation = traitlets.Int(5).tag(sync=True)
title = traitlets.Unicode('Title').tag(sync=True)
subtitle = traitlets.Unicode('Subtitle').tag(sync=True)
icon = traitlets.Unicode('').tag(sync=True)
iconsize = traitlets.Unicode('32px').tag(sync=True)
image = traitlets.Unicode('').tag(sync=True)
imagesize = traitlets.Unicode('190px').tag(sync=True)
on_click = traitlets.Any(None).tag(sync=False)
argument = traitlets.Any(None).tag(sync=False)
responsive = traitlets.Bool(False).tag(sync=True)
fontsizemultiplier = traitlets.Float(1.0).tag(sync=True)
backgroundimageurl = traitlets.Unicode('').tag(sync=True)
subtitlemargins = traitlets.Unicode('ma-0 ml-4 mb-4 mt-0 mr-4').tag(sync=True)
focusedopacity = traitlets.Float(0.1).tag(sync=True)
textcolor = traitlets.Unicode('black').tag(sync=True)
titleweight = traitlets.Int(700).tag(sync=True)
subtitleweight = traitlets.Int(400).tag(sync=True)
@traitlets.default('template')
def _template(self):
pre = ''
ttip = ''
post = ''
if len(self.tooltip) > 0:
pre = '<v-hover v-slot="{ hover }">'
ttip = '<v-tooltip attach allow-overflow absolute center bottom z-index=99999 v-model="hover"><span>%s</span></v-tooltip>' % self.tooltip
post = '</v-hover>'
title_pre = ''
title_att = ''
title_post = ''
if len(self.titletooltip) > 0:
title_pre = '<v-tooltip bottom max-width="%s"><template v-slot:activator="{ on, attrs }">' % str(self.width)
title_att = 'v-bind="attrs" v-on="on"'
title_post = '</template><span>%s</span></v-tooltip>' % self.titletooltip
return '''
%s
<v-card
class="pa-1 ma-1"
:width="width"
:height="height"
:color="color"
:dark="dark"
raised
hover
:elevation="elevation"
:ripple="ripple"
:disabled="disabled"
@click="clicked"
style="overflow: hidden;"
:img="backgroundimageurl"
>
<div class="d-flex flex-no-wrap justify-space-between">
%s
<div>
<v-row dense>
<v-avatar class="pa-0 ma-0 ml-3 mt-2 mr-n2" :size="iconsize" tile >
<v-img :src="icon"></v-img>
</v-avatar>
%s
<v-card-title %s class="mt-n2 mb-1" :style="fontSizeTitle" v-text="title"></v-card-title>
%s
</v-row>
<div :class="subtitlemargins" :style="fontSizeSubTitle" v-html="subtitle"/>
</div>
<v-avatar class="ma-n1" :size="imagesize" tile >
<v-img :src="image" contain></v-img>
</v-avatar>
</div>
</v-card>
%s
<script>
export default {
computed: {
fontSizeTitle ()
{
if( this.responsive )
{
switch( this.$vuetify.breakpoint.name )
{
case 'xs': return 'color: %s; font-weight: %d; font-size: ' + (0.75*this.fontsizemultiplier).toFixed(3) + 'em;'
case 'sm': return 'color: %s; font-weight: %d; font-size: ' + (1.00*this.fontsizemultiplier).toFixed(3) + 'em;'
case 'md': return 'color: %s; font-weight: %d; font-size: ' + (1.25*this.fontsizemultiplier).toFixed(3) + 'em;'
case 'lg': return 'color: %s; font-weight: %d; font-size: ' + (1.45*this.fontsizemultiplier).toFixed(3) + 'em;'
case 'xl': return 'color: %s; font-weight: %d; font-size: ' + (1.60*this.fontsizemultiplier).toFixed(3) + 'em;'
}
}
else
{
return 'colors: %s; font-weight: %d; font-size: ' + (1.25*this.fontsizemultiplier).toFixed(3) + 'em;'
}
},
fontSizeSubTitle ()
{
if( this.responsive )
{
switch( this.$vuetify.breakpoint.name )
{
case 'xs': return 'color: %s; font-weight: %d; font-size: ' + (0.8*this.fontsizemultiplier).toFixed(3) + 'em;'
case 'sm': return 'color: %s; font-weight: %d; font-size: ' + (0.9*this.fontsizemultiplier).toFixed(3) + 'em;'
case 'md': return 'color: %s; font-weight: %d; font-size: ' + (1.0*this.fontsizemultiplier).toFixed(3) + 'em;'
case 'lg': return 'color: %s; font-weight: %d; font-size: ' + (1.1*this.fontsizemultiplier).toFixed(3) + 'em;'
case 'xl': return 'color: %s; font-weight: %d; font-size: ' + (1.2*this.fontsizemultiplier).toFixed(3) + 'em;'
}
}
else
{
return 'color: %s; font-weight: %d; font-size: ' + (1.0*this.fontsizemultiplier).toFixed(3) + 'em;'
}
},
},
}
</script>
<style>
.vuetify-styles .v-card--link:focus::before {
opacity: %f;
}
</style>
''' % (pre,ttip, title_pre,title_att,title_post, post,
self.textcolor,self.titleweight, self.textcolor,self.titleweight, self.textcolor,self.titleweight, self.textcolor,self.titleweight, self.textcolor,self.titleweight, self.textcolor,self.titleweight,
self.textcolor,self.subtitleweight, self.textcolor,self.subtitleweight, self.textcolor,self.subtitleweight, self.textcolor,self.subtitleweight, self.textcolor,self.subtitleweight, self.textcolor,self.subtitleweight,
self.focusedopacity)
def __init__(self,
*args,
width='400px',
height='',
color='white',
dark=False,
ripple=False,
disabled=False,
elevation=3,
title='Title',
subtitle='Subtitle',
icon='',
iconsize='32px',
image='',
imagesize='190px',
on_click=None,
argument=None,
responsive=False,
fontsizemultiplier=1.0,
backgroundimageurl='',
tooltip='',
titletooltip='',
focusedopacity=0.1, # Opacity for the background when the card is clicked (has focus)
textcolor='black',
titleweight=700,
subtitleweight=400,
**kwargs):
self.tooltip = tooltip
self.titletooltip = titletooltip
self.focusedopacity = focusedopacity
self.textcolor = textcolor
self.titleweight = titleweight
self.subtitleweight = subtitleweight
self.width = width
self.height = height
self.color = color
self.dark = dark
self.ripple = ripple
self.disabled = disabled
self.elevation = elevation
self.title = title
self.subtitle = subtitle
if len(self.subtitle) == 0:
self.subtitlemargins = 'ma-0 ml-4 mb-n4 mt-0'
self.icon = icon
if len(icon) == 0: self.iconsize = '0px'
else: self.iconsize = iconsize
self.image = image
if len(image) == 0: self.imagesize = '0px'
else: self.imagesize = imagesize
self.on_click = on_click
self.argument = argument
self.responsive = responsive
self.fontsizemultiplier = fontsizemultiplier
self.backgroundimageurl = backgroundimageurl
super().__init__(*args, **kwargs)
# Manage event "click"
def vue_clicked(self, data):
if not self.on_click is None:
if self.argument is None:
self.on_click()
else:
self.on_click(self.argument)