From a77fea57240eb5a485c9f8332c98f44c68ef6e58 Mon Sep 17 00:00:00 2001 From: WithoutPants <53250216+WithoutPants@users.noreply.github.com> Date: Fri, 12 Jun 2020 09:11:39 +1000 Subject: [PATCH] Rating stars (#567) * Add ratings stars control. Add to scene details * Replace rating with stars on edit panel * Add changelog entry --- ui/v2.5/.stylelintrc | 1 - ui/v2.5/package.json | 1 + .../components/Changelog/versions/v030.tsx | 1 + .../Scenes/SceneDetails/RatingStars.tsx | 118 ++++++++++++++++++ .../Scenes/SceneDetails/SceneDetailPanel.tsx | 9 +- .../Scenes/SceneDetails/SceneEditPanel.tsx | 18 +-- ui/v2.5/src/components/Scenes/styles.scss | 41 ++++++ ui/v2.5/src/components/Shared/Icon.tsx | 9 +- ui/v2.5/yarn.lock | 7 ++ 9 files changed, 193 insertions(+), 12 deletions(-) create mode 100644 ui/v2.5/src/components/Scenes/SceneDetails/RatingStars.tsx diff --git a/ui/v2.5/.stylelintrc b/ui/v2.5/.stylelintrc index a87318b34..5f5be26f0 100644 --- a/ui/v2.5/.stylelintrc +++ b/ui/v2.5/.stylelintrc @@ -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 diff --git a/ui/v2.5/package.json b/ui/v2.5/package.json index 29f895d36..974c76f65 100644 --- a/ui/v2.5/package.json +++ b/ui/v2.5/package.json @@ -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", diff --git a/ui/v2.5/src/components/Changelog/versions/v030.tsx b/ui/v2.5/src/components/Changelog/versions/v030.tsx index 4ce277bdb..780a84047 100644 --- a/ui/v2.5/src/components/Changelog/versions/v030.tsx +++ b/ui/v2.5/src/components/Changelog/versions/v030.tsx @@ -3,6 +3,7 @@ import ReactMarkdown from "react-markdown"; const markup = ` ### 🎨 Improvements +* Show rating as stars in scene page. * Add reload scrapers button. `; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/RatingStars.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/RatingStars.tsx new file mode 100644 index 000000000..99e5a251d --- /dev/null +++ b/ui/v2.5/src/components/Scenes/SceneDetails/RatingStars.tsx @@ -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 = ( + props: IRatingStarsProps +) => { + const [hoverRating, setHoverRating] = useState(); + 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) => ( + + ); + + const maxRating = 5; + + return ( +
+ {Array.from(Array(maxRating)).map((value, index) => + renderRatingButton(index + 1) + )} +
+ ); +}; diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneDetailPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneDetailPanel.tsx index f64f00a58..7d2556e04 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneDetailPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneDetailPanel.tsx @@ -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 = (props) => { ) : undefined} - {props.scene.rating ?
Rating: {props.scene.rating}
: ""} + {props.scene.rating ? ( +
+ Rating: +
+ ) : ( + "" + )} {props.scene.file.height && (
Resolution: {TextUtils.resolution(props.scene.file.height)}
)} diff --git a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx index 34e6dc804..71ab839a9 100644 --- a/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx +++ b/ui/v2.5/src/components/Scenes/SceneDetails/SceneEditPanel.tsx @@ -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 = (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], - })} + + Rating + + setRating(value)} + /> + + Gallery diff --git a/ui/v2.5/src/components/Scenes/styles.scss b/ui/v2.5/src/components/Scenes/styles.scss index c7af5c17e..a7b32164d 100644 --- a/ui/v2.5/src/components/Scenes/styles.scss +++ b/ui/v2.5/src/components/Scenes/styles.scss @@ -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); +} diff --git a/ui/v2.5/src/components/Shared/Icon.tsx b/ui/v2.5/src/components/Shared/Icon.tsx index 88b912893..ca822d9e0 100644 --- a/ui/v2.5/src/components/Shared/Icon.tsx +++ b/ui/v2.5/src/components/Shared/Icon.tsx @@ -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; } diff --git a/ui/v2.5/yarn.lock b/ui/v2.5/yarn.lock index d68e02a69..45253b544 100644 --- a/ui/v2.5/yarn.lock +++ b/ui/v2.5/yarn.lock @@ -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"