Skip to content

Commit 96142cd

Browse files
author
Pablo Henrique
authored
Merge pull request vuematerial#614 from LaercioSantana/md-rating-bar
Components > md-rating-bar
2 parents f09b7ea + bbda58b commit 96142cd

File tree

10 files changed

+561
-0
lines changed

10 files changed

+561
-0
lines changed

docs/src/App.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@
107107
<router-link exact to="/components/radio">Radio</router-link>
108108
</md-list-item>
109109

110+
<md-list-item class="md-inset">
111+
<router-link exact to="/components/rating-bar">Rating Bar</router-link>
112+
</md-list-item>
113+
110114
<md-list-item class="md-inset">
111115
<router-link exact to="/components/select">Select</router-link>
112116
</md-list-item>

docs/src/assets/icon-home-back.png

840 Bytes
Loading

docs/src/assets/icon-home-front.png

842 Bytes
Loading

docs/src/pages/components/RatingBar.vue

Lines changed: 304 additions & 0 deletions
Large diffs are not rendered by default.

docs/src/routes.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const List = (r) => require.ensure([], () => r(require('./pages/components/List'
2323
const Menu = (r) => require.ensure([], () => r(require('./pages/components/Menu')), 'menu');
2424
const Progress = (r) => require.ensure([], () => r(require('./pages/components/Progress')), 'progress');
2525
const Radio = (r) => require.ensure([], () => r(require('./pages/components/Radio')), 'radio');
26+
const RatingBar = (r) => require.ensure([], () => r(require('./pages/components/RatingBar')), 'rating-bar');
2627
const Select = (r) => require.ensure([], () => r(require('./pages/components/Select')), 'select');
2728
const Sidenav = (r) => require.ensure([], () => r(require('./pages/components/Sidenav')), 'sidenav');
2829
const Snackbar = (r) => require.ensure([], () => r(require('./pages/components/Snackbar')), 'snackbar');
@@ -158,6 +159,11 @@ const components = [
158159
name: 'components:radio',
159160
component: Radio
160161
},
162+
{
163+
path: '/components/rating-bar',
164+
name: 'components:rating-bar',
165+
component: RatingBar
166+
},
161167
{
162168
path: '/components/select',
163169
name: 'components:select',

src/components/mdRatingBar/index.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import mdRatingBar from './mdRatingBar.vue';
2+
import mdRatingBarTheme from './mdRatingBar.theme';
3+
4+
export default function install(Vue) {
5+
Vue.component('md-rating-bar', mdRatingBar);
6+
7+
Vue.material.styles.push(mdRatingBarTheme);
8+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
@import '../../core/stylesheets/variables.scss';
2+
3+
$button-radius: 2px;
4+
5+
.md-rating-bar {
6+
width: auto;
7+
display: flex;
8+
width: fit-content;
9+
padding: 3px;
10+
border-radius: 2px;
11+
12+
> .md-full-icon {
13+
overflow-x: hidden;
14+
display: inherit;
15+
}
16+
17+
> .md-empty-icon,
18+
> .md-full-icon {
19+
> .md-icon {
20+
margin: 0;
21+
white-space: nowrap;
22+
cursor: pointer;
23+
}
24+
}
25+
26+
&:not([disabled]) {
27+
&:hover{
28+
background-color: rgba(#999, .2);
29+
}
30+
}
31+
32+
&[disabled] {
33+
> .md-empty-icon,
34+
> .md-full-icon {
35+
> .md-icon {
36+
cursor: default;
37+
}
38+
}
39+
}
40+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
.THEME_NAME {
2+
&.md-rating-bar {
3+
> .md-empty-icon .md-icon {
4+
color: #{'BACKGROUND-CONTRAST-0.26'};
5+
}
6+
7+
> .md-full-icon .md-icon {
8+
color: #{'BACKGROUND-CONTRAST-0.38'};
9+
}
10+
11+
&.md-primary > .md-full-icon .md-icon {
12+
color: #{'PRIMARY-COLOR'};
13+
}
14+
15+
&.md-accent > .md-full-icon .md-icon {
16+
color: #{'ACCENT-COLOR'};
17+
18+
}
19+
20+
&.md-warn > .md-full-icon .md-icon {
21+
color: #{'WARN-COLOR'};
22+
}
23+
}
24+
}
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
<template>
2+
<div class="md-rating-bar" :class="[themeClass]" :disabled="disabled">
3+
<div class="md-empty-icon" v-if="srcEmptyIcon">
4+
<md-icon v-for="i in mdMaxRating"
5+
@mouseover.native="hoverStars"
6+
@click.native="clickStars"
7+
@mouseout.native="onMouseOut"
8+
:md-src="srcEmptyIcon"
9+
:class="[iconClasses]"
10+
v-if="srcEmptyIcon"></md-icon>
11+
</div>
12+
<div class="md-empty-icon" v-else>
13+
<md-icon v-for="i in mdMaxRating"
14+
:md-iconset="mdEmptyIconset"
15+
@mouseover.native="hoverStars"
16+
@click.native="clickStars"
17+
@mouseout.native="onMouseOut"
18+
:class="[iconClasses]"
19+
v-html="emptyIcon"></md-icon>
20+
</div>
21+
22+
<div class="md-full-icon" :style="fullIconStyle" v-if="srcFullIcon">
23+
<md-icon v-for="i in mdMaxRating"
24+
@mouseover.native="hoverStars"
25+
@click.native="clickStars"
26+
@mouseout.native="onMouseOut"
27+
:md-src="srcFullIcon"
28+
:class="[iconClasses]"
29+
v-if="srcFullIcon"></md-icon>
30+
</div>
31+
<div class="md-full-icon" :style="fullIconStyle" v-else>
32+
<md-icon v-for="i in mdMaxRating"
33+
:md-iconset="mdFullIconset"
34+
@mouseover.native="hoverStars"
35+
@click.native="clickStars"
36+
@mouseout.native="onMouseOut"
37+
:class="[iconClasses]"
38+
v-html="fullIcon"></md-icon>
39+
</div>
40+
</div>
41+
</template>
42+
43+
<style lang="scss" src="./mdRatingBar.scss"></style>
44+
45+
<script>
46+
import theme from '../../core/components/mdTheme/mixin';
47+
48+
let iconSize = 24;//size of each icon from rating bar in pixels
49+
50+
export default {
51+
props: {
52+
mdMaxRating: {
53+
type: Number,
54+
default: 5
55+
},
56+
disabled: Boolean,
57+
value: {
58+
type: Number,
59+
default: 0
60+
},
61+
mdIconSize: {
62+
type: Number,
63+
default: 1
64+
},
65+
mdFullIconset: String,
66+
mdEmptyIconset: String,
67+
mdFullIcon: {
68+
type: String,
69+
default: 'star'
70+
},
71+
mdEmptyIcon: {
72+
type: String,
73+
default: 'star'
74+
}
75+
},
76+
mixins: [theme],
77+
data() {
78+
return {
79+
srcFullIcon: null,
80+
srcEmptyIcon: null,
81+
rating: this.value
82+
};
83+
},
84+
mounted: function() {
85+
this.srcFullIcon = this.checkSrc(this.mdFullIcon);
86+
this.srcEmptyIcon = this.checkSrc(this.mdEmptyIcon);
87+
},
88+
computed: {
89+
emptyIcon() {
90+
if (this.mdEmptyIconset) {
91+
return '';
92+
}
93+
94+
return this.mdEmptyIcon;
95+
},
96+
fullIcon() {
97+
if (this.mdFullIconset) {
98+
return '';
99+
}
100+
101+
return this.mdFullIcon;
102+
},
103+
iconClasses() {
104+
let classes = {};
105+
106+
if (this.mdIconSize) {
107+
classes[`md-size-${this.mdIconSize}x`] = true;
108+
}
109+
110+
return classes;
111+
},
112+
fullIconStyle() {
113+
return {
114+
width: 100 / this.mdMaxRating * this.rating + '%',
115+
'margin-left': -iconSize * this.mdIconSize * this.mdMaxRating + 'px'
116+
};
117+
}
118+
},
119+
watch: {
120+
mdFullIcon() {
121+
this.srcFullIcon = this.checkSrc(this.mdFullIcon);
122+
},
123+
mdEmptyIcon() {
124+
this.srcEmptyIcon = this.checkSrc(this.mdEmptyIcon);
125+
},
126+
value() {
127+
this.rating = this.value;
128+
}
129+
},
130+
methods: {
131+
hoverStars(evt) {
132+
if (!this.disabled) {
133+
this.rating = this.getIconIndex(evt.currentTarget);
134+
this.$emit('hover', this.rating);
135+
}
136+
},
137+
clickStars(evt) {
138+
if (!this.disabled) {
139+
var selected = this.getIconIndex(evt.currentTarget);
140+
141+
this.$emit('input', selected);
142+
this.$emit('change', selected);
143+
}
144+
},
145+
getIconIndex(iconSelected) {//iconSelected is a dom element
146+
let ratingIcons = this.$el.querySelectorAll('.md-empty-icon > .md-icon, .md-full-icon > .md-icon');
147+
let selected = -1;
148+
149+
ratingIcons = Array.prototype.slice.call(ratingIcons);
150+
//find index from iconSelected
151+
ratingIcons.some((icon, i) => {
152+
if (icon === iconSelected) {
153+
selected = (i + 1) % this.mdMaxRating;
154+
selected = !selected ? this.mdMaxRating : selected;
155+
return true;
156+
}
157+
});
158+
159+
return selected;
160+
},
161+
checkSrc(src) {
162+
if (src && (/.+\.(svg|png)/).test(src)) {//check if src is a image source
163+
return src;
164+
}
165+
166+
return null;
167+
},
168+
onMouseOut() {
169+
this.rating = this.value;
170+
}
171+
}
172+
};
173+
</script>

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import MdList from './components/mdList';
1818
import MdMenu from './components/mdMenu';
1919
import MdProgress from './components/mdProgress';
2020
import MdRadio from './components/mdRadio';
21+
import MdRatingBar from './components/mdRatingBar';
2122
import MdSelect from './components/mdSelect';
2223
import MdSidenav from './components/mdSidenav';
2324
import MdSnackbar from './components/mdSnackbar';
@@ -52,6 +53,7 @@ const options = {
5253
MdMenu,
5354
MdProgress,
5455
MdRadio,
56+
MdRatingBar,
5557
MdSelect,
5658
MdSidenav,
5759
MdSnackbar,

0 commit comments

Comments
 (0)