feat: add review
This commit is contained in:
25
libs/reviews-stars/.eslintrc.json
Normal file
25
libs/reviews-stars/.eslintrc.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*", "storybook-static"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.ts", "*.tsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.js", "*.jsx"],
|
||||
"rules": {}
|
||||
},
|
||||
{
|
||||
"files": ["*.json"],
|
||||
"parser": "jsonc-eslint-parser",
|
||||
"rules": {
|
||||
"@nx/dependency-checks": "error"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
34
libs/reviews-stars/.storybook/main.ts
Normal file
34
libs/reviews-stars/.storybook/main.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||
import type { StorybookConfig } from '@storybook/web-components-vite';
|
||||
import { mergeConfig } from 'vite';
|
||||
|
||||
// These options were migrated by @nx/storybook:convert-to-inferred from the project.json file.
|
||||
const configValues = { default: {}, ci: {} };
|
||||
|
||||
// Determine the correct configValue to use based on the configuration
|
||||
const nxConfiguration = process.env.NX_TASK_TARGET_CONFIGURATION ?? 'default';
|
||||
|
||||
const options = {
|
||||
...configValues.default,
|
||||
...(configValues[nxConfiguration] ?? {}),
|
||||
};
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../src/lib/*.stories.@(js|jsx|ts|tsx|mdx)'],
|
||||
addons: ['@storybook/addon-essentials', '@storybook/addon-interactions'],
|
||||
framework: {
|
||||
name: '@storybook/web-components-vite',
|
||||
options: {},
|
||||
},
|
||||
|
||||
viteFinal: async (config) =>
|
||||
mergeConfig(config, {
|
||||
plugins: [nxViteTsPaths()],
|
||||
}),
|
||||
};
|
||||
|
||||
export default config;
|
||||
|
||||
// To customize your Vite configuration you can use the viteFinal field.
|
||||
// Check https://storybook.js.org/docs/react/builders/vite#configuration
|
||||
// and https://nx.dev/recipes/storybook/custom-builder-configs
|
||||
0
libs/reviews-stars/.storybook/preview.ts
Normal file
0
libs/reviews-stars/.storybook/preview.ts
Normal file
11
libs/reviews-stars/README.md
Normal file
11
libs/reviews-stars/README.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# reviews-stars
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
## Building
|
||||
|
||||
Run `nx build reviews-stars` to build the library.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test reviews-stars` to execute the unit tests via [Jest](https://jestjs.io).
|
||||
11
libs/reviews-stars/jest.config.ts
Normal file
11
libs/reviews-stars/jest.config.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
displayName: 'reviews-stars',
|
||||
preset: '../../jest.preset.js',
|
||||
testEnvironment: 'node',
|
||||
transform: {
|
||||
'^.+\\.[tj]s$': ['ts-jest', { tsconfig: '<rootDir>/tsconfig.spec.json' }],
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||
coverageDirectory: '../../coverage/libs/reviews-stars',
|
||||
};
|
||||
11
libs/reviews-stars/package.json
Normal file
11
libs/reviews-stars/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@z-elements/reviews-stars",
|
||||
"version": "0.0.1",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"main": "./src/index.js",
|
||||
"typings": "./src/index.d.ts",
|
||||
"private": true
|
||||
}
|
||||
64
libs/reviews-stars/project.json
Normal file
64
libs/reviews-stars/project.json
Normal file
@@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "reviews-stars",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "libs/reviews-stars/src",
|
||||
"projectType": "library",
|
||||
"tags": [],
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nx/js:tsc",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/libs/reviews-stars",
|
||||
"main": "libs/reviews-stars/src/index.ts",
|
||||
"tsConfig": "libs/reviews-stars/tsconfig.lib.json",
|
||||
"assets": ["libs/reviews-stars/*.md"]
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint"
|
||||
},
|
||||
"test": {
|
||||
"executor": "@nx/jest:jest",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"jestConfig": "libs/reviews-stars/jest.config.ts"
|
||||
}
|
||||
},
|
||||
"storybook": {
|
||||
"options": {
|
||||
"port": 4400,
|
||||
"config-dir": ".storybook"
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"args": ["--quiet"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"build-storybook": {
|
||||
"outputs": [
|
||||
"{projectRoot}/{options.output-dir}",
|
||||
"{workspaceRoot}/{projectRoot}/storybook-static",
|
||||
"{options.output-dir}",
|
||||
"{options.outputDir}",
|
||||
"{options.o}"
|
||||
],
|
||||
"options": {
|
||||
"config-dir": ".storybook",
|
||||
"output-dir": "../../dist/storybook/reviews-stars"
|
||||
},
|
||||
"configurations": {
|
||||
"ci": {
|
||||
"quiet": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"test-storybook": {
|
||||
"executor": "nx:run-commands",
|
||||
"options": {
|
||||
"command": "test-storybook -c libs/reviews-stars/.storybook --url=http://localhost:4400"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1
libs/reviews-stars/src/index.ts
Normal file
1
libs/reviews-stars/src/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './lib/reviews-stars';
|
||||
7
libs/reviews-stars/src/lib/reviews-stars.spec.ts
Normal file
7
libs/reviews-stars/src/lib/reviews-stars.spec.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { reviewsStars } from './reviews-stars';
|
||||
|
||||
describe('reviewsStars', () => {
|
||||
it('should work', () => {
|
||||
expect(reviewsStars()).toEqual('reviews-stars');
|
||||
});
|
||||
});
|
||||
53
libs/reviews-stars/src/lib/reviews-stars.stories.ts
Normal file
53
libs/reviews-stars/src/lib/reviews-stars.stories.ts
Normal file
@@ -0,0 +1,53 @@
|
||||
import { Meta, StoryObj } from '@storybook/web-components';
|
||||
|
||||
import { html } from 'lit';
|
||||
|
||||
import './reviews-stars';
|
||||
import { ReviewsStarsComponent } from './reviews-stars';
|
||||
|
||||
const meta: Meta<ReviewsStarsComponent> = {
|
||||
title: 'Design System/Atoms/Reviews Stars',
|
||||
component: 'z-reviews.stars',
|
||||
render: (args) => html`
|
||||
<z-reviews.stars
|
||||
?allow-fractional="${args.allowFractional}"
|
||||
rating="${args.rating}"
|
||||
out-of="${args.outOf}"
|
||||
.stars=${args.stars}
|
||||
></z-reviews.stars>
|
||||
`,
|
||||
parameters: {
|
||||
layout: 'centered',
|
||||
},
|
||||
argTypes: {
|
||||
rating: {
|
||||
control: 'number',
|
||||
min: 1,
|
||||
},
|
||||
outOf: {
|
||||
control: {
|
||||
type: 'number',
|
||||
min: 1,
|
||||
},
|
||||
},
|
||||
stars: {
|
||||
control: {
|
||||
type: 'number',
|
||||
min: 1,
|
||||
},
|
||||
},
|
||||
allowFractional: {
|
||||
control: 'boolean',
|
||||
},
|
||||
},
|
||||
args: {
|
||||
rating: 3,
|
||||
outOf: 5,
|
||||
stars: 5,
|
||||
allowFractional: false,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const Primary: StoryObj<ReviewsStarsComponent> = {};
|
||||
140
libs/reviews-stars/src/lib/reviews-stars.ts
Normal file
140
libs/reviews-stars/src/lib/reviews-stars.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { css, CSSResultArray, html, LitElement, TemplateResult } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
/**
|
||||
* @cssprop --filled-star-color - The color of the filled stars.
|
||||
* @cssprop --empty-star-color - The color of the empty stars.
|
||||
*/
|
||||
@customElement('z-reviews.stars')
|
||||
export class ReviewsStarsComponent extends LitElement {
|
||||
/// Private variables ///
|
||||
|
||||
/// Protected variables ///
|
||||
@state() protected _filledStarCount = 0;
|
||||
|
||||
/// Public variables ///
|
||||
@property({ type: Number }) public rating: number | undefined;
|
||||
@property({ type: Number, attribute: 'out-of' }) public outOf: number | undefined;
|
||||
@property({ type: Number }) public stars: number = 5;
|
||||
@property({ type: Boolean, attribute: 'allow-fractional' }) public allowFractional = false;
|
||||
|
||||
/// constructor & lifecycle ///
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
this.validateProperties();
|
||||
}
|
||||
|
||||
override updated(changedProperties: Map<string | number | symbol, unknown>): void {
|
||||
super.updated(changedProperties);
|
||||
|
||||
this._filledStarCount = this.calculateFilledStarCount();
|
||||
// this.requestUpdate();
|
||||
}
|
||||
|
||||
/// Public methods ///
|
||||
|
||||
/// Protected methods ///
|
||||
protected override render(): TemplateResult {
|
||||
return html`
|
||||
<div class="stars">${this.renderStars()}</div>
|
||||
<div
|
||||
class="stars stars--filled"
|
||||
style="${styleMap({
|
||||
'--filled-star-count': this._filledStarCount,
|
||||
'--_filled-star-width': `${(this._filledStarCount / this.stars) * 100}%`,
|
||||
})}"
|
||||
>
|
||||
${this.renderStars()}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
protected renderStars(): TemplateResult {
|
||||
const stars: TemplateResult[] = [];
|
||||
|
||||
for (let i = 0; i < this.stars; i++) {
|
||||
stars.push(this.renderStar());
|
||||
}
|
||||
|
||||
return html`${stars}`;
|
||||
}
|
||||
|
||||
protected renderStar(): TemplateResult {
|
||||
return html`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512" class="icon">
|
||||
<!--!Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.-->
|
||||
<path
|
||||
d="M316.9 18C311.6 7 300.4 0 288.1 0s-23.4 7-28.8 18L195 150.3 51.4 171.5c-12 1.8-22 10.2-25.7 21.7s-.7 24.2 7.9 32.7L137.8 329 113.2 474.7c-2 12 3 24.2 12.9 31.3s23 8 33.8 2.3l128.3-68.5 128.3 68.5c10.8 5.7 23.9 4.9 33.8-2.3s14.9-19.3 12.9-31.3L438.5 329 542.7 225.9c8.6-8.5 11.7-21.2 7.9-32.7s-13.7-19.9-25.7-21.7L381.2 150.3 316.9 18z"
|
||||
/>
|
||||
</svg>
|
||||
</svg>`;
|
||||
}
|
||||
|
||||
/// Private methods ///
|
||||
/**
|
||||
* Validate the properties for the rules of availability.
|
||||
*
|
||||
* @throws {Error} If the properties are not valid.
|
||||
*/
|
||||
private validateProperties(): void {
|
||||
console.log(this.rating, this.stars, this.outOf, this.allowFractional);
|
||||
if (!this.rating) {
|
||||
throw new Error('Rating is required.');
|
||||
}
|
||||
|
||||
if (!this.outOf) {
|
||||
throw new Error('Out of is required when rating is used.');
|
||||
}
|
||||
|
||||
if (this.stars < 1) {
|
||||
throw new Error('Stars cannot be less than 1.');
|
||||
}
|
||||
|
||||
if (this.rating! > this.outOf) {
|
||||
throw new Error('Rating cannot be greater than out of.');
|
||||
}
|
||||
}
|
||||
|
||||
private calculateFilledStarCount(): number {
|
||||
if (this.allowFractional) {
|
||||
return (this.rating! / this.outOf!) * this.stars;
|
||||
}
|
||||
|
||||
return Math.round((this.rating! / this.outOf!) * this.stars);
|
||||
}
|
||||
|
||||
/// Statics ///
|
||||
|
||||
static override styles: CSSResultArray = [
|
||||
css`
|
||||
:host {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.icon {
|
||||
vertical-align: -0.125em;
|
||||
flex: 0 0 1em;
|
||||
height: 1em;
|
||||
width: 1em;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
.stars {
|
||||
display: flex;
|
||||
color: var(--empty-star-color, #e4e5e9);
|
||||
}
|
||||
|
||||
.stars--filled {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
opacity: 1;
|
||||
right: calc(100% - var(--_filled-star-width));
|
||||
color: var(--filled-star-color, #f7b731);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
25
libs/reviews-stars/tsconfig.json
Normal file
25
libs/reviews-stars/tsconfig.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"noImplicitOverride": true,
|
||||
"noPropertyAccessFromIndexSignature": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.storybook.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
10
libs/reviews-stars/tsconfig.lib.json
Normal file
10
libs/reviews-stars/tsconfig.lib.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"declaration": true,
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src/**/*.ts"],
|
||||
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts", "**/*.stories.ts", "**/*.stories.js"]
|
||||
}
|
||||
9
libs/reviews-stars/tsconfig.spec.json
Normal file
9
libs/reviews-stars/tsconfig.spec.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts", "src/**/*.d.ts"]
|
||||
}
|
||||
16
libs/reviews-stars/tsconfig.storybook.json
Normal file
16
libs/reviews-stars/tsconfig.storybook.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"emitDecoratorMetadata": true
|
||||
},
|
||||
"exclude": ["src/**/*.spec.ts", "src/**/*.test.ts"],
|
||||
"include": [
|
||||
"src/**/*.stories.ts",
|
||||
"src/**/*.stories.js",
|
||||
"src/**/*.stories.jsx",
|
||||
"src/**/*.stories.tsx",
|
||||
"src/**/*.stories.mdx",
|
||||
".storybook/*.js",
|
||||
".storybook/*.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user