Rating stars (#567)

* Add ratings stars control. Add to scene details
* Replace rating with stars on edit panel
* Add changelog entry
This commit is contained in:
WithoutPants
2020-06-12 09:11:39 +10:00
committed by GitHub
parent d8ce137086
commit a77fea5724
9 changed files with 193 additions and 12 deletions

View File

@@ -85,7 +85,6 @@
"string-no-newline": true,
"string-quotes": "double",
"time-min-milliseconds": 100,
"unit-blacklist": ["em"],
"value-list-comma-space-after": "always-single-line",
"value-list-comma-space-before": "never",
"value-no-vendor-prefix": true

View File

@@ -28,6 +28,7 @@
"@apollo/react-hooks": "^3.1.5",
"@formatjs/intl-numberformat": "^4.2.1",
"@fortawesome/fontawesome-svg-core": "^1.2.28",
"@fortawesome/free-regular-svg-icons": "^5.13.0",
"@fortawesome/free-solid-svg-icons": "^5.13.0",
"@fortawesome/react-fontawesome": "^0.1.9",
"apollo-cache": "^1.3.4",

View File

@@ -3,6 +3,7 @@ import ReactMarkdown from "react-markdown";
const markup = `
### 🎨 Improvements
* Show rating as stars in scene page.
* Add reload scrapers button.
`;

View File

@@ -0,0 +1,118 @@
import React, { useState } from "react";
import { Button } from "react-bootstrap";
import { Icon } from "src/components/Shared";
export interface IRatingStarsProps {
value?: number;
onSetRating?: (value?: number) => void;
}
export const RatingStars: React.FC<IRatingStarsProps> = (
props: IRatingStarsProps
) => {
const [hoverRating, setHoverRating] = useState<number | undefined>();
const disabled = !props.onSetRating;
function setRating(rating: number) {
if (!props.onSetRating) {
return;
}
let newRating: number | undefined = rating;
// unset if we're clicking on the current rating
if (props.value === rating) {
newRating = undefined;
}
// set the hover rating to undefined so that it doesn't immediately clear
// the stars
setHoverRating(undefined);
props.onSetRating(newRating);
}
function getIconPrefix(rating: number) {
if (hoverRating && hoverRating >= rating) {
if (hoverRating === props.value) {
return "far";
}
return "fas";
}
if (!hoverRating && props.value && props.value >= rating) {
return "fas";
}
return "far";
}
function onMouseOver(rating: number) {
if (!disabled) {
setHoverRating(rating);
}
}
function onMouseOut(rating: number) {
if (!disabled && hoverRating === rating) {
setHoverRating(undefined);
}
}
function getClassName(rating: number) {
if (hoverRating && hoverRating >= rating) {
if (hoverRating === props.value) {
return "unsetting";
}
return "setting";
}
if (props.value && props.value >= rating) {
return "set";
}
return "unset";
}
function getTooltip(rating: number) {
if (disabled && props.value) {
// always return current rating for disabled control
return props.value.toString();
}
if (!disabled) {
return rating.toString();
}
}
const renderRatingButton = (rating: number) => (
<Button
disabled={disabled}
className="minimal"
onClick={() => setRating(rating)}
variant="secondary"
onMouseOver={() => onMouseOver(rating)}
onMouseOut={() => onMouseOut(rating)}
onFocus={() => onMouseOver(rating)}
onBlur={() => onMouseOut(rating)}
title={getTooltip(rating)}
>
<Icon
icon={[getIconPrefix(rating), "star"]}
className={getClassName(rating)}
/>
</Button>
);
const maxRating = 5;
return (
<div className="rating-stars">
{Array.from(Array(maxRating)).map((value, index) =>
renderRatingButton(index + 1)
)}
</div>
);
};

View File

@@ -4,6 +4,7 @@ import { FormattedDate } from "react-intl";
import * as GQL from "src/core/generated-graphql";
import { TextUtils } from "src/utils";
import { TagLink } from "src/components/Shared";
import { RatingStars } from "./RatingStars";
interface ISceneDetailProps {
scene: GQL.SceneDataFragment;
@@ -44,7 +45,13 @@ export const SceneDetailPanel: React.FC<ISceneDetailProps> = (props) => {
<FormattedDate value={props.scene.date} format="long" />
</h4>
) : undefined}
{props.scene.rating ? <h6>Rating: {props.scene.rating}</h6> : ""}
{props.scene.rating ? (
<h6>
Rating: <RatingStars value={props.scene.rating} />
</h6>
) : (
""
)}
{props.scene.file.height && (
<h6>Resolution: {TextUtils.resolution(props.scene.file.height)}</h6>
)}

View File

@@ -25,6 +25,7 @@ import { useToast } from "src/hooks";
import { ImageUtils, TableUtils } from "src/utils";
import { MovieSelect } from "src/components/Shared/Select";
import { SceneMovieTable, MovieSceneIndexMap } from "./SceneMovieTable";
import { RatingStars } from "./RatingStars";
interface IProps {
scene: GQL.SceneDataFragment;
@@ -441,14 +442,15 @@ export const SceneEditPanel: React.FC<IProps> = (props: IProps) => {
onChange: setDate,
placeholder: "YYYY-MM-DD",
})}
{TableUtils.renderHtmlSelect({
title: "Rating",
value: rating,
isEditing: true,
onChange: (value: string) =>
setRating(Number.parseInt(value, 10)),
selectOptions: ["", 1, 2, 3, 4, 5],
})}
<tr className="rating">
<td>Rating</td>
<td>
<RatingStars
value={rating}
onSetRating={(value) => setRating(value)}
/>
</td>
</tr>
<tr>
<td>Gallery</td>
<td>

View File

@@ -218,3 +218,44 @@
.movie-table td {
vertical-align: middle;
}
.rating-stars {
display: inline-block;
button {
font-size: inherit;
margin-right: 1px;
padding: 0;
&:hover {
background-color: inherit;
}
&:disabled {
background-color: inherit;
opacity: inherit;
}
}
.unsetting {
color: gold;
}
.setting {
color: gold;
}
.set {
color: gold;
}
}
.rating td {
padding-bottom: 0;
padding-top: 0;
}
#scene-edit-details .rating-stars {
font-size: 1.3em;
height: calc(1.5em + 0.75rem + 2px);
}

View File

@@ -1,9 +1,14 @@
import React from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IconName } from "@fortawesome/fontawesome-svg-core";
import { IconProp, library } from "@fortawesome/fontawesome-svg-core";
import { faStar as fasStar } from "@fortawesome/free-solid-svg-icons";
import { faStar as farStar } from "@fortawesome/free-regular-svg-icons";
// need these to use far and fas styles of stars
library.add(fasStar, farStar);
interface IIcon {
icon: IconName;
icon: IconProp;
className?: string;
color?: string;
}

View File

@@ -1761,6 +1761,13 @@
dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.28"
"@fortawesome/free-regular-svg-icons@^5.13.0":
version "5.13.0"
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.13.0.tgz#925a13d8bdda0678f71551828cac80ab47b8150c"
integrity sha512-70FAyiS5j+ANYD4dh9NGowTorNDnyvQHHpCM7FpnF7GxtDjBUCKdrFqCPzesEIpNDFNd+La3vex+jDk4nnUfpA==
dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.28"
"@fortawesome/free-solid-svg-icons@^5.13.0":
version "5.13.0"
resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.13.0.tgz#44d9118668ad96b4fd5c9434a43efc5903525739"