feat: integrate StarRating component into MediaFormModal for improved rating input

This commit is contained in:
ethan.chen
2025-05-27 18:40:23 +08:00
parent 69e4a66375
commit 701021c112
2 changed files with 44 additions and 11 deletions

View File

@@ -2,6 +2,7 @@
import type { Media } from './interfaces'; import type { Media } from './interfaces';
import { fade, scale } from 'svelte/transition'; import { fade, scale } from 'svelte/transition';
import DatePicker from './DatePicker.svelte'; import DatePicker from './DatePicker.svelte';
import StarRating from './StarRating.svelte';
let {show, mode, submitMedia, handleClose, media: initialMedia, itemType} = $props(); let {show, mode, submitMedia, handleClose, media: initialMedia, itemType} = $props();
let media: Media = $state({ let media: Media = $state({
@@ -114,17 +115,11 @@
/> />
</div> </div>
<div class="flex justify-between items-center gap-6"> <div class="flex start items-center gap-6">
<label class="font-medium text-gray-700 whitespace-nowrap" for="rating">评分</label> <label for="score" class="font-medium text-gray-700 whitespace-nowrap">评分</label>
<input <StarRating
id="rating" value={media.rating}
type="number" onSelect={(score: number) => media.rating = score}
min="0"
max="10"
step="0.5"
bind:value={media.rating}
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
aria-label="输入评分范围0-10"
/> />
</div> </div>
{#if media.type === 'game' || media.type === 'other'} {#if media.type === 'game' || media.type === 'other'}

38
src/lib/StarRating.svelte Normal file
View File

@@ -0,0 +1,38 @@
<script lang="ts">
let { value = 0, maxStars = 10, onSelect } = $props();
let hoverValue = $state(0);
function handleStarClick(index: number) {
onSelect(index + 1);
}
function handleStarHover(index: number) {
hoverValue = index + 1;
}
function handleMouseLeave() {
hoverValue = 0;
}
</script>
<div class="flex items-center gap-1" onmouseleave={handleMouseLeave} role="presentation">
{#each Array(maxStars) as _, i}
<div
class="text-l focus:outline-none transition-colors duration-200 cursor-pointer"
class:text-yellow-400={i <(hoverValue || value)}
class:text-gray-300={i >= (hoverValue || value)}
onclick={(e) => {
e.preventDefault();
e.stopPropagation();
handleStarClick(i);
}}
onmouseenter={() => handleStarHover(i)}
role="presentation"
>
</div>
{/each}
{#if value > 0}
<span class="ml-2 text-sm text-gray-600">{value}</span>
{/if}
</div>