Skip to content

Commit 19c1219

Browse files
committed
feat: rating/CustomIcon, fix: Star, Heart, Thumbup
1 parent 59c5ef3 commit 19c1219

File tree

11 files changed

+117
-65
lines changed

11 files changed

+117
-65
lines changed

src/lib/rating/CustomIcon.svelte

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<script lang="ts">
2+
import { type RatingIconProps as Props } from ".";
3+
4+
let {
5+
fillPercent = 100,
6+
fillColor = "#00ff00",
7+
strokeColor = "#00ff00",
8+
size = 24,
9+
ariaLabel = "custom icon",
10+
starIndex = 0,
11+
groupId = "custom",
12+
role = "img",
13+
svgClass,
14+
pathd = "M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z",
15+
...restProps
16+
}: Props = $props();
17+
18+
const uniqueId = `custom-icon-${Math.random().toString(36).slice(2)}`;
19+
20+
</script>
21+
22+
<svg
23+
width={size}
24+
height={size}
25+
class={svgClass}
26+
{...restProps}
27+
aria-label={ariaLabel}
28+
viewBox="0 0 24 24"
29+
{role}
30+
stroke-width="1.5"
31+
>
32+
<defs>
33+
<linearGradient id={uniqueId} x1="0%" y1="0%" x2="100%" y2="0%">
34+
{#if fillPercent !== 100}
35+
<stop offset="0%" stop-color={fillColor} />
36+
<stop offset="{fillPercent}%" stop-color={fillColor} />
37+
<stop offset="{fillPercent}%" stop-color="transparent" />
38+
<stop offset="100%" stop-color="transparent" />
39+
{:else}
40+
<stop offset="0%" stop-color={fillColor} />
41+
<stop offset="100%" stop-color={fillColor} />
42+
{/if}
43+
</linearGradient>
44+
</defs>
45+
46+
<path
47+
d={pathd}
48+
fill="url(#{uniqueId})"
49+
stroke={strokeColor}
50+
stroke-linecap="round"
51+
stroke-linejoin="round"
52+
/>
53+
</svg>

src/lib/rating/Heart.svelte

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<script lang="ts">
2-
import { idGenerator } from "$lib/uiHelpers.svelte";
3-
import { type HeartProps as Props } from ".";
2+
import { type RatingIconProps as Props } from ".";
43
5-
let { fillPercent = 100, fillColor = "#ff0000", strokeColor = "#ff0000", size = 24, ariaLabel = "heart", id = idGenerator(), role = "img", svgClass, ...restProps }: Props = $props();
4+
let { fillPercent = 100, fillColor = "#ff0000", strokeColor = "#ff0000", size = 24, ariaLabel = "star", starIndex = 0, groupId ="star", role = "img", svgClass, ...restProps }: Props = $props();
5+
6+
const uniqueId = `${groupId}-${starIndex}`;
67
</script>
78

89
<svg width={size} height={size} class={svgClass} {...restProps} aria-label={ariaLabel} viewBox="0 0 24 24" {role} stroke-width="1.5" stroke="currentColor" fill="none">
910
<defs>
10-
<linearGradient {id}>
11+
<linearGradient id={uniqueId}>
1112
{#if fillPercent !== 100}
1213
<stop offset="0%" stop-color={fillColor} />
1314
<stop offset="{fillPercent}%" stop-color={fillColor} />
@@ -19,7 +20,7 @@
1920
{/if}
2021
</linearGradient>
2122
</defs>
22-
<path fill="url(#{id})" stroke={strokeColor} stroke-linecap="round" stroke-linejoin="round" d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
23+
<path fill="url(#{uniqueId})" stroke={strokeColor} stroke-linecap="round" stroke-linejoin="round" d="M21 8.25c0-2.485-2.099-4.5-4.688-4.5-1.935 0-3.597 1.126-4.312 2.733-.715-1.607-2.377-2.733-4.313-2.733C5.1 3.75 3 5.765 3 8.25c0 7.22 9 12 9 12s9-4.78 9-12z" />
2324
</svg>
2425

2526
<!--

src/lib/rating/Rating.svelte

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
<script lang="ts">
22
import Star from "./Star.svelte";
3-
import { idGenerator } from "$lib/uiHelpers.svelte";
43
import { type RatingProps as Props, rating as ratingVariants } from ".";
54
6-
let { children, text, divClass, size = 24, total = 5, rating = 4, partialId = "partialStar" + idGenerator(), Icon = Star, count = false, pClass }: Props = $props();
5+
let { children, text, divClass, size = 24, total = 5, rating = 4, Icon = Star, count = false, pClass }: Props = $props();
76
87
const { base, p } = $derived(ratingVariants());
9-
10-
// generate unique id for full star and gray star
11-
const fullStarId: string = idGenerator();
12-
const grayStarId: string = idGenerator();
8+
const ratingGroupId = crypto.randomUUID();
139
let fullStars: number = Math.floor(rating);
1410
let rateDiffence = rating - fullStars;
1511
let percentRating = Math.round(rateDiffence * 100);
@@ -18,19 +14,22 @@
1814

1915
<div class={base({ class: divClass })}>
2016
{#if count && children}
21-
<Icon fillPercent={100} {size} />
17+
<Icon fillPercent={100} {size} starIndex={0} groupId={ratingGroupId}/>
2218
<p class={p({ class: pClass })}>{rating}</p>
2319
{@render children()}
2420
{:else}
2521
<!-- eslint-disable @typescript-eslint/no-unused-vars -->
26-
{#each Array(fullStars) as _}
27-
<Icon {size} fillPercent={100} id={fullStarId} />
22+
{#each Array(fullStars) as _, index}
23+
<Icon {size} fillPercent={100} starIndex={index}
24+
groupId={`${ratingGroupId}-full`} />
2825
{/each}
2926
{#if percentRating}
30-
<Icon {size} fillPercent={percentRating} id={partialId} />
27+
<Icon {size} fillPercent={percentRating} starIndex={fullStars}
28+
groupId={`${ratingGroupId}-partial`} />
3129
{/if}
32-
{#each Array(grayStars) as _}
33-
<Icon {size} fillPercent={0} id={grayStarId} />
30+
{#each Array(grayStars) as _, index}
31+
<Icon {size} fillPercent={0} starIndex={index}
32+
groupId={`${ratingGroupId}-empty`} />
3433
{/each}
3534
{#if text}
3635
{@render text()}

src/lib/rating/Star.svelte

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<script lang="ts">
2-
import { idGenerator } from "$lib/uiHelpers.svelte";
3-
import { type StarProps as Props } from ".";
2+
import { type RatingIconProps as Props } from ".";
43
5-
let { fillPercent = 100, fillColor = "#F5CA14", strokeColor = "#F5CA14", size = 24, ariaLabel = "star", id = idGenerator(), role = "img", svgClass, ...restProps }: Props = $props();
4+
let { fillPercent = 100, fillColor = "#F5CA14", strokeColor = "#F5CA14", size = 24, ariaLabel = "star", starIndex = 0, groupId ="star", role = "img", svgClass, ...restProps }: Props = $props();
5+
6+
const uniqueId = `${groupId}-${starIndex}`;
67
</script>
78

89
<svg width={size} height={size} {...restProps} class={svgClass} aria-label={ariaLabel} viewBox="100 100 120 120" {role}>
910
<defs>
10-
<linearGradient {id}>
11+
<linearGradient id={uniqueId}>
1112
{#if fillPercent !== 100}
1213
<stop offset="0%" stop-color={fillColor} />
1314
<stop offset="{fillPercent}%" stop-color={fillColor} />
@@ -19,7 +20,7 @@
1920
{/if}
2021
</linearGradient>
2122
</defs>
22-
<g fill="url(#{id})" stroke={strokeColor} stroke-width="2">
23+
<g fill="url(#{uniqueId})" stroke={strokeColor} stroke-width="2">
2324
<polygon
2425
points="165.000, 185.000, 188.511, 197.361, 184.021, 171.180,
2526
203.042, 152.639, 176.756, 148.820, 165.000, 125.000,

src/lib/rating/Thumbup.svelte

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<script lang="ts">
2-
import { idGenerator } from "$lib/uiHelpers.svelte";
3-
import { type ThumbupProps as Props } from ".";
2+
import { type RatingIconProps as Props } from ".";
43
5-
let { fillPercent = 100, fillColor = "#00b500", strokeColor = "#00b500", size = 24, ariaLabel = "thumbup", id = idGenerator(), role = "img", svgClass, ...restProps }: Props = $props();
4+
let { fillPercent = 100, fillColor = "#00b500", strokeColor = "#00b500", size = 24, ariaLabel = "thumbup", starIndex = 0, groupId ="star", role = "img", svgClass, ...restProps }: Props = $props();
5+
6+
const uniqueId = `${groupId}-${starIndex}`;
67
</script>
78

89
<svg width={size} height={size} {...restProps} class={svgClass} aria-label={ariaLabel} viewBox="0 0 24 24" {role} stroke-width="1.5" stroke="currentColor" fill="none">
910
<defs>
10-
<linearGradient {id}>
11+
<linearGradient id={uniqueId}>
1112
{#if fillPercent !== 100}
1213
<stop offset="0%" stop-color={fillColor} />
1314
<stop offset="{fillPercent}%" stop-color={fillColor} />
@@ -19,7 +20,7 @@
1920
{/if}
2021
</linearGradient>
2122
</defs>
22-
<path fill="url(#{id})" stroke={strokeColor} stroke-linecap="round" stroke-linejoin="round" d="M6.633 10.5c.806 0 1.533-.446 2.031-1.08a9.041 9.041 0 012.861-2.4c.723-.384 1.35-.956 1.653-1.715a4.498 4.498 0 00.322-1.672V3a.75.75 0 01.75-.75A2.25 2.25 0 0116.5 4.5c0 1.152-.26 2.243-.723 3.218-.266.558.107 1.282.725 1.282h3.126c1.026 0 1.945.694 2.054 1.715.045.422.068.85.068 1.285a11.95 11.95 0 01-2.649 7.521c-.388.482-.987.729-1.605.729H13.48c-.483 0-.964-.078-1.423-.23l-3.114-1.04a4.501 4.501 0 00-1.423-.23H5.904M14.25 9h2.25M5.904 18.75c.083.205.173.405.27.602.197.4-.078.898-.523.898h-.908c-.889 0-1.713-.518-1.972-1.368a12 12 0 01-.521-3.507c0-1.553.295-3.036.831-4.398C3.387 10.203 4.167 9.75 5 9.75h1.053c.472 0 .745.556.5.96a8.958 8.958 0 00-1.302 4.665c0 1.194.232 2.333.654 3.375z" />
23+
<path fill="url(#{uniqueId})" stroke={strokeColor} stroke-linecap="round" stroke-linejoin="round" d="M6.633 10.5c.806 0 1.533-.446 2.031-1.08a9.041 9.041 0 012.861-2.4c.723-.384 1.35-.956 1.653-1.715a4.498 4.498 0 00.322-1.672V3a.75.75 0 01.75-.75A2.25 2.25 0 0116.5 4.5c0 1.152-.26 2.243-.723 3.218-.266.558.107 1.282.725 1.282h3.126c1.026 0 1.945.694 2.054 1.715.045.422.068.85.068 1.285a11.95 11.95 0 01-2.649 7.521c-.388.482-.987.729-1.605.729H13.48c-.483 0-.964-.078-1.423-.23l-3.114-1.04a4.501 4.501 0 00-1.423-.23H5.904M14.25 9h2.25M5.904 18.75c.083.205.173.405.27.602.197.4-.078.898-.523.898h-.908c-.889 0-1.713-.518-1.972-1.368a12 12 0 01-.521-3.507c0-1.553.295-3.036.831-4.398C3.387 10.203 4.167 9.75 5 9.75h1.053c.472 0 .745.556.5.96a8.958 8.958 0 00-1.302 4.665c0 1.194.232 2.333.654 3.375z" />
2324
</svg>
2425

2526
<!--

src/lib/rating/index.ts

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Review from "./Review.svelte";
66
import ScoreRating from "./ScoreRating.svelte";
77
import Star from "./Star.svelte";
88
import Thumbup from "./Thumbup.svelte";
9+
import CustomIcon from "./CustomIcon.svelte";
910
import type { Snippet, Component } from "svelte";
1011
import { advancedrating, rating, review, scorerating } from "./theme";
1112
import type { SVGAttributes, HTMLAttributes } from "svelte/elements";
@@ -24,25 +25,13 @@ interface AdvancedRatingProps {
2425
unit?: string;
2526
}
2627

27-
interface HeartProps extends SVGAttributes<SVGSVGElement> {
28-
fillPercent?: number;
29-
fillColor?: string;
30-
strokeColor?: string;
31-
size?: number;
32-
ariaLabel?: string;
33-
id?: string;
34-
role?: string;
35-
svgClass?: string;
36-
}
37-
3828
interface RatingProps {
3929
children?: Snippet;
4030
text?: Snippet;
4131
divClass?: string;
4232
size?: number;
4333
total?: number;
4434
rating?: number;
45-
partialId?: string;
4635
Icon?: Component;
4736
count?: boolean;
4837
pClass?: string;
@@ -111,26 +100,17 @@ interface ScoreRatingProps {
111100
};
112101
}
113102

114-
interface StarProps extends SVGAttributes<SVGSVGElement> {
115-
fillPercent?: number;
116-
fillColor?: string;
117-
strokeColor?: string;
118-
size?: number;
119-
ariaLabel?: string;
120-
id?: string;
121-
role?: string;
122-
svgClass?: string;
123-
}
124-
125-
interface ThumbupProps extends SVGAttributes<SVGSVGElement> {
103+
interface RatingIconProps extends SVGAttributes<SVGSVGElement> {
126104
fillPercent?: number;
127105
fillColor?: string;
128106
strokeColor?: string;
129107
size?: number;
130108
ariaLabel?: string;
131-
id?: string;
132109
role?: string;
133110
svgClass?: string;
111+
starIndex?: number;
112+
groupId?: string;
113+
pathd?: string;
134114
}
135115

136-
export { AdvancedRating, advancedrating, Heart, Rating, rating, RatingComment, Review, review, ScoreRating, scorerating, Star, Thumbup, type AdvancedRatingProps, type HeartProps, type RatingProps, type RatingCommentProps, type ReviewProps, type ScoreRatingProps, type StarProps, type ThumbupProps };
116+
export { AdvancedRating, advancedrating, Heart, Rating, rating, RatingComment, Review, review, ScoreRating, scorerating, Star, Thumbup, CustomIcon, type AdvancedRatingProps, type RatingProps, type RatingCommentProps, type ReviewProps, type ScoreRatingProps, type RatingIconProps };

src/routes/components/rating/+page.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
{ name: "Text", component: ExampleComponents.Text },
2525
{ name: "Count", component: ExampleComponents.Count },
2626
{ name: "Icon", component: ExampleComponents.Icon },
27+
{ name: "Custom icon", component: ExampleComponents.CustomIcon },
2728
{ name: "Advanced rating", component: ExampleComponents.AdvancedRating },
2829
{ name: "Advanced rating and icon", component: ExampleComponents.AdvancedRatingAndIcon },
2930
{ name: "Score rating", component: ExampleComponents.ScoreRating },

src/routes/components/rating/examples/Count.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import { Rating } from "$lib";
33
</script>
44

5-
<Rating count rating={4.95}>
5+
<Rating count rating={3.2}>
66
<span class="mx-1.5 h-1 w-1 rounded-full bg-gray-500 dark:bg-gray-400"></span>
77
<a href="/" class="text-sm font-medium text-gray-900 underline hover:no-underline dark:text-white">73 reviews</a>
88
</Rating>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script lang="ts">
2+
import { CustomIcon } from "$lib";
3+
import { size } from "@floating-ui/dom";
4+
</script>
5+
6+
<div class="flex gap-2">
7+
<CustomIcon size={30} fillPercent={50} />
8+
<CustomIcon size={30} fillPercent={50} fillColor="#ff0000" strokeColor="#ff0000"/>
9+
<CustomIcon size={30} fillPercent={50} fillColor="#1158e8" strokeColor="#1158e8"
10+
pathd="M8 4a4 4 0 1 0 0 8 4 4 0 0 0 0-8Zm-2 9a4 4 0 0 0-4 4v1a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-1a4 4 0 0 0-4-4H6Zm7.25-2.095c.478-.86.75-1.85.75-2.905a5.973 5.973 0 0 0-.75-2.906 4 4 0 1 1 0 5.811ZM15.466 20c.34-.588.535-1.271.535-2v-1a5.978 5.978 0 0 0-1.528-4H18a4 4 0 0 1 4 4v1a2 2 0 0 1-2 2h-4.535Z"
11+
/>
12+
<CustomIcon size={30} fillPercent={30} fillColor="#3300e8" strokeColor="#3300e8"
13+
pathd="M9.586 2.586A2 2 0 0 1 11 2h2a2 2 0 0 1 2 2v.089l.473.196.063-.063a2.002 2.002 0 0 1 2.828 0l1.414 1.414a2 2 0 0 1 0 2.827l-.063.064.196.473H20a2 2 0 0 1 2 2v2a2 2 0 0 1-2 2h-.089l-.196.473.063.063a2.002 2.002 0 0 1 0 2.828l-1.414 1.414a2 2 0 0 1-2.828 0l-.063-.063-.473.196V20a2 2 0 0 1-2 2h-2a2 2 0 0 1-2-2v-.089l-.473-.196-.063.063a2.002 2.002 0 0 1-2.828 0l-1.414-1.414a2 2 0 0 1 0-2.827l.063-.064L4.089 15H4a2 2 0 0 1-2-2v-2a2 2 0 0 1 2-2h.09l.195-.473-.063-.063a2 2 0 0 1 0-2.828l1.414-1.414a2 2 0 0 1 2.827 0l.064.063L9 4.089V4a2 2 0 0 1 .586-1.414ZM8 12a4 4 0 1 1 8 0 4 4 0 0 1-8 0Z"
14+
/>
15+
</div>

src/routes/components/rating/examples/Star.svelte

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,15 @@
33
</script>
44

55
<div class="flex gap-2">
6-
<Star size={30} id="0" fillPercent={0} />
7-
<Star size={30} id="10" fillPercent={10} />
8-
<Star size={30} id="20" fillPercent={20} />
9-
<Star size={30} id="30" fillPercent={30} />
10-
<Star size={30} id="40" fillPercent={40} />
11-
<Star size={30} id="50" fillPercent={50} />
12-
<Star size={30} id="60" fillPercent={60} />
13-
<Star size={30} id="70" fillPercent={70} />
14-
<Star size={30} id="80" fillPercent={80} />
15-
<Star size={30} id="90" fillPercent={90} />
16-
<Star size={30} id="100" fillPercent={100} />
6+
<Star size={30} starIndex={0} fillPercent={0} />
7+
<Star size={30} starIndex={10} fillPercent={10} />
8+
<Star size={30} starIndex={20} fillPercent={20} />
9+
<Star size={30} starIndex={30} fillPercent={30} />
10+
<Star size={30} starIndex={40} fillPercent={40} />
11+
<Star size={30} starIndex={50} fillPercent={50} />
12+
<Star size={30} starIndex={60} fillPercent={60} />
13+
<Star size={30} starIndex={70} fillPercent={70} />
14+
<Star size={30} starIndex={80} fillPercent={80} />
15+
<Star size={30} starIndex={90} fillPercent={90} />
16+
<Star size={30} starIndex={100} fillPercent={100} />
1717
</div>

0 commit comments

Comments
 (0)