Merge pull request #614 from LaercioSantana/md-rating-bar

Components > md-rating-bar
This commit is contained in:
Pablo Henrique 2017-05-29 13:26:07 -03:00 committed by GitHub
commit 96142cd0f7
10 changed files with 561 additions and 0 deletions

View file

@ -107,6 +107,10 @@
<router-link exact to="/components/radio">Radio</router-link>
</md-list-item>
<md-list-item class="md-inset">
<router-link exact to="/components/rating-bar">Rating Bar</router-link>
</md-list-item>
<md-list-item class="md-inset">
<router-link exact to="/components/select">Select</router-link>
</md-list-item>

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 B

View file

@ -0,0 +1,304 @@
<template>
<page-content page-title="Components - Rating Bar">
<docs-component>
<div slot="description">
<p>Rating Bar can be used to show a rating to user or capture a rating from user.</p>
<p>The following classes can be applied to change the color palette:</p>
<ul class="md-body-2">
<li><code>md-primary</code></li>
<li><code>md-accent</code></li>
<li><code>md-warn</code></li>
</ul>
</div>
<div slot="api">
<api-table name="md-rating-bar">
<md-table slot="properties">
<md-table-header>
<md-table-row>
<md-table-head>Name</md-table-head>
<md-table-head>Type</md-table-head>
<md-table-head>Description</md-table-head>
</md-table-row>
</md-table-header>
<md-table-body>
<md-table-row>
<md-table-cell>v-model</md-table-cell>
<md-table-cell><code>Number</code></md-table-cell>
<md-table-cell>A required model object to bind the value. The value is limited by range [0, <code>md-max-rating</code>].</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>md-max-rating</md-table-cell>
<md-table-cell><code>Number</code></md-table-cell>
<md-table-cell>Max rating allowed. Default <code>5</code>.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>md-full-icon</md-table-cell>
<md-table-cell><code>String</code></md-table-cell>
<md-table-cell>The icon used to represent full star. Can be a material icon from google font or src of the image file (svg or png). Default <code>star</code>.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>md-empty-icon</md-table-cell>
<md-table-cell><code>String</code></md-table-cell>
<md-table-cell>The icon used to represent empty star. Can be a material icon from google font or src of the image file (svg or png). Default <code>star</code>.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>md-full-iconset</md-table-cell>
<md-table-cell><code>String</code></md-table-cell>
<md-table-cell>The font icon set used on full star. Example: <code>md-iconset="fa fa-heart"</code> for font awesome.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>md-empty-iconset</md-table-cell>
<md-table-cell><code>String</code></md-table-cell>
<md-table-cell>The font icon set used on empty star. Example: <code>md-iconset="fa fa-heart-o"</code> for font awesome.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>md-icon-size</md-table-cell>
<md-table-cell><code>Number</code></md-table-cell>
<md-table-cell>Change the icon size. From 1 to 5, it corresponds the 1x to 5x of the md-size-{type} class in md-icon, where in 1x, the icon has <code>24px</code>. Default <code>1</code>.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>disabled</md-table-cell>
<md-table-cell><code>Boolean</code></md-table-cell>
<md-table-cell>Disable the rating and prevent his actions. Default <code>false</code></md-table-cell>
</md-table-row>
</md-table-body>
</md-table>
<md-table slot="events">
<md-table-header>
<md-table-row>
<md-table-head>Name</md-table-head>
<md-table-head>Value</md-table-head>
<md-table-head>Description</md-table-head>
</md-table-row>
</md-table-header>
<md-table-body>
<md-table-row>
<md-table-cell>change</md-table-cell>
<md-table-cell>Receive the new rating</md-table-cell>
<md-table-cell>Triggered when the rating changes his value by user interaction.</md-table-cell>
</md-table-row>
<md-table-row>
<md-table-cell>hover</md-table-cell>
<md-table-cell>Receive the pointer rating</md-table-cell>
<md-table-cell>Triggered when the user points over a new rating.</md-table-cell>
</md-table-row>
</md-table-body>
</md-table>
</api-table>
</div>
<div slot="example">
<example-box card-title="Default">
<div slot="demo">
<md-rating-bar v-model="rating1" disabled></md-rating-bar>
<md-rating-bar v-model="rating2" :md-max-rating="10" disabled></md-rating-bar>
<md-rating-bar v-model="rating3" :md-max-rating="7" class="md-primary" disabled></md-rating-bar>
<md-rating-bar v-model="rating4" :md-max-rating="7" class="md-accent" disabled></md-rating-bar>
<md-rating-bar v-model="rating5" :md-max-rating="7" class="md-warn" disabled></md-rating-bar>
<md-rating-bar v-model="rating6" :md-max-rating="7" class="md-primary" :md-empty-icon="'star_border'"></md-rating-bar>
<md-rating-bar v-model="rating7" :md-max-rating="5" class="md-warn" :md-empty-icon="'panorama_fish_eye'" :md-full-icon="'lens'"></md-rating-bar>
</div>
<div slot="code">
<code-block lang="xml">
&lt;md-rating-bar v-model="rating1" disabled&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating2" :md-max-rating="10" disabled&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating3" :md-max-rating="7" class="md-primary" disabled&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating4" :md-max-rating="7" class="md-accent" disabled&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating5" :md-max-rating="7" class="md-warn" disabled&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating6" :md-max-rating="7" class="md-primary" :md-empty-icon="'star_border'"&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating7" :md-max-rating="5" class="md-warn" :md-empty-icon="'panorama_fish_eye'" :md-full-icon="'lens'"&gt;&lt;/md-rating-bar&gt;
</code-block>
</div>
</example-box>
<example-box card-title="Themes">
<div slot="demo">
<md-rating-bar v-model="rating8" class="md-primary" md-theme="orange" disabled></md-rating-bar>
<md-rating-bar v-model="rating9" class="md-primary" md-theme="brown" disabled></md-rating-bar>
<md-rating-bar v-model="rating10" class="md-primary" md-theme="light-blue"></md-rating-bar>
<md-rating-bar v-model="rating11" class="md-primary" md-theme="teal" :md-empty-icon="'star_border'"></md-rating-bar>
</div>
<div slot="code">
<code-block lang="xml">
&lt;md-rating-bar v-model="rating8" class="md-primary" md-theme="orange" disabled&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating9" class="md-primary" md-theme="brown" disabled&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating10" class="md-primary" md-theme="light-blue"&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating11" class="md-primary" md-theme="teal" :md-empty-icon="'star_border'"&gt;&lt;/md-rating-bar&gt;
</code-block>
</div>
</example-box>
<example-box card-title="Sizes">
<div slot="demo">
<md-rating-bar v-model="rating12" ></md-rating-bar>
<md-rating-bar v-model="rating12" :md-icon-size="2" ></md-rating-bar>
<md-rating-bar v-model="rating12" :md-icon-size="3" ></md-rating-bar>
</div>
<div slot="code">
<code-block lang="xml">
&lt;md-rating-bar v-model="rating12" &gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating12" :md-icon-size="2" &gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating12" :md-icon-size="3" &gt;&lt;/md-rating-bar&gt;
</code-block>
</div>
</example-box>
<example-box card-title="Images">
<div slot="demo">
<md-layout :md-gutter="true">
<md-layout>
<strong class="md-body-2">SVG:</strong>
<md-rating-bar v-model="rating13" class="md-primary" :md-empty-icon="'assets/icon-home.svg'" :md-full-icon="'assets/icon-home.svg'"></md-rating-bar>
<md-rating-bar v-model="rating13" class="md-primary" :md-empty-icon="'assets/icon-home.svg'" :md-full-icon="'assets/icon-home.svg'" :md-icon-size="2"></md-rating-bar>
</md-layout>
<md-layout>
<strong class="md-body-2">PNG:</strong>
<md-rating-bar v-model="rating13" :md-empty-icon="'assets/icon-home-back.png'" :md-full-icon="'assets/icon-home-front.png'"></md-rating-bar>
<md-rating-bar v-model="rating13" :md-empty-icon="'assets/icon-home-back.png'" :md-full-icon="'assets/icon-home-front.png'" :md-icon-size="2"></md-rating-bar>
</md-layout>
</md-layout>
</div>
<div slot="code">
<code-block lang="xml">
&lt;md-layout :md-gutter="true"&gt;<br />
&lt;md-layout&gt;<br />
&lt;strong class="md-body-2"&gt;SVG:&lt;/strong&gt;<br />
&lt;md-rating-bar v-model="rating13" class="md-primary" :md-empty-icon="'assets/icon-home.svg'" :md-full-icon="'assets/icon-home.svg'"&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating13" class="md-primary" :md-empty-icon="'assets/icon-home.svg'" :md-full-icon="'assets/icon-home.svg'" :md-icon-size="2"&gt;&lt;/md-rating-bar&gt;<br />
&lt;/md-layout&gt;<br />
<br />
&lt;md-layout&gt;<br />
&lt;strong class="md-body-2"&gt;PNG:&lt;/strong&gt;<br />
&lt;md-rating-bar v-model="rating13" :md-empty-icon="'assets/icon-home-back.png'" :md-full-icon="'assets/icon-home-front.png'"&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating13" :md-empty-icon="'assets/icon-home-back.png'" :md-full-icon="'assets/icon-home-front.png'" :md-icon-size="2"&gt;&lt;/md-rating-bar&gt;<br />
&lt;/md-layout&gt;<br />
&lt;/md-layout&gt;
</code-block>
</div>
</example-box>
<example-box card-title="Font Icons">
<!-- had a few trouble on making webpack accept font awesome and others,
therefore i'm using those cdn's' for the sake of a good example -->
<div slot="demo">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/>
<div>This first example uses <a href="http://fontawesome.io/icons/" target="fa_icons">Font Awesome Icons</a></div>
<md-rating-bar v-model="rating14" class="md-primary" :md-empty-iconset="'fa fa-bell-o'" :md-full-iconset="'fa fa-bell'"></md-rating-bar>
<md-rating-bar v-model="rating14" class="md-warn" :md-icon-size="2" :md-empty-iconset="'fa fa-heart-o'" :md-full-iconset="'fa fa-heart'"></md-rating-bar>
<hr/>
<link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"/>
<div>This second example uses <a href="http://ionicons.com/" target="ion_icons">Ion Icons</a></div>
<md-rating-bar v-model="rating14" class="md-primary" :md-empty-iconset="'ion-ios-bell-outline'" :md-full-iconset="'ion-ios-bell'"></md-rating-bar>
<md-rating-bar v-model="rating14" class="md-warn" :md-icon-size="2" :md-empty-iconset="'ion-android-favorite-outline'" :md-full-iconset="'ion-android-favorite'"></md-rating-bar>
</div>
<div slot="code">
<code-block lang="xml">
&lt;link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"/&gt;<br />
&lt;div&gt;This first example uses &lt;a href="http://fontawesome.io/icons/" target="fa_icons"&gt;Font Awesome Icons&lt;/a&gt;&lt;/div&gt;<br />
&lt;md-rating-bar v-model="rating14" class="md-primary" :md-empty-iconset="'fa fa-bell-o'" :md-full-iconset="'fa fa-bell'"&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating14" class="md-warn" :md-icon-size="2" :md-empty-iconset="'fa fa-heart-o'" :md-full-iconset="'fa fa-heart'"&gt;&lt;/md-rating-bar&gt;<br />
&lt;style type="text/css"&gt;&lt;!-- offset fix to awesome icons--&gt;<br />
.fa {<br />
font-size: 19px !important;<br />
line-height: 1.3em !important;<br />
padding-left: 0.1em;<br />
}<br />
.fa.md-size-2x {<br />
font-size: 38px !important;<br />
}<br />
<br />
.fa.md-size-3x {<br />
font-size: 57px !important;<br />
}<br />
<br />
.fa.md-size-4x {<br />
font-size: 76px !important;<br />
}<br />
<br />
.fa.md-size-5x {<br />
font-size: 95px !important;<br />
}<br />
&lt;/style&gt;<br />
&lt;hr/&gt;<br />
&lt;link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"/&gt;<br />
&lt;div&gt;This second example uses &lt;a href="http://ionicons.com/" target="ion_icons"&gt;Ion Icons&lt;/a&gt;&lt;/div&gt;<br />
&lt;md-rating-bar v-model="rating14" class="md-primary" :md-empty-iconset="'ion-ios-bell-outline'" :md-full-iconset="'ion-ios-bell'"&gt;&lt;/md-rating-bar&gt;<br />
&lt;md-rating-bar v-model="rating14" class="md-warn" :md-size="2" :md-empty-iconset="'ion-android-favorite-outline'" :md-full-iconset="'ion-android-favorite'"&gt;&lt;/md-rating-bar&gt;<br />
&lt;style type="text/css"&gt; &lt;!-- offset fix to ion icons--&gt;<br />
i[class*="ion-"]{<br />
padding-left: 0.1em;<br />
}<br />
&lt;/style&gt;
</code-block>
</div>
</example-box>
</div>
</docs-component>
</page-content>
</template>
<script>
export default {
data() {
return {
rating1: 5 * 0.70,
rating2: 10 * 0.6,
rating3: 7 * 0.2,
rating4: 7 * 0.84,
rating5: 7 * 0.7,
rating6: 7 * 0.5,
rating7: 5 * 0.90,
rating8: 5 * 0.9,
rating9: 5 * 0.18,
rating10: 5 * 0.45,
rating11: 5 * 0.82,
rating12: 5 * 0.5,
rating13: 5 * 0.7,
rating14: 5 * 0.4
};
}
};
</script>
<style>
.fa {
font-size: 19px !important;
line-height: 1.3em !important;
padding-left: 0.1em;
}
.fa.md-size-2x {
font-size: 38px !important;
}
.fa.md-size-3x {
font-size: 57px !important;
}
.fa.md-size-4x {
font-size: 76px !important;
}
.fa.md-size-5x {
font-size: 95px !important;
}
i[class*="ion-"]{
padding-left: 0.1em;
}
</style>

View file

@ -23,6 +23,7 @@ const List = (r) => require.ensure([], () => r(require('./pages/components/List'
const Menu = (r) => require.ensure([], () => r(require('./pages/components/Menu')), 'menu');
const Progress = (r) => require.ensure([], () => r(require('./pages/components/Progress')), 'progress');
const Radio = (r) => require.ensure([], () => r(require('./pages/components/Radio')), 'radio');
const RatingBar = (r) => require.ensure([], () => r(require('./pages/components/RatingBar')), 'rating-bar');
const Select = (r) => require.ensure([], () => r(require('./pages/components/Select')), 'select');
const Sidenav = (r) => require.ensure([], () => r(require('./pages/components/Sidenav')), 'sidenav');
const Snackbar = (r) => require.ensure([], () => r(require('./pages/components/Snackbar')), 'snackbar');
@ -158,6 +159,11 @@ const components = [
name: 'components:radio',
component: Radio
},
{
path: '/components/rating-bar',
name: 'components:rating-bar',
component: RatingBar
},
{
path: '/components/select',
name: 'components:select',

View file

@ -0,0 +1,8 @@
import mdRatingBar from './mdRatingBar.vue';
import mdRatingBarTheme from './mdRatingBar.theme';
export default function install(Vue) {
Vue.component('md-rating-bar', mdRatingBar);
Vue.material.styles.push(mdRatingBarTheme);
}

View file

@ -0,0 +1,40 @@
@import '../../core/stylesheets/variables.scss';
$button-radius: 2px;
.md-rating-bar {
width: auto;
display: flex;
width: fit-content;
padding: 3px;
border-radius: 2px;
> .md-full-icon {
overflow-x: hidden;
display: inherit;
}
> .md-empty-icon,
> .md-full-icon {
> .md-icon {
margin: 0;
white-space: nowrap;
cursor: pointer;
}
}
&:not([disabled]) {
&:hover{
background-color: rgba(#999, .2);
}
}
&[disabled] {
> .md-empty-icon,
> .md-full-icon {
> .md-icon {
cursor: default;
}
}
}
}

View file

@ -0,0 +1,24 @@
.THEME_NAME {
&.md-rating-bar {
> .md-empty-icon .md-icon {
color: #{'BACKGROUND-CONTRAST-0.26'};
}
> .md-full-icon .md-icon {
color: #{'BACKGROUND-CONTRAST-0.38'};
}
&.md-primary > .md-full-icon .md-icon {
color: #{'PRIMARY-COLOR'};
}
&.md-accent > .md-full-icon .md-icon {
color: #{'ACCENT-COLOR'};
}
&.md-warn > .md-full-icon .md-icon {
color: #{'WARN-COLOR'};
}
}
}

View file

@ -0,0 +1,173 @@
<template>
<div class="md-rating-bar" :class="[themeClass]" :disabled="disabled">
<div class="md-empty-icon" v-if="srcEmptyIcon">
<md-icon v-for="i in mdMaxRating"
@mouseover.native="hoverStars"
@click.native="clickStars"
@mouseout.native="onMouseOut"
:md-src="srcEmptyIcon"
:class="[iconClasses]"
v-if="srcEmptyIcon"></md-icon>
</div>
<div class="md-empty-icon" v-else>
<md-icon v-for="i in mdMaxRating"
:md-iconset="mdEmptyIconset"
@mouseover.native="hoverStars"
@click.native="clickStars"
@mouseout.native="onMouseOut"
:class="[iconClasses]"
v-html="emptyIcon"></md-icon>
</div>
<div class="md-full-icon" :style="fullIconStyle" v-if="srcFullIcon">
<md-icon v-for="i in mdMaxRating"
@mouseover.native="hoverStars"
@click.native="clickStars"
@mouseout.native="onMouseOut"
:md-src="srcFullIcon"
:class="[iconClasses]"
v-if="srcFullIcon"></md-icon>
</div>
<div class="md-full-icon" :style="fullIconStyle" v-else>
<md-icon v-for="i in mdMaxRating"
:md-iconset="mdFullIconset"
@mouseover.native="hoverStars"
@click.native="clickStars"
@mouseout.native="onMouseOut"
:class="[iconClasses]"
v-html="fullIcon"></md-icon>
</div>
</div>
</template>
<style lang="scss" src="./mdRatingBar.scss"></style>
<script>
import theme from '../../core/components/mdTheme/mixin';
let iconSize = 24;//size of each icon from rating bar in pixels
export default {
props: {
mdMaxRating: {
type: Number,
default: 5
},
disabled: Boolean,
value: {
type: Number,
default: 0
},
mdIconSize: {
type: Number,
default: 1
},
mdFullIconset: String,
mdEmptyIconset: String,
mdFullIcon: {
type: String,
default: 'star'
},
mdEmptyIcon: {
type: String,
default: 'star'
}
},
mixins: [theme],
data() {
return {
srcFullIcon: null,
srcEmptyIcon: null,
rating: this.value
};
},
mounted: function() {
this.srcFullIcon = this.checkSrc(this.mdFullIcon);
this.srcEmptyIcon = this.checkSrc(this.mdEmptyIcon);
},
computed: {
emptyIcon() {
if (this.mdEmptyIconset) {
return '';
}
return this.mdEmptyIcon;
},
fullIcon() {
if (this.mdFullIconset) {
return '';
}
return this.mdFullIcon;
},
iconClasses() {
let classes = {};
if (this.mdIconSize) {
classes[`md-size-${this.mdIconSize}x`] = true;
}
return classes;
},
fullIconStyle() {
return {
width: 100 / this.mdMaxRating * this.rating + '%',
'margin-left': -iconSize * this.mdIconSize * this.mdMaxRating + 'px'
};
}
},
watch: {
mdFullIcon() {
this.srcFullIcon = this.checkSrc(this.mdFullIcon);
},
mdEmptyIcon() {
this.srcEmptyIcon = this.checkSrc(this.mdEmptyIcon);
},
value() {
this.rating = this.value;
}
},
methods: {
hoverStars(evt) {
if (!this.disabled) {
this.rating = this.getIconIndex(evt.currentTarget);
this.$emit('hover', this.rating);
}
},
clickStars(evt) {
if (!this.disabled) {
var selected = this.getIconIndex(evt.currentTarget);
this.$emit('input', selected);
this.$emit('change', selected);
}
},
getIconIndex(iconSelected) {//iconSelected is a dom element
let ratingIcons = this.$el.querySelectorAll('.md-empty-icon > .md-icon, .md-full-icon > .md-icon');
let selected = -1;
ratingIcons = Array.prototype.slice.call(ratingIcons);
//find index from iconSelected
ratingIcons.some((icon, i) => {
if (icon === iconSelected) {
selected = (i + 1) % this.mdMaxRating;
selected = !selected ? this.mdMaxRating : selected;
return true;
}
});
return selected;
},
checkSrc(src) {
if (src && (/.+\.(svg|png)/).test(src)) {//check if src is a image source
return src;
}
return null;
},
onMouseOut() {
this.rating = this.value;
}
}
};
</script>

View file

@ -18,6 +18,7 @@ import MdList from './components/mdList';
import MdMenu from './components/mdMenu';
import MdProgress from './components/mdProgress';
import MdRadio from './components/mdRadio';
import MdRatingBar from './components/mdRatingBar';
import MdSelect from './components/mdSelect';
import MdSidenav from './components/mdSidenav';
import MdSnackbar from './components/mdSnackbar';
@ -52,6 +53,7 @@ const options = {
MdMenu,
MdProgress,
MdRadio,
MdRatingBar,
MdSelect,
MdSidenav,
MdSnackbar,