Skip to content

Commit

Permalink
feat: split-circle
Browse files Browse the repository at this point in the history
  • Loading branch information
byronogis committed Sep 17, 2023
1 parent 85aa709 commit d211187
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 67 deletions.
74 changes: 17 additions & 57 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,30 @@
# web-component-starter
# split-circle

A starter kit for building web components with [lit](https://lit.dev/).
[![NPM version](https://img.shields.io/npm/v/pkg-name?color=a1b858&label=)](https://www.npmjs.com/package/split-circle)

## Start
> Split a circle into a number of equal parts
> web component, so you can use it in any framework
### Clone with degit
## API

```bash
npx degit byronogis/web-component-starter my-component
cd my-component
pnpm i
```
### Props

### Github Template
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `parts` | `array` | `[1,2,3,4,5,6,7,8]` | data of circle, used in show and event |
| `radius` | `string` | `100px` | the radius of circle |

[Create a repo from this template on GitHub.](https://github.com/byronogis/web-component-starter/generate)
### Events

## Checklist
| Name | Description |
| --- | --- |
| `partclick` | click event, return a CustomEvent Object, you can find part data in `event.detail.part` |

- Change `web-component-starter`, `WebComponentStarter` with your component name.
- Rename `packages/core/src/components/WebComponentStarter.js` with your component name.
- Change the author name in LICENSE.
- Clean up the READMEs.
## Demo

## Repo Usage
### Vue

### Multi-Component

Add more components by creating new files in `packages/core/src/components` and aggregating them in `packages/core/src/components/index.js`.

### Development

```bash
pnpm dev
```

### Build

```bash
pnpm build
```

## Component Usage

### define all components

```js
import { defineWebComponents } from 'web-component-starter'

defineWebComponents()
```

### or define a single component

```js
import { defineWebComponent } from 'web-component-starter'
import { WebComponentStarter } from 'web-component-starter/components'

defineWebComponent('web-component-starter', WebComponentStarter)
```

### use in html

```html
<web-component-starter></web-component-starter>
```
[playground-vue](./playground//vue/src/App.vue)

## License

Expand Down
49 changes: 42 additions & 7 deletions packages/core/src/components/SplitCircle.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,60 @@
import { LitElement, css, html } from 'lit'
import { LitElement, html } from 'lit'
import { styleMap } from 'lit/directives/style-map.js'
import SplitCircleStyle from './SplitCircleStyle'

export default class SplitCircle extends LitElement {
static properties = {
name: {},
parts: { type: Array },
radius: { type: String },
styles: {},
}

// Define scoped styles right with your component, in plain CSS
static styles = css`
:host {
color: blue;
}
`
static styles = [
SplitCircleStyle,
]

constructor() {
super()
// Declare reactive properties
this.name = 'World'
this.parts = Array.from({ length: 8 }, (_, i) => i + 1)
this.radius = '100px'
this.styles = {}
}

// Render the UI as a function of component state
render() {
return html`<p>Hello, ${this.name}!</p>`
this.styles = {
'--radius': this.radius,
'--parts': this.parts.length,
}

return html`
<ul class="circle" style=${styleMap(this.styles)}>
${this.parts.map((part, index) => html`
<li
class="circle-part"
data-part=${JSON.stringify(part)}
style=${styleMap({ '--part': index + 1 })}
@click=${this._dispatchEvent}
>
<div class="circle-part-inner_wrapper">
<div class="circle-part-inner">
<slot name=${index}>${part}</slot>
</div>
</div>
</li>
`)}
</ul>
`
}

_dispatchEvent(e) {
if (e.currentTarget?.classList.contains('circle-part')) {
const part = JSON.parse(e.currentTarget.dataset.part)
this.dispatchEvent(new CustomEvent('partclick', { detail: { part } }))
}
}
}
49 changes: 49 additions & 0 deletions packages/core/src/components/SplitCircleStyle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { css } from 'lit'

export default css`
.circle {
--part-degree: calc(360deg / var(--parts));
overflow: hidden;
position: relative;
margin: 0;
padding: 0;
border-radius: 50%;
width: calc(var(--radius) * 2);
height: calc(var(--radius) * 2);
background-color: #ccc;
transform: rotate(v-bind(rotate));
}
.circle-part {
overflow: hidden;
position: absolute;
top: -50%;
left: -50%;
width: 100%;
height: 100%;
list-style: none;
transform: rotate(calc(var(--part-degree) * calc(var(--part) - 1)))
skew(calc(90deg - var(--part-degree))) ;
transform-origin: right bottom;
}
.circle-part:hover {
background-color: #42b883;
}
.circle-part-inner_wrapper {
display: flex;
justify-content: center;
align-items: flex-end;
width: 100%;
height: 100%;
transform: skew(calc(var(--part-degree) - 90deg))
rotate(calc(calc(var(--part-degree) / 2) - 90deg))
translate(50%);
transform-origin: right bottom;
}
.circle-part-inner {
height: 50%;
}
`
38 changes: 37 additions & 1 deletion packages/docs/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
<script setup>
import { computed, ref } from 'vue'
const partsLength = ref(3)
const parts = computed(() => {
return Array.from({ length: partsLength.value }, (_, i) => i + 1)
})
function handlePartclick(e) {
console.log(e.detail)
}
</script>

<template>
<split-circle />
<div class="playground-vue">
<split-circle :parts="parts" @partclick="handlePartclick">
<template v-for="(part, index) in parts" :key="index">
<span :slot="index">{{ part }}</span>
</template>
</split-circle>

<input v-model="partsLength" class="playground-vue-input" type="number" min="3">
</div>
</template>

<style scoped>
.playground-vue {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
.playground-vue-input {
margin-top: 20px;
text-align: center;
}
</style>
6 changes: 5 additions & 1 deletion playground/vanilla/index.html
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>playground-vanilla</title>
</head>

<body>
<split-circle></split-circle>
<div id="app"></div>

<script type="module" src="/src/main.js"></script>
</body>

</html>
13 changes: 13 additions & 0 deletions playground/vanilla/src/main.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
import { defineWebComponents } from 'split-circle'

defineWebComponents()

const parts = Array.from({ length: 5 }, (_, i) => i + 1)
const radius = '150px'

const splitCircle = document.createElement('split-circle')
splitCircle.setAttribute('parts', JSON.stringify(parts))
splitCircle.setAttribute('radius', radius)
splitCircle.addEventListener('partclick', (e) => {
alert(`partclick: ${JSON.stringify(e.detail)}`)
})

const app = document.querySelector('#app')
app.appendChild(splitCircle)
38 changes: 37 additions & 1 deletion playground/vue/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,3 +1,39 @@
<script setup>
import { computed, ref } from 'vue'
const partsLength = ref(3)
const parts = computed(() => {
return Array.from({ length: partsLength.value }, (_, i) => i + 1)
})
function handlePartclick(e) {
console.log(e.detail)
}
</script>

<template>
<split-circle />
<div class="playground-vue">
<split-circle :parts="parts" @partclick="handlePartclick">
<template v-for="(part, index) in parts" :key="index">
<span :slot="index">{{ part }}</span>
</template>
</split-circle>

<input v-model="partsLength" class="playground-vue-input" type="number" min="3">
</div>
</template>

<style scoped>
.playground-vue {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
}
.playground-vue-input {
margin-top: 20px;
text-align: center;
}
</style>

0 comments on commit d211187

Please sign in to comment.