You've already forked obsidian-visualiser
Finish TrainingViewer and rework character editor style
This commit is contained in:
@@ -1,28 +1,120 @@
|
||||
<script setup lang="ts">
|
||||
import { clamp } from '#shared/general.util';
|
||||
import { MAIN_STATS, mainStatTexts, type CharacterConfig } from '~/types/character';
|
||||
import PreviewA from './prose/PreviewA.vue';
|
||||
|
||||
const { config } = defineProps<{
|
||||
config: CharacterConfig
|
||||
config: CharacterConfig,
|
||||
}>();
|
||||
|
||||
const position = ref(0);
|
||||
const dragger = useTemplateRef<HTMLElement | null>('dragger'), items = useTemplateRef<HTMLElement[] | null>('items');
|
||||
const position = ref(0), id = ref<number>(0);
|
||||
const dragging = ref(false), offset = ref(0);
|
||||
|
||||
const dragend = () => {
|
||||
window.removeEventListener('mousemove', dragmove);
|
||||
window.removeEventListener('mouseup', dragend);
|
||||
|
||||
dragging.value = false;
|
||||
};
|
||||
const dragmove = (e: MouseEvent) => {
|
||||
const box = dragger.value!.getBoundingClientRect();
|
||||
offset.value = clamp(offset.value - e.movementX, 0, (320+32+2) * 16);
|
||||
if(dragger.value) dragger.value.scrollLeft = offset.value;
|
||||
};
|
||||
const dragstart = () => {
|
||||
window.addEventListener('mousemove', dragmove);
|
||||
window.addEventListener('mouseup', dragend);
|
||||
|
||||
dragging.value = true;
|
||||
};
|
||||
const wheel = (e: WheelEvent) => {
|
||||
if(dragging.value) return;
|
||||
|
||||
const box = dragger.value!.getBoundingClientRect();
|
||||
offset.value = clamp(offset.value + e.deltaY, 0, (320+32+2) * 16);
|
||||
if(dragger.value) dragger.value.scrollLeft = offset.value;
|
||||
}
|
||||
onMounted(() => {
|
||||
|
||||
dragger.value?.addEventListener('mousedown', dragstart);
|
||||
dragger.value?.addEventListener('wheel', wheel);
|
||||
|
||||
transition(1, 0);
|
||||
});
|
||||
onUnmounted(() => {
|
||||
dragger.value?.removeEventListener('mousedown', dragstart);
|
||||
dragger.value?.removeEventListener('wheel', wheel);
|
||||
});
|
||||
function transition(from: number, to: number)
|
||||
{
|
||||
if(!items.value || from === to)
|
||||
return;
|
||||
|
||||
position.value = to;
|
||||
items.value![to].style.visibility = 'visible';
|
||||
items.value![from].style.opacity = '0';
|
||||
items.value![to].style.opacity = '1';
|
||||
|
||||
for(let i = 0; i < MAIN_STATS.length; i++)
|
||||
{
|
||||
if(i < to)
|
||||
items.value![i].style.top = `-25%`;
|
||||
else
|
||||
items.value![i].style.top = `25%`;
|
||||
}
|
||||
items.value![to].style.top = `0%`;
|
||||
|
||||
clearTimeout(id.value);
|
||||
//@ts-ignore
|
||||
id.value = setTimeout(() => {
|
||||
items.value![from].style.visibility = 'hidden';
|
||||
}, 200);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<TabsRoot class="flex flex-1 flex-row justify-start items-stretch w-full" :default-value="MAIN_STATS[0]">
|
||||
<TabsList class="flex flex-col gap-3 relative">
|
||||
<TabsTrigger v-for="(stat, i) of MAIN_STATS" :value="stat" class="block w-2.5 h-2.5 m-px outline outline-1 outline-transparent hover:outline-light-70 dark:hover:outline-dark-70 rounded-full bg-light-40 dark:bg-dark-40 cursor-pointer" @click="position = i"></TabsTrigger>
|
||||
<!-- <TabsIndicator class="absolute left-0 h-[3px] bottom-0 w-[--radix-tabs-indicator-size] translate-x-[--radix-tabs-indicator-position] transition-[width,transform] duration-300 bg-accent-blue"></TabsIndicator> -->
|
||||
<!-- <template>
|
||||
<div class="flex flex-1 flex-row justify-start w-full max-h-full h-full overflow-hidden gap-8 relative">
|
||||
<div class="flex flex-col gap-3 relative items-center">
|
||||
<span v-for="(stat, i) of MAIN_STATS" :value="stat" class="block w-2.5 h-2.5 m-px outline outline-1 outline-transparent
|
||||
hover:outline-light-70 dark:hover:outline-dark-70 rounded-full bg-light-40 dark:bg-dark-40 cursor-pointer" @click="() => transition(position, i)"></span>
|
||||
<span :style="{ 'top': position * 1.5 + 'em' }" :data-text="mainStatTexts[MAIN_STATS[position]]" class="rounded-full w-3 h-3 bg-accent-blue absolute transition-[top]
|
||||
after:content-[attr(data-text)] after:absolute after:-top-2 after:left-4 after:p-px after:bg-light-0 dark:after:bg-dark-0"></span>
|
||||
</TabsList>
|
||||
<TabsContent v-for="(stat) of MAIN_STATS" :value="stat" class="flex-1">
|
||||
<div class="flex flex-row overflow-x-auto w-full flex-nowrap gap-4">
|
||||
<div class="w-96 flex flex-col gap-4 justify-between" v-for="(level) of config.training[stat]">
|
||||
<div class="border border-light-35 dark:border-dark-35 px-3 py-1" v-for="(option) of level"><MarkdownRenderer :proses="{ 'a': PreviewA }" :content="option.description.map(e => e.text).join('\n')" /></div>
|
||||
</div>
|
||||
<div class="flex flex-1 flex-col justify-center relative cursor-grab" ref="dragger" :class="{ 'cursor-grabbing': dragging }">
|
||||
<div v-for="(stat) of MAIN_STATS" :value="stat" class="flex-1 transition-[opacity,transform] items-center hidden absolute" ref="items" :style="{ 'left': `${-offset}%` }">
|
||||
<div class="flex flex-row overflow-x-auto items-center w-full gap-4">
|
||||
<div class="w-96 flex flex-col gap-4 justify-between" v-for="(level, i) of config.training[stat]">
|
||||
<template v-for="(option) of level">
|
||||
<slot :stat="stat" :level="i" :option="option"></slot>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</TabsContent>
|
||||
</TabsRoot>
|
||||
</div>
|
||||
</div>
|
||||
</template> -->
|
||||
|
||||
<template>
|
||||
<div class="w-full h-full flex gap-8 max-w-full relative">
|
||||
<div class="flex flex-col gap-3 relative items-center">
|
||||
<span v-for="(stat, i) of MAIN_STATS" :value="stat" class="block w-2.5 h-2.5 m-px outline outline-1 outline-transparent
|
||||
hover:outline-light-70 dark:hover:outline-dark-70 rounded-full bg-light-40 dark:bg-dark-40 cursor-pointer" @click="() => transition(position, i)"></span>
|
||||
<span :style="{ 'top': position * 1.5 + 'em' }" :data-text="mainStatTexts[MAIN_STATS[position]]" class="rounded-full w-3 h-3 bg-accent-blue absolute transition-[top]
|
||||
after:content-[attr(data-text)] after:absolute after:-top-2 after:left-4 after:p-px after:bg-light-0 dark:after:bg-dark-0"></span>
|
||||
</div>
|
||||
<div class="absolute top-0 left-24 z-10">
|
||||
<slot name="addin" :stat="MAIN_STATS[position]"></slot>
|
||||
</div>
|
||||
<div ref="dragger" class="flex flex-col gap-4 pb-4 cursor-grab active:cursor-grabbing select-none overflow-hidden h-full w-full relative">
|
||||
<div v-for="(stat, name) in config.training" class="flex flex-1 gap-4 items-center absolute h-full z-0" ref="items" :style="{ 'opacity': '0', 'visibility': 'hidden', 'transition': 'opacity 200ms ease-in-out, top 200ms ease-in-out' }">
|
||||
<div v-for="(options, level) in stat" class="flex-shrink-0 w-80">
|
||||
<div class="space-y-2" @mousedown.stop>
|
||||
<template v-for="(option, i) in options">
|
||||
<slot :stat="name" :level="level" :index="i" :option="option"></slot>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user