Update Docs
This commit is contained in:
@@ -0,0 +1,536 @@
|
||||
# Rating
|
||||
|
||||
Star rating component with customizable count, icons, and read-only mode.
|
||||
|
||||
## Tag
|
||||
|
||||
`Rating`
|
||||
|
||||
## Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| :----------- | :--------------------------- | :--------------- | :----------------------------------------------- |
|
||||
| `value` | `number \| Signal<number>` | `0` | Current rating value |
|
||||
| `count` | `number \| Signal<number>` | `5` | Number of stars/items |
|
||||
| `mask` | `string` | `'mask-star'` | Mask shape (mask-star, mask-star-2, mask-heart) |
|
||||
| `readonly` | `boolean \| Signal<boolean>` | `false` | Disable interaction |
|
||||
| `class` | `string` | `''` | Additional CSS classes (DaisyUI + Tailwind) |
|
||||
|
||||
## Live Examples
|
||||
|
||||
### Basic Rating
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-basic" class="bg-base-100 p-6 rounded-xl border border-base-300 flex items-center justify-center"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const BasicDemo = () => {
|
||||
const rating = $(3);
|
||||
|
||||
return Div({ class: 'flex flex-col gap-2 items-center' }, [
|
||||
Rating({
|
||||
value: rating,
|
||||
count: 5,
|
||||
onchange: (value) => rating(value)
|
||||
}),
|
||||
Div({ class: 'text-sm opacity-70' }, () => `Rating: ${rating()} / 5`)
|
||||
]);
|
||||
};
|
||||
$mount(BasicDemo, '#demo-basic');
|
||||
```
|
||||
|
||||
### Heart Rating
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-heart" class="bg-base-100 p-6 rounded-xl border border-base-300 flex items-center justify-center"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const HeartDemo = () => {
|
||||
const rating = $(4);
|
||||
|
||||
return Div({ class: 'flex flex-col gap-2 items-center' }, [
|
||||
Rating({
|
||||
value: rating,
|
||||
count: 5,
|
||||
mask: 'mask-heart',
|
||||
onchange: (value) => rating(value)
|
||||
}),
|
||||
Div({ class: 'text-sm opacity-70' }, () => `${rating()} hearts`)
|
||||
]);
|
||||
};
|
||||
$mount(HeartDemo, '#demo-heart');
|
||||
```
|
||||
|
||||
### Star with Outline
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-star2" class="bg-base-100 p-6 rounded-xl border border-base-300 flex items-center justify-center"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const Star2Demo = () => {
|
||||
const rating = $(2);
|
||||
|
||||
return Div({ class: 'flex flex-col gap-2 items-center' }, [
|
||||
Rating({
|
||||
value: rating,
|
||||
count: 5,
|
||||
mask: 'mask-star-2',
|
||||
onchange: (value) => rating(value)
|
||||
}),
|
||||
Div({ class: 'text-sm opacity-70' }, () => `${rating()} stars`)
|
||||
]);
|
||||
};
|
||||
$mount(Star2Demo, '#demo-star2');
|
||||
```
|
||||
|
||||
### Read-only Rating
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-readonly" class="bg-base-100 p-6 rounded-xl border border-base-300 flex items-center justify-center"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const ReadonlyDemo = () => {
|
||||
const rating = $(4.5);
|
||||
|
||||
return Div({ class: 'flex flex-col gap-2 items-center' }, [
|
||||
Rating({
|
||||
value: rating,
|
||||
count: 5,
|
||||
readonly: true
|
||||
}),
|
||||
Div({ class: 'text-sm opacity-70' }, 'Average rating: 4.5/5 (read-only)')
|
||||
]);
|
||||
};
|
||||
$mount(ReadonlyDemo, '#demo-readonly');
|
||||
```
|
||||
|
||||
### Custom Count
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-custom" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const CustomDemo = () => {
|
||||
const rating = $(3);
|
||||
const count = $(10);
|
||||
|
||||
return Div({ class: 'flex flex-col gap-4 w-full' }, [
|
||||
Div({ class: 'flex items-center gap-4' }, [
|
||||
Span({ class: 'text-sm' }, 'Number of stars:'),
|
||||
Input({
|
||||
type: 'number',
|
||||
value: count,
|
||||
class: 'input input-sm w-24',
|
||||
oninput: (e) => count(parseInt(e.target.value) || 1)
|
||||
})
|
||||
]),
|
||||
Rating({
|
||||
value: rating,
|
||||
count: count,
|
||||
onchange: (value) => rating(value)
|
||||
}),
|
||||
Div({ class: 'text-sm opacity-70' }, () => `Rating: ${rating()} / ${count()}`)
|
||||
]);
|
||||
};
|
||||
$mount(CustomDemo, '#demo-custom');
|
||||
```
|
||||
|
||||
### Product Review
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-review" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const ReviewDemo = () => {
|
||||
const quality = $(4);
|
||||
const price = $(3);
|
||||
const support = $(5);
|
||||
|
||||
const average = () => Math.round(((quality() + price() + support()) / 3) * 10) / 10;
|
||||
|
||||
return Div({ class: 'flex flex-col gap-4' }, [
|
||||
Div({ class: 'text-lg font-bold' }, 'Product Review'),
|
||||
Div({ class: 'flex flex-col gap-2' }, [
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-sm w-24' }, 'Quality:'),
|
||||
Rating({
|
||||
value: quality,
|
||||
count: 5,
|
||||
size: 'sm',
|
||||
onchange: (v) => quality(v)
|
||||
})
|
||||
]),
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-sm w-24' }, 'Price:'),
|
||||
Rating({
|
||||
value: price,
|
||||
count: 5,
|
||||
size: 'sm',
|
||||
onchange: (v) => price(v)
|
||||
})
|
||||
]),
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-sm w-24' }, 'Support:'),
|
||||
Rating({
|
||||
value: support,
|
||||
count: 5,
|
||||
size: 'sm',
|
||||
onchange: (v) => support(v)
|
||||
})
|
||||
])
|
||||
]),
|
||||
Div({ class: 'divider my-1' }),
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'font-bold' }, 'Overall:'),
|
||||
Div({ class: 'text-2xl font-bold text-primary' }, () => average())
|
||||
])
|
||||
]);
|
||||
};
|
||||
$mount(ReviewDemo, '#demo-review');
|
||||
```
|
||||
|
||||
### All Variants
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-variants" class="bg-base-100 p-6 rounded-xl border border-base-300 flex flex-col gap-6"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const VariantsDemo = () => {
|
||||
return Div({ class: 'flex flex-col gap-6' }, [
|
||||
Div({ class: 'text-center' }, [
|
||||
Div({ class: 'text-sm mb-2' }, 'Mask Star'),
|
||||
Rating({ value: $(3), count: 5, mask: 'mask-star' })
|
||||
]),
|
||||
Div({ class: 'text-center' }, [
|
||||
Div({ class: 'text-sm mb-2' }, 'Mask Star 2 (yellow)' ),
|
||||
Rating({ value: $(4), count: 5, mask: 'mask-star-2', class: 'rating-warning' })
|
||||
]),
|
||||
Div({ class: 'text-center' }, [
|
||||
Div({ class: 'text-sm mb-2' }, 'Mask Heart'),
|
||||
Rating({ value: $(5), count: 5, mask: 'mask-heart', class: 'rating-error' })
|
||||
]),
|
||||
Div({ class: 'text-center' }, [
|
||||
Div({ class: 'text-sm mb-2' }, 'Half Stars (read-only)'),
|
||||
Rating({ value: $(3.5), count: 5, readonly: true })
|
||||
])
|
||||
]);
|
||||
};
|
||||
$mount(VariantsDemo, '#demo-variants');
|
||||
```
|
||||
|
||||
### Interactive Feedback
|
||||
|
||||
<div class="card bg-base-200 border border-base-300 shadow-sm my-6">
|
||||
<div class="card-body">
|
||||
<h3 class="card-title text-sm uppercase opacity-50 mb-4">Live Demo</h3>
|
||||
<div id="demo-feedback" class="bg-base-100 p-6 rounded-xl border border-base-300"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
```javascript
|
||||
const FeedbackDemo = () => {
|
||||
const rating = $(0);
|
||||
const feedback = $(false);
|
||||
|
||||
const messages = {
|
||||
1: 'Very disappointed 😞',
|
||||
2: 'Could be better 😕',
|
||||
3: 'Good 👍',
|
||||
4: 'Very good 😊',
|
||||
5: 'Excellent! 🎉'
|
||||
};
|
||||
|
||||
return Div({ class: 'flex flex-col gap-4 items-center' }, [
|
||||
Div({ class: 'text-center' }, [
|
||||
Div({ class: 'text-sm mb-2' }, 'How was your experience?'),
|
||||
Rating({
|
||||
value: rating,
|
||||
count: 5,
|
||||
onchange: (value) => {
|
||||
rating(value);
|
||||
feedback(true);
|
||||
if (value >= 4) {
|
||||
Toast('Thank you for your positive feedback!', 'alert-success', 2000);
|
||||
} else if (value <= 2) {
|
||||
Toast('We appreciate your feedback and will improve!', 'alert-warning', 2000);
|
||||
} else {
|
||||
Toast('Thanks for your rating!', 'alert-info', 2000);
|
||||
}
|
||||
}
|
||||
})
|
||||
]),
|
||||
() => rating() > 0
|
||||
? Div({ class: 'alert alert-soft text-center' }, [
|
||||
messages[rating()] || `Rating: ${rating()} stars`
|
||||
])
|
||||
: null
|
||||
]);
|
||||
};
|
||||
$mount(FeedbackDemo, '#demo-feedback');
|
||||
```
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
const initRatingExamples = () => {
|
||||
|
||||
// 1. Basic Rating
|
||||
const basicTarget = document.querySelector('#demo-basic');
|
||||
if (basicTarget && !basicTarget.hasChildNodes()) {
|
||||
const BasicDemo = () => {
|
||||
const rating = $(3);
|
||||
|
||||
return Div({ class: 'flex flex-col gap-2 items-center' }, [
|
||||
Rating({
|
||||
value: rating,
|
||||
count: 5,
|
||||
onchange: (value) => rating(value)
|
||||
}),
|
||||
Div({ class: 'text-sm opacity-70' }, () => `Rating: ${rating()} / 5`)
|
||||
]);
|
||||
};
|
||||
$mount(BasicDemo, basicTarget);
|
||||
}
|
||||
|
||||
// 2. Heart Rating
|
||||
const heartTarget = document.querySelector('#demo-heart');
|
||||
if (heartTarget && !heartTarget.hasChildNodes()) {
|
||||
const HeartDemo = () => {
|
||||
const rating = $(4);
|
||||
|
||||
return Div({ class: 'flex flex-col gap-2 items-center' }, [
|
||||
Rating({
|
||||
value: rating,
|
||||
count: 5,
|
||||
mask: 'mask-heart',
|
||||
onchange: (value) => rating(value)
|
||||
}),
|
||||
Div({ class: 'text-sm opacity-70' }, () => `${rating()} hearts`)
|
||||
]);
|
||||
};
|
||||
$mount(HeartDemo, heartTarget);
|
||||
}
|
||||
|
||||
// 3. Star with Outline
|
||||
const star2Target = document.querySelector('#demo-star2');
|
||||
if (star2Target && !star2Target.hasChildNodes()) {
|
||||
const Star2Demo = () => {
|
||||
const rating = $(2);
|
||||
|
||||
return Div({ class: 'flex flex-col gap-2 items-center' }, [
|
||||
Rating({
|
||||
value: rating,
|
||||
count: 5,
|
||||
mask: 'mask-star-2',
|
||||
onchange: (value) => rating(value)
|
||||
}),
|
||||
Div({ class: 'text-sm opacity-70' }, () => `${rating()} stars`)
|
||||
]);
|
||||
};
|
||||
$mount(Star2Demo, star2Target);
|
||||
}
|
||||
|
||||
// 4. Read-only Rating
|
||||
const readonlyTarget = document.querySelector('#demo-readonly');
|
||||
if (readonlyTarget && !readonlyTarget.hasChildNodes()) {
|
||||
const ReadonlyDemo = () => {
|
||||
const rating = $(4.5);
|
||||
|
||||
return Div({ class: 'flex flex-col gap-2 items-center' }, [
|
||||
Rating({
|
||||
value: rating,
|
||||
count: 5,
|
||||
readonly: true
|
||||
}),
|
||||
Div({ class: 'text-sm opacity-70' }, 'Average rating: 4.5/5 (read-only)')
|
||||
]);
|
||||
};
|
||||
$mount(ReadonlyDemo, readonlyTarget);
|
||||
}
|
||||
|
||||
// 5. Custom Count
|
||||
const customTarget = document.querySelector('#demo-custom');
|
||||
if (customTarget && !customTarget.hasChildNodes()) {
|
||||
const CustomDemo = () => {
|
||||
const rating = $(3);
|
||||
const count = $(10);
|
||||
|
||||
return Div({ class: 'flex flex-col gap-4 w-full' }, [
|
||||
Div({ class: 'flex items-center gap-4' }, [
|
||||
Span({ class: 'text-sm' }, 'Number of stars:'),
|
||||
Input({
|
||||
type: 'number',
|
||||
value: count,
|
||||
class: 'input input-sm w-24',
|
||||
oninput: (e) => count(parseInt(e.target.value) || 1)
|
||||
})
|
||||
]),
|
||||
Rating({
|
||||
value: rating,
|
||||
count: count,
|
||||
onchange: (value) => rating(value)
|
||||
}),
|
||||
Div({ class: 'text-sm opacity-70' }, () => `Rating: ${rating()} / ${count()}`)
|
||||
]);
|
||||
};
|
||||
$mount(CustomDemo, customTarget);
|
||||
}
|
||||
|
||||
// 6. Product Review
|
||||
const reviewTarget = document.querySelector('#demo-review');
|
||||
if (reviewTarget && !reviewTarget.hasChildNodes()) {
|
||||
const ReviewDemo = () => {
|
||||
const quality = $(4);
|
||||
const price = $(3);
|
||||
const support = $(5);
|
||||
|
||||
const average = () => Math.round(((quality() + price() + support()) / 3) * 10) / 10;
|
||||
|
||||
return Div({ class: 'flex flex-col gap-4' }, [
|
||||
Div({ class: 'text-lg font-bold' }, 'Product Review'),
|
||||
Div({ class: 'flex flex-col gap-2' }, [
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-sm w-24' }, 'Quality:'),
|
||||
Rating({
|
||||
value: quality,
|
||||
count: 5,
|
||||
size: 'sm',
|
||||
onchange: (v) => quality(v)
|
||||
})
|
||||
]),
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-sm w-24' }, 'Price:'),
|
||||
Rating({
|
||||
value: price,
|
||||
count: 5,
|
||||
size: 'sm',
|
||||
onchange: (v) => price(v)
|
||||
})
|
||||
]),
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'text-sm w-24' }, 'Support:'),
|
||||
Rating({
|
||||
value: support,
|
||||
count: 5,
|
||||
size: 'sm',
|
||||
onchange: (v) => support(v)
|
||||
})
|
||||
])
|
||||
]),
|
||||
Div({ class: 'divider my-1' }),
|
||||
Div({ class: 'flex justify-between items-center' }, [
|
||||
Span({ class: 'font-bold' }, 'Overall:'),
|
||||
Div({ class: 'text-2xl font-bold text-primary' }, () => average())
|
||||
])
|
||||
]);
|
||||
};
|
||||
$mount(ReviewDemo, reviewTarget);
|
||||
}
|
||||
|
||||
// 7. All Variants
|
||||
const variantsTarget = document.querySelector('#demo-variants');
|
||||
if (variantsTarget && !variantsTarget.hasChildNodes()) {
|
||||
const VariantsDemo = () => {
|
||||
return Div({ class: 'flex flex-col gap-6' }, [
|
||||
Div({ class: 'text-center' }, [
|
||||
Div({ class: 'text-sm mb-2' }, 'Mask Star'),
|
||||
Rating({ value: $(3), count: 5, mask: 'mask-star' })
|
||||
]),
|
||||
Div({ class: 'text-center' }, [
|
||||
Div({ class: 'text-sm mb-2' }, 'Mask Star 2 (yellow)' ),
|
||||
Rating({ value: $(4), count: 5, mask: 'mask-star-2', class: 'rating-warning' })
|
||||
]),
|
||||
Div({ class: 'text-center' }, [
|
||||
Div({ class: 'text-sm mb-2' }, 'Mask Heart'),
|
||||
Rating({ value: $(5), count: 5, mask: 'mask-heart', class: 'rating-error' })
|
||||
]),
|
||||
Div({ class: 'text-center' }, [
|
||||
Div({ class: 'text-sm mb-2' }, 'Half Stars (read-only)'),
|
||||
Rating({ value: $(3.5), count: 5, readonly: true })
|
||||
])
|
||||
]);
|
||||
};
|
||||
$mount(VariantsDemo, variantsTarget);
|
||||
}
|
||||
|
||||
// 8. Interactive Feedback
|
||||
const feedbackTarget = document.querySelector('#demo-feedback');
|
||||
if (feedbackTarget && !feedbackTarget.hasChildNodes()) {
|
||||
const FeedbackDemo = () => {
|
||||
const rating = $(0);
|
||||
const feedback = $(false);
|
||||
|
||||
const messages = {
|
||||
1: 'Very disappointed 😞',
|
||||
2: 'Could be better 😕',
|
||||
3: 'Good 👍',
|
||||
4: 'Very good 😊',
|
||||
5: 'Excellent! 🎉'
|
||||
};
|
||||
|
||||
return Div({ class: 'flex flex-col gap-4 items-center' }, [
|
||||
Div({ class: 'text-center' }, [
|
||||
Div({ class: 'text-sm mb-2' }, 'How was your experience?'),
|
||||
Rating({
|
||||
value: rating,
|
||||
count: 5,
|
||||
onchange: (value) => {
|
||||
rating(value);
|
||||
feedback(true);
|
||||
if (value >= 4) {
|
||||
Toast('Thank you for your positive feedback!', 'alert-success', 2000);
|
||||
} else if (value <= 2) {
|
||||
Toast('We appreciate your feedback and will improve!', 'alert-warning', 2000);
|
||||
} else {
|
||||
Toast('Thanks for your rating!', 'alert-info', 2000);
|
||||
}
|
||||
}
|
||||
})
|
||||
]),
|
||||
() => rating() > 0
|
||||
? Div({ class: 'alert alert-soft text-center' }, [
|
||||
messages[rating()] || `Rating: ${rating()} stars`
|
||||
])
|
||||
: null
|
||||
]);
|
||||
};
|
||||
$mount(FeedbackDemo, feedbackTarget);
|
||||
}
|
||||
};
|
||||
|
||||
initRatingExamples();
|
||||
|
||||
if (window.$docsify) {
|
||||
window.$docsify.plugins = [].concat(window.$docsify.plugins || [], (hook) => {
|
||||
hook.doneEach(initRatingExamples);
|
||||
});
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user