coomdev
2 years ago
5 changed files with 171 additions and 3 deletions
@ -0,0 +1,74 @@ |
|||
<script context="module"> |
|||
export const DIAL = {}; |
|||
</script> |
|||
|
|||
<script lang="ts"> |
|||
import { |
|||
setContext, |
|||
onDestroy, |
|||
createEventDispatcher, |
|||
afterUpdate, |
|||
} from "svelte"; |
|||
import type { NailState } from "./Nail.svelte"; |
|||
import type { Writable } from "svelte/store"; |
|||
|
|||
let states: Writable<NailState>[] = []; |
|||
|
|||
let visible = false; |
|||
|
|||
export let dist = 82; |
|||
|
|||
export let angleRange = [0, 360]; |
|||
|
|||
let self; |
|||
|
|||
const updateNails = () => { |
|||
const pi = (angleRange[1] - angleRange[0]) / states.length; |
|||
for (let i = 0; i < states.length; ++i) { |
|||
states[i].set({ |
|||
angle: pi * i + angleRange[0], |
|||
length: dist, |
|||
visible, |
|||
}); |
|||
} |
|||
}; |
|||
|
|||
setContext(DIAL, { |
|||
registerNail(nail: Writable<NailState>) { |
|||
states.push(nail); |
|||
updateNails(); |
|||
onDestroy(() => { |
|||
const i = states.indexOf(nail); |
|||
console.log("destroy at ", i); |
|||
states.splice(i, 1); |
|||
updateNails(); |
|||
}); |
|||
}, |
|||
}); |
|||
|
|||
afterUpdate(() => { |
|||
updateNails(); |
|||
}); |
|||
</script> |
|||
|
|||
<div |
|||
bind:this={self} |
|||
on:click={() => { |
|||
visible = !visible; |
|||
updateNails(); |
|||
}} |
|||
class="dial" |
|||
> |
|||
<slot /> |
|||
</div> |
|||
|
|||
<style> |
|||
.dial { |
|||
padding: 10px; |
|||
border: 1px solid; |
|||
border-radius: 99px; |
|||
width: 25px; |
|||
height: 25px; |
|||
cursor: pointer; |
|||
} |
|||
</style> |
@ -0,0 +1,28 @@ |
|||
<script lang="ts"> |
|||
import type { EmbeddedFile } from "../main"; |
|||
import { createEventDispatcher } from "svelte"; |
|||
import Embedding from "./Embedding.svelte"; |
|||
import Dial from "./Dial.svelte"; |
|||
import Nail from "./Nail.svelte"; |
|||
|
|||
export const dispatch = createEventDispatcher(); |
|||
|
|||
export let files: EmbeddedFile[]; |
|||
export let id: string = ""; |
|||
|
|||
let children: { [k in number]: Embedding } = {}; |
|||
export async function bepis(ev: MouseEvent) { |
|||
for (let child of Object.values(children)) child.bepis(ev); |
|||
} |
|||
</script> |
|||
|
|||
<Dial dist={220}> |
|||
{#each files as file, i} |
|||
<Nail> |
|||
<Embedding on:fileinfo bind:this={children[i]} {id} {file} /> |
|||
</Nail> |
|||
{/each} |
|||
</Dial> |
|||
|
|||
<style scoped> |
|||
</style> |
@ -0,0 +1,55 @@ |
|||
<script lang="ts" context="module"> |
|||
export type NailState = { |
|||
angle: number; |
|||
length: number; |
|||
visible: boolean; |
|||
}; |
|||
</script> |
|||
|
|||
<script lang="ts"> |
|||
import { getContext } from "svelte"; |
|||
import { DIAL } from "./Dial.svelte"; |
|||
import { writable } from "svelte/store"; |
|||
import { elasticOut, elasticIn } from "svelte/easing"; |
|||
|
|||
const state = writable<NailState>({ |
|||
angle: 0, |
|||
length: 0, |
|||
visible: false, |
|||
}); |
|||
|
|||
function slide(node: any, { delay = 0, duration = 1000 }) { |
|||
return { |
|||
delay, |
|||
easing: elasticOut, |
|||
duration, |
|||
css: (t: number) => |
|||
`transform: rotate(${$state.angle}deg) translateX(${ |
|||
t * $state.length |
|||
}px) scale(${t}); opacity: ${t}`, |
|||
}; |
|||
} |
|||
|
|||
const ctx: any = getContext(DIAL); |
|||
if (ctx) ctx.registerNail(state); |
|||
</script> |
|||
|
|||
{#if $state.visible} |
|||
<div |
|||
transition:slide |
|||
style="transform: rotate({$state.angle}deg) translateX({$state.length}px);" |
|||
class="rel" |
|||
> |
|||
<div style="transform: rotate({-$state.angle}deg)" class="abs"> |
|||
<slot /> |
|||
</div> |
|||
</div> |
|||
{/if} |
|||
|
|||
<style> |
|||
.rel { |
|||
} |
|||
|
|||
.abs { |
|||
} |
|||
</style> |
@ -0,0 +1,8 @@ |
|||
<script lang="ts"> |
|||
|
|||
</script> |
|||
|
|||
<div></div> |
|||
|
|||
<style> |
|||
</style> |
Loading…
Reference in new issue