Public
Edited
Aug 28, 2023
Paused
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
filteredPopularitiesID = popularities.indexOf(filteredPopularities[0])
Insert cell
Insert cell
Insert cell
productsSupplyTrends = Object.fromEntries(productsSupplyTrendsTable)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
VueCalculator = (old)=>({
components: {
VueCraftPanel,
VueCycleList,
VueCycleItem,
VueWorkshopList,
VueWorkshopCrafting
},
template: appTemplate,
setup() {
const {ref,reactive,shallowReactive,provide,computed,watch,onMounted} = Vue;
const el = ref(null);
const cellData = {
cycles: null, // debug
selected: [],
activeCycle: 0,
activeWorkshop: 0
};

const cycles = reactive(
Array(7).fill().map(() => useWorkshopCycle())
);
for (let i = 1; i < cycles.length; i++) {
cycles[i].previous = cycles[i - 1];
cycles[i].weekday = i;
}
provide("cycles", cycles);
const updateCell = () => {
cellData.cycles = cycles
for (let i = 0; i < 7; i++){
for (let j = 0; j < 3; j++){
selections[i][j] = cycles[i].current[j]
}
}
updateInput(el.value.parentElement, cellData);
};
onMounted(() => {
for (let i = 0; i < 7; i++){
for (let j = 0; j < 3; j++){
cycles[i].current[j] = selections[i][j]
}
}
updateCell();
});

const editState = shallowReactive({
activeElement: null,
activeCycle: 0,
activeWorkshop: 0,
selected: shallowReactive([])
});
provide("editState", editState);

const targetPos = ref({
x: 0,
y: 0,
toLeft: false
});

watch(
[editState.selected, () => [editState.activeCycle, editState.activeWorkshop], cycles],
() => {
cellData.selected = editState.selected;
cellData.activeCycle = editState.activeCycle;
cellData.activeWorkshop = editState.activeWorkshop;
updateCell();
}
);

watch(
() => editState.activeElement,
(newVal, oldVal) => {
if (!newVal) return;
const rootBounding = el.value.getBoundingClientRect();
const targetBounding = newVal.getBoundingClientRect();
const width = document.body.clientWidth;
const toLeft = width - targetBounding.right < targetBounding.left;
let x = toLeft
? targetBounding.left - rootBounding.left
: targetBounding.right - rootBounding.left;
targetPos.value = {
toLeft,
x,
y: targetBounding.top - rootBounding.top
};
}
);

const restDayNotEnough = computed(() => {});

return {
el,
updateCell,
cycles,
editState,
targetPos
};
}
})
Insert cell
VueCraftPanel = ({
template: VueCraftPanelTemp,
setup(){
const { ref, computed, reactive, inject, toRef, readonly, watch } = Vue;
const cycles = inject('cycles', Array(7).fill(null))
const editState = inject('editState', null)
const prods = readonly(products)
const onClickCrafting = (product)=>{
if (!canAdd(product)) return
editState.selected =[...editState.selected, product]
cycles[editState.activeCycle].current[editState.activeWorkshop] = [...editState.selected]
if(Utils.getCombinationHour(cycles[editState.activeCycle].current[editState.activeWorkshop]) >= 24){
editState.activeElement = null
}
}
const sameThemeWithLast = (next)=>{
if (editState.selected.length === 0) return false
return canAdd(next)
&& editState.selected[editState.selected.length-1] !== next
&& editState.selected[editState.selected.length-1].themes.some(it=>next.themes.includes(it))
}
const canAdd = (next)=>{
return editState.selected.map(it=>it.duration).reduce((a,b)=>a+b,0) + next.duration<=24
}
const onClickClose = ()=>{
editState.activeElement = null
}
return {
prods,
onClickCrafting,
sameThemeWithLast,
canAdd,
onClickClose,
}
}
})
Insert cell
<template>
<!-- VueCraftPanel -->
<div class="p-2 w-550px h-60 flex flex-col overflow-hidden">
<div class="grid grid-cols-4 flex-1 overflow-auto">
<div v-for="p in prods"
class="col-span-1 flex flex-row"
:class="[ sameThemeWithLast(p) ? 'bg-green' : '']"
:title="p.name" @click="onClickCrafting(p)">
<div
class="flex-1 flex flex-row items-center p-1"
:class="[canAdd(p) ? 'hover:bg-dark/20 cursor-pointer' : 'opacity-30']"
>
<img class="w-8 h-8" :src="p.icon">
<span class="mx-2 text-xs" >{{p.name.replace('Isleworks ','')}}</span>
</div>
</div>
</div>
<div class="flex-0 text-center m-2 border rounded hover:bg-light-300 active:bg-light-700 cursor-pointer" @click="onClickClose">Close</div
</div>
</template>
Insert cell
VueCycleList = ({
components: { VueCycleItem },
template: VueCycleListTemp,
setup(){
const { inject } = Vue
const cycles = inject('cycles', Array(7).fill(null))
return {
cycles,
}
}
})
Insert cell
<template>
<!-- VueCycleList -->
<div class="grid grid-cols-7 divide-x-1">
<vue-cycle-item class="col-span-1 text-center" v-for="k, i in cycles" :day="i" :key="i">Cycle {{i+1}}</vue-cycle-item>
</div>
</template>
Insert cell
VueCycleItem = ({
components: { VueWorkshopList },
template: VueCycleItemTemp,
props: ['day'],
setup(props){
const { ref, computed, reactive, inject, toRef } = Vue;
const cycles = inject('cycles', Array(7).fill(null))
const cycle = toRef(cycles, props.day)
const editState = inject('editState')
const showRest = computed(()=>{
return cycle.value?.current.every(it=> it.length === 0 ) && (editState.activeElement === null || editState.activeCycle !== props.day)
})
const isHovering = ref(false)
return {
showRest,
cycle,
isHovering
}
}
})
Insert cell
<template>
<!-- VueCycleItem -->
<div class="flex flex-col abc">
<slot>Day</slot>
<div ref="el" class="relative flex flex-col flex-1 ml-2" @mouseenter="isHovering = true" @mouseleave="isHovering = false">
<!-- Measure -->
<div class="absolute top-0 bottom-0 right-full grid grid-rows-24">
<div class="block row-span-1 w-2 last:border-b-1" v-for="i in 24" :class="[i!==1 && (i-1)%4===0? 'border-t-2': 'border-t-1']"></div>
</div>
<!-- Combinations -->
<vue-workshop-list class="flex-1 mx-1" :day="$props.day"></vue-workshop-list>
<!-- Rest Overlay -->
<div v-if="showRest" v-show="!isHovering" class="absolute inset-0 mx-1 bg-white border-dashed rounded-xl border-2"
>
<div class="text-2xl font-sans h-full flex justify-center items-center select-none">
<span>Rest</span>
</div>
</div>
</div>
<!-- profit -->
<div class="grid grid-cols-3 ml-3 mr-1 text-sm">
<div v-for="v, i in cycle.profitByWorkshop" :key="i">
{{v}}
</div>
</div>
<div class="text-lg ml-2">{{cycle.profit}}</div>
</div>
</template>
Insert cell
VueWorkshopList = ({
components: { VueWorkshopCrafting },
template: VueWorkshopListTemp,
props: ['day'],
setup(props){
const { ref, computed, reactive, inject, toRef } = Vue;
const cycles = inject('cycles', Array(7).fill(null))
const cycle = toRef(cycles, props.day)
const combinations = computed(()=>{
return cycle.value.current
})
const editState = inject('editState', null)
const onNewCrafting = (el, idx)=>{
if(!editState) return
if(editState.activeElement === el){
editState.activeElement = null
} else {
editState.activeElement = el
}
editState.activeCycle = props.day
editState.activeWorkshop = idx
editState.selected = []
}
const isSelfActive = (workshop)=>{
return editState.activeElement !== null && editState.activeCycle === props.day && editState.activeWorkshop === workshop
}
return {
cycle,
combinations,
onNewCrafting,
isSelfActive,
}
}
})
Insert cell
<template>
<!-- VueWorkshopList -->
<div class="divide-x-1 divide-y-0 divide-dotted grid grid-cols-3">
<div class="col-span-1 grid" v-for="idx in 3" :key="idx" :class="isSelfActive(idx-1)?'bg-green-300':''">
<vue-workshop-crafting v-if="combinations[idx-1].length > 0" :day="$props.day" :workshop="idx-1"></vue-workshop-crafting>
<div v-else class="flex flex-col children:invisible children:hover:visible">
<div class="relative flex-1 grid mx-1 border-dotted border-1 rounded cursor-pointer" @click="onNewCrafting($event.currentTarget, idx-1)">
<div class="my-auto text-2xl font-bold select-none">+</div>
</div>
</div>
</div>
</div>
</template>
Insert cell
VueWorkshopCrafting = ({
template: VueWorkshopCraftingTemp,
props: ['day', 'workshop'],
setup(props){
const { ref, computed, reactive, inject, toRef } = Vue;
const cycles = inject('cycles', Array(7).fill(null))
const editState = inject('editState', null)
const cycle = toRef(cycles, props.day)
const combination = computed(()=>{
return cycle.value?.current[props.workshop]
})
const root = ref(null)
const onClickEdit = ()=>{
if(!editState) return
if(editState.activeElement === root.value){
editState.activeElement = null
} else {
editState.activeElement = root.value
}
editState.activeCycle = props.day
editState.activeWorkshop = props.workshop
editState.selected = [...cycle.value.current[props.workshop]]
}
const canEdit = computed(()=>{
return editState.activeElement === null || (editState.activeCycle !== props.day && editState.activeWorkshop !== props.workshop)
})
const onClickDelete = ()=>{
cycle.value.current[props.workshop] = []
editState.activeElement = null
}
const onClickBack = ()=>{
cycle.value.current[props.workshop] = cycle.value.current[props.workshop].slice(0, cycle.value.current[props.workshop].length-1)
editState.selected = [...cycle.value.current[props.workshop]]
}
const canBack = computed(()=>{
return cycle.value.current[props.workshop].length > 0
})
const onClickCopyLeft = ()=>{
if (props.workshop-1 < 0) return
cycle.value.current[props.workshop-1] = [...cycle.value.current[props.workshop]]
}
const onClickCopyRight = ()=>{
if (props.workshop+1 > 2) return
cycle.value.current[props.workshop+1] = [...cycle.value.current[props.workshop]]
}
const canCopyLeft = computed(()=>{
return props.workshop > 0
})
const canCopyRight = computed(()=>{
return props.workshop < 2
})
return {
combination,
onClickDelete,
onClickBack,
canBack,
onClickCopyLeft,
onClickCopyRight,
canCopyLeft,
canCopyRight,
onClickEdit,
canEdit,
root,
}
}
})
Insert cell
<template>
<!-- VueWorkshopCrafting -->
<div ref="root" class="grid grid-rows-24 gap-y-1 px-1 relative group">
<template v-for="product, idx in combination" :key="idx">
<div class="border rounded p-px" :class="['row-span-'+ product.duration]">
<img class="w-90%" :src="product.icon" :title="product.name">
</div>
</template>
<div class="absolute inset-0 flex gap-4 flex-col place-content-center invisible group-hover:visible
bg-white/50
backdrop-filter backdrop-blur-sm">
<div v-if="canBack" class="bg-orange rounded select-none cursor-pointer hover:bg-orange-300 active:bg-orange-700" @click="onClickBack">Back</div>
<div v-if="canEdit" class="bg-light border rounded select-none cursor-pointer hover:bg-light-300 active:bg-light-700" @click="onClickEdit">Edit</div>
<div v-if="canCopyLeft" class="bg-light border rounded select-none cursor-pointer hover:bg-light-300 active:bg-light-700 overflow-hidden" @click="onClickCopyLeft"> << </div>
<div v-if="canCopyRight" class="bg-light border rounded select-none cursor-pointer hover:bg-light-300 active:bg-light-700 overflow-hidden" @click="onClickCopyRight"> >> </div>
<div class="bg-red rounded select-none cursor-pointer hover:bg-red-300 active:bg-red-700" @click="onClickDelete">Clear</div>
</div>
</div>
</template>
Insert cell
Insert cell
Insert cell
Insert cell
{ // debug
const cycle = useWorkshopCycle(null, maxTension);
// cycle.current[0] = combinations[0]
// cycle.current[1] = combinations[0]
// cycle.current[2] = combinations[0]
const cycle2 = useWorkshopCycle(cycle, maxTension)
cycle2.current[0] = combinations[0]
cycle2.current[1] = combinations[0]
cycle2.current[2] = combinations[0]
const cycle3 = useWorkshopCycle(cycle2, maxTension)
// cycle3.current[0] = combinations[0]
// cycle3.current[1] = combinations[0]
// cycle3.current[2] = combinations[0]
const cycle4 = useWorkshopCycle(cycle3, maxTension)
// cycle4.current[0] = combinations[0]
// cycle4.current[1] = combinations[0]
// cycle4.current[2] = combinations[0]
const cycle5 = useWorkshopCycle(cycle4, maxTension)
// cycle5.current[0] = combinations[0]
// cycle5.current[1] = combinations[0]
// cycle5.current[2] = combinations[0]
// return cycle.current
let sum = Utils.calcValue(cycle2.current[0][0], 16, 0)+2*Utils.calcValue(cycle2.current[0][1], 10, 3)+2*Utils.calcValue(cycle2.current[0][2], 13, 6)
const {reactive, toRaw} = Vue;
return [reactive(cycle2), sum]
// return [cycle.totalProfit.value, cycle2.totalProfit.value, cycle3.totalProfit.value, cycle4.totalProfit.value, cycle5.totalProfit.value]
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import { Vue, VueUse } from "@unluckyninja/vue"
Insert cell
import {createVueApp} from "53b92343f9084d61"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more