Files
zeroone/src/renderer/src/components/config/values/ValueCard.vue
2024-05-27 15:50:29 +02:00

191 lines
6.3 KiB
Vue

<template>
<div class="overflow-hidden rounded-lg border border-zinc-800 bg-zinc-900/50">
<div class="p-4">
<span class="font-mono text-sm text-muted-foreground"
>Value{{ valueIndex ? ` ${valueIndex}` : '' }}:</span
>
<span class="float-end mx-2 w-4 cursor-grab">
<GripHorizontal class="value-handle mb-0.5 inline-block size-4 text-zinc-600" />
</span>
<div class="flex items-center gap-2">
<Popover v-model:open="open">
<PopoverTrigger as-child>
<Button
ref="comboboxButton"
variant="outline"
role="combobox"
:aria-expanded="open"
class="my-2 w-full min-w-0 justify-between"
>
<ScrambleText
class="overflow-hidden text-ellipsis text-nowrap"
:text="valueType?.label || 'Select a value type...'"
/>
<ChevronsUpDown class="ml-2 size-4 shrink-0 opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent class="p-0" :style="{ width: `${width + 35}px` }">
<Command>
<CommandInput class="h-9" placeholder="Search value types..." />
<CommandEmpty>
<ScrambleText scramble-on-mount text="No value types found." />
</CommandEmpty>
<CommandList>
<CommandGroup>
<CommandItem
v-for="(valueType, key) in valueTypeOptions"
:key="key"
:value="valueType"
@select="
() => {
inputValue = key
open = false
deviceStore.updateKnobValueParameter(valueIndex - 1, { type: key })
}
"
>
{{ valueType.label }}
<Check
:class="
cn('ml-auto h-4 w-4', inputValue === key ? 'opacity-100' : 'opacity-0')
"
/>
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
<Button
v-if="!confirmDelete"
class="aspect-square border border-zinc-800 bg-transparent p-1 text-muted-foreground hover:bg-orange-900 hover:text-zinc-100"
@click="confirmDelete = true"
><Trash2 class="size-4"
/></Button>
<template v-else>
<Button
class="aspect-square bg-orange-950 p-1 text-zinc-200 hover:bg-orange-900 hover:text-zinc-100"
@click="$emit('delete')"
><Check class="size-4"
/></Button>
<Button
class="aspect-square border border-zinc-800 bg-transparent p-1 text-zinc-200 hover:bg-zinc-800 hover:text-zinc-100"
@click="confirmDelete = false"
><X class="size-4"
/></Button>
</template>
</div>
<span class="font-mono text-sm text-muted-foreground">Conditions:</span>
<div class="flex gap-2 py-2">
<Button
v-for="(condition, key) in conditions"
:key="key"
class="font-heading flex flex-1 basis-1/4 items-center justify-center"
:class="{
'border border-zinc-200 bg-zinc-300': condition === true,
'border border-zinc-800 bg-transparent text-muted-foreground hover:border-zinc-700 hover:bg-zinc-800 hover:text-zinc-300':
condition === false
}"
@click="cycleCondition(key)"
>
<span class="mr-0.5">{{ key.toUpperCase() }}:</span>
<PanelBottomClose v-if="condition === true" class="size-4" />
<PanelBottomOpen v-else-if="condition === false" class="size-4" />
<HelpCircle v-else class="size-4" />
</Button>
</div>
</div>
<Separator />
<component
:is="
inputValue && valueTypeOptions[inputValue]?.component
? valueTypeOptions[inputValue]?.component
: WIP
"
:value="value"
@update="(updates) => deviceStore.updateKnobValueParameter(valueIndex - 1, updates)"
/>
</div>
</template>
<script setup lang="ts">
import WIP from '@renderer/components/WIP.vue'
import { Popover, PopoverTrigger, PopoverContent } from '@renderer/components/ui/popover'
import { Button } from '@renderer/components/ui/button'
import { Separator } from '@renderer/components/ui/separator'
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList
} from '@renderer/components/ui/command'
import { computed, ref } from 'vue'
import { cn } from '@renderer/lib/utils'
import ScrambleText from '@renderer/components/common/ScrambleText.vue'
import {
ChevronsUpDown,
Check,
GripHorizontal,
Trash2,
X,
PanelBottomClose,
PanelBottomOpen,
HelpCircle
} from 'lucide-vue-next'
import { useElementSize } from '@vueuse/core'
import TriggerActionsValue from '@renderer/components/config/values/TriggerActionsValue.vue'
import MidiValue from './MidiValue.vue'
import { useDeviceStore } from '@renderer/deviceStore'
const deviceStore = useDeviceStore()
defineEmits(['delete'])
const props = defineProps({
value: {
type: Object,
required: true
},
valueIndex: {
type: Number,
required: true
}
})
const valueTypeOptions = ref({
mouse: { label: 'Move or Scroll the Mouse', component: 'ControlMouseValue' },
gamepad: { label: 'Control a Gamepad Axis', component: 'ControlGamepadValue' },
midi: { label: 'Control a MIDI CC Value', component: MidiValue },
action: { label: 'Trigger Actions on Rotation', component: TriggerActionsValue }
})
const valueType = computed(() => {
if (inputValue.value in valueTypeOptions.value) {
return valueTypeOptions.value[inputValue.value]
}
return null
})
const conditions = ref({
a: true,
b: false,
c: false,
d: false
})
const cycleCondition = (key: string) => {
const condition = conditions.value[key]
if (condition === true) conditions.value[key] = false
else conditions.value[key] = true
}
const comboboxButton = ref(null)
const { width } = useElementSize(comboboxButton)
const open = ref(false)
const inputValue = ref(props.value.type || null)
const confirmDelete = ref(false)
</script>