Skip to content

Commit

Permalink
chore: score render via score value
Browse files Browse the repository at this point in the history
  • Loading branch information
wenqing committed Aug 14, 2023
1 parent 5ce89b6 commit 1cfd31c
Show file tree
Hide file tree
Showing 12 changed files with 396 additions and 3 deletions.
1 change: 1 addition & 0 deletions env.d.ts
@@ -1 +1,2 @@
/// <reference types="vite/client" />
/// <reference types="vite-plugin-svg4vue/client" />
4 changes: 4 additions & 0 deletions package.json
Expand Up @@ -68,9 +68,13 @@
"sass": "^1.65.1",
"typescript": "~5.1.6",
"vite": "^4.4.6",
"vite-plugin-svg4vue": "^2.16.0",
"vitest": "^0.33.0",
"vue": "^3.3.4",
"vue-router": "^4.2.4",
"vue-tsc": "^1.8.6"
},
"dependencies": {
"fourdom": "^1.3.0"
}
}
129 changes: 129 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions src/lib/CONSTANTS.ts
@@ -0,0 +1,7 @@
export enum CONSTANTS {
containerClassName = 'starscore-container',
scoreWrapperClassName = 'starscore-radio-group',
scoreItemClassName = 'starscore-radio',
scoreIconClassName = 'starscore-radio__icon',
scoreVoidIconClassName = 'starscore-radio__void-icon',
}
143 changes: 142 additions & 1 deletion src/lib/Starscore.ts
Expand Up @@ -2,18 +2,159 @@ import type {
StarscoreInstance,
CreateStarscore,
StarscoreOptions,
ScoreItemsRecord,
} from './interfaces/core'
import { CONSTANTS } from './CONSTANTS'
import { addClass, css } from 'fourdom'
import StarIcon from './icons/star.svg?raw'
import VoidStarIcon from './icons/void-star.svg?raw'
import { safetyNumberToPx } from './utils'

class Starscore implements StarscoreInstance {
options: Required<StarscoreOptions> = {
container: '',
count: 5,
size: '20px',
gutter: '4px',
color: '#ee0a24',
voidColor: '#c8c9cc',
disabledColor: '#c8c9cc',
icon: '',
voidIcon: '',
readonly: false,
disabled: false,
allowHalf: false,
scoreDetails: [
{ score: 1, description: '' },
{ score: 2, description: '' },
{ score: 3, description: '' },
{ score: 4, description: '' },
{ score: 5, description: '' },
],
}

container: HTMLElement | null = null

value: number = 0

get scoreItems() {
const res = []

for (let i = 1; i <= this.options.count; i++) {
const percent = i - this.value

const proportion =
this.value >= i
? 1
: percent >= 1
? 0
: Number.parseFloat((1 - percent).toFixed(1))

res.push({
score: i,
active: this.value >= i,
proportion,
width: `${proportion * 100}%`,
})
}

return res
}

constructor(opts: StarscoreOptions) {
this.options = Object.assign(this.options, opts)

this.clickListener = this.clickListener.bind(this)

this.initCSSVars()

this.render()
}

clickListener(e: MouseEvent) {
console.log(e)
}

registerListeners() {
this.removeListeners()

this.getScoreItemEl().forEach((el) => {
el.addEventListener('click', this.clickListener)
})
}

removeListeners() {
this.getScoreItemEl().forEach((el) => {
el.removeEventListener('click', this.clickListener)
})
}

getScoreItemEl() {
return this.getContainer().querySelectorAll(
`.${CONSTANTS.scoreItemClassName}`,
) as NodeListOf<HTMLElement>
}

render() {}
initCSSVars(): void {
css(this.getContainer(), {
'--starscore-size': safetyNumberToPx(this.options.size),
'--starscore-color': this.options.color,
'--starscore-void-color': this.options.voidColor,
'--starscore-disabled-color': this.options.disabledColor,
'--starscore-gutter': safetyNumberToPx(this.options.gutter),
})
}

generateRadioHTML(item: ScoreItemsRecord) {
return `
<div class="${CONSTANTS.scoreItemClassName}" data-score="${item.score}">
<span class="${CONSTANTS.scoreVoidIconClassName}">${VoidStarIcon}</span>
<span class="${CONSTANTS.scoreIconClassName}" style="width:${item.width}">${StarIcon}</span>
</div>
`
}

generateRadioGroupHTML() {
const radios = this.scoreItems.reduce((res, v) => {
res += `${this.generateRadioHTML(v)}`
return res
}, '')

return `
<div class="${CONSTANTS.scoreWrapperClassName}">${radios}</div>
`
}

render() {
const container = this.getContainer()

const content = `${this.generateRadioGroupHTML()}`

addClass(container, CONSTANTS.containerClassName)

container.innerHTML = content

this.registerListeners()
}

destory() {
this.removeListeners()
}

getContainer() {
if (this.container) return this.container

const el =
typeof this.options.container === 'string'
? (document.querySelector(`${this.options.container}`) as HTMLElement)
: this.options.container

if (el) {
this.container = el
}

return el
}
}

const createStarscore: CreateStarscore = (opts) => {
Expand Down

0 comments on commit 1cfd31c

Please sign in to comment.