ADD: KnobConfig & KeyConfig

This commit is contained in:
Robert Kossessa
2024-02-04 15:21:02 +01:00
parent d843f7c878
commit 7f85f9986e
8 changed files with 161 additions and 73 deletions

View File

@@ -4,12 +4,9 @@ import DevicePreview from '@/components/device/DevicePreview.vue'
import ConfigPane from '@/components/config/ConfigPane.vue'
import Navbar from '@/components/Navbar.vue'
import { useStore } from '@/store'
import { ref } from 'vue'
const store = useStore()
const currentConfigPage = ref(0)
store.fetchProfiles()
</script>
@@ -20,10 +17,8 @@ store.fetchProfiles()
<ProfileManager
class="basis-1/3 min-w-60 flex-1 flex flex-col border-solid border-0 border-r bg-zinc-900 bg-opacity-50" />
<DevicePreview
class="basis-1/3 flex-col flex-1 flex border-solid border-0 border-r"
@select="currentConfigPage = (currentConfigPage+1)%4" />
class="basis-1/3 flex-col flex-1 flex border-solid border-0 border-r" />
<ConfigPane
v-model="currentConfigPage"
class="flex-1 basis-2/5 flex flex-col border-solid border-0 border-r bg-zinc-900 bg-opacity-50" />
</div>
</main>

View File

@@ -1,61 +1,12 @@
<template>
<div>
<div v-if="showTabs" class="flex">
<!-- TODO: Remove later if not needed -->
<div v-for="(option, index) in configPageOptions" :key="index" class="flex flex-1 items-center">
<button
class="flex-1 h-12 items-center text-center group px-3 font-heading"
:class="index===currentPage ? 'bg-zinc-900': 'hover:bg-zinc-800 text-zinc-200'"
@click="currentPage = index">
{{ $t(option.titleKey) }}
</button>
<div
class="group-hover:h-full"
:class="index===currentPage || index+1===currentPage ? 'h-full' : 'h-7'">
<Separator orientation="vertical" />
</div>
</div>
</div>
<div class="grow overflow-y-auto">
<component :is="configPageOptions[currentPage].component" />
<component :is="store.currentConfigComponent" />
</div>
</div>
</template>
<script setup>
import LEDsConfig from '@/components/config/pages/LEDsConfig.vue'
import ProfileConfig from '@/components/config/pages/ProfileConfig.vue'
import MappingConfig from '@/components/config/pages/MappingConfig.vue'
import HapticConfig from '@/components/config/pages/HapticConfig.vue'
import { Separator } from '@/components/ui/separator'
import { useStore } from '@/store'
defineProps({
showTabs: {
type: Boolean,
default: false,
},
})
const currentPage = defineModel({
type: Number,
default: 0,
})
const configPageOptions = [
{
titleKey: 'config_options.profile_settings.title',
component: ProfileConfig,
},
{
titleKey: 'config_options.feedback_designer.title',
component: HapticConfig,
},
{
titleKey: 'config_options.mapping_configuration.title',
component: MappingConfig,
},
{
titleKey: 'config_options.light_designer.title',
component: LEDsConfig,
},
]
const store = useStore()
</script>

View File

@@ -5,7 +5,7 @@
class="flex-1 pt-2 items-center text-center"
:class="currentOption!==key ? 'hover:bg-zinc-800 text-zinc-200' : 'text-black bg-zinc-200 hover:bg-zinc-100'"
@click="currentOption = key">
{{ $t(option.key) }}
{{ $t(option.titleKey) }}
<span class="flex h-4 w-full mt-2" :style="{background: option.color.hex()}" />
</button>
</div>
@@ -15,6 +15,7 @@
import HSVInput from '@/components/config/HSVInput.vue'
import Color from 'color'
import { onBeforeMount, reactive, ref } from 'vue'
import TabSelect from '@/components/config/TabSelect.vue'
const currentOption = ref(null)
@@ -22,15 +23,15 @@ const model = defineModel({
type: Object,
default: () => ({
one: {
key: 'One',
titleKey: 'One',
color: Color('#ff0000'),
},
two: {
key: 'Two',
titleKey: 'Two',
color: Color('#00ff00'),
},
three: {
key: 'Three',
titleKey: 'Three',
color: Color('#0000ff'),
},
}),

View File

@@ -0,0 +1,23 @@
<template>
<ConfigSection title="Key Light" :icon-component="Lightbulb">
<PaletteInput v-model="keyColors" />
</ConfigSection>
</template>
<script setup>
import { Lightbulb } from 'lucide-vue-next'
import ConfigSection from '@/components/config/ConfigSection.vue'
import PaletteInput from '@/components/config/PaletteInput.vue'
import Color from 'color'
import { ref } from 'vue'
const keyColors = ref({
default: {
titleKey: 'default',
color: Color('#4f25ef'),
},
pressed: {
titleKey: 'pressed',
color: Color('#d0078f'),
},
})
</script>

View File

@@ -0,0 +1,99 @@
<template>
<ConfigSection
:title="$t('config_options.feedback_designer.feedback_type.title')"
:icon-component="GaugeCircle">
<TabSelect v-model="feedbackType" :options="feedbackTypeOptions" />
</ConfigSection>
<ConfigSection
:title="$t('config_options.feedback_designer.haptic_response.title')"
:icon-component="AudioWaveform"
:show-toggle="true">
<SteppedSlider
v-model="feedbackStrength"
:label="$t('config_options.feedback_designer.haptic_response.feedback_strength')" />
<Separator />
<SteppedSlider
v-model="bounceBackStrength"
:label="$t('config_options.feedback_designer.haptic_response.bounce_back_strength')" />
<Separator />
<SteppedSlider
v-model="outputRampDampening"
:label="$t('config_options.feedback_designer.haptic_response.output_ramp_dampening')" />
</ConfigSection>
<ConfigSection
:title="$t('config_options.feedback_designer.auditory_response.title')"
:icon-component="AudioLines" :show-toggle="true">
<SteppedSlider
v-model="auditoryHapticLevel"
:label="$t('config_options.feedback_designer.auditory_response.haptic_level')" />
<Separator />
<SteppedSlider
v-model="auditoryMagnitude"
:label="$t('config_options.feedback_designer.auditory_response.magnitude')"
:max="3"
:named-positions="[
{value:0, label: 'Faint'},
{value:1, label: 'Soft'},
{value:2, label: 'Normal'},
{value:3, label: 'Loud'}]" />
</ConfigSection>
<ConfigSection title="Ring Light" :icon-component="Lightbulb">
<PaletteInput v-model="ringColors" />
</ConfigSection>
</template>
<script setup>
import { AudioLines, AudioWaveform, GaugeCircle, Lightbulb } from 'lucide-vue-next'
import ConfigSection from '@/components/config/ConfigSection.vue'
import PaletteInput from '@/components/config/PaletteInput.vue'
import Color from 'color'
import { computed, ref } from 'vue'
import TabSelect from '@/components/config/TabSelect.vue'
import FdIcon from '@/assets/icons/iconFineDetents.svg'
import CdIcon from '@/assets/icons/iconCoarseDetents.svg'
import VfIcon from '@/assets/icons/iconViscousRotation.svg'
import RcIcon from '@/assets/icons/iconReturnToCenter.svg'
import SteppedSlider from '@/components/config/SteppedSlider.vue'
const feedbackType = ref('fineDetents') // TODO: replace with actual value
const feedbackTypeOptions = {
fineDetents: {
icon: FdIcon,
titleKey: 'config_options.feedback_designer.feedback_type.fine_detents',
},
coarseDetents: {
icon: CdIcon,
titleKey: 'config_options.feedback_designer.feedback_type.coarse_detents',
},
viscousRotation: {
icon: VfIcon,
titleKey: 'config_options.feedback_designer.feedback_type.viscous_rotation',
},
returnToCenter: {
icon: RcIcon,
titleKey: 'config_options.feedback_designer.feedback_type.return_to_center',
},
}
const feedbackStrength = ref(2)
const bounceBackStrength = ref(2)
const outputRampDampening = ref(2)
const auditoryHapticLevel = ref(2)
const auditoryMagnitude = ref(2)
const ringColors = ref({
primary: {
titleKey: 'config_options.light_designer.primary_color',
color: Color('#4f25ef'),
},
secondary: {
titleKey: 'config_options.light_designer.secondary_color',
color: Color('#1a1498'),
},
pointer: {
titleKey: 'config_options.light_designer.pointer_color',
color: Color('#ffa346'),
},
})
</script>

View File

@@ -28,12 +28,13 @@
</div>
<button
class="rounded-full outline-2 absolute h-[41.5%] top-[24.5%] aspect-square left-0 right-0 mx-auto transition-all"
:class="{'outline outline-white': selected==='ring',
'hover:outline outline-zinc-400': selected!=='ring'}"
@click="selected='ring'; $emit('select', selected)" />
:class="{'outline outline-white': store.currentConfigPage==='knob',
'hover:outline outline-zinc-400': store.currentConfigPage!=='knob'}"
@click="store.setCurrentConfigPage('knob')" />
<DeviceKeys
:selected="selected" class="absolute w-[72.7%] top-[77.2%] gap-[2.8%] left-0 right-0 mx-auto"
@select="args => {selected=args; $emit('select', selected)}" />
class="absolute w-[72.7%] top-[77.2%] gap-[2.8%] left-0 right-0 mx-auto"
:selected="store.currentConfigPage"
@select="store.setCurrentConfigPage" />
</div>
</div>
</template>
@@ -48,10 +49,6 @@ import DeviceLEDRing from '@/components/device/DeviceLEDRing.vue'
import gsap from 'gsap'
import DeviceKeys from '@/components/device/DeviceKeys.vue'
defineEmits(['select'])
const selected = ref('a')
const value = ref(69)
const barValue = computed(() => value.value / 127 * 100)

View File

@@ -10,8 +10,8 @@
<ScrambleText
v-if="showProfileList" class="text-sm text-zinc-600"
scramble-on-mount
fill-interval="20"
delay="500"
:fill-interval="20"
:delay="500"
:text="`(${store.profiles.length}/${ maxProfiles})`" />
</span>
</button>

View File

@@ -19,6 +19,8 @@ import { createPinia, defineStore } from 'pinia'
import Axios from 'axios'
import schema from '@/data/profileSchema.json'
import Ajv from 'ajv'
import KnobConfig from '@/components/config/pages/KnobConfig.vue'
import KeyConfig from '@/components/config/pages/KeyConfig.vue'
const ajv = new Ajv()
@@ -29,11 +31,28 @@ export const useStore = defineStore('main', {
profiles: [],
selectedProfileId: null,
connected: false,
currentConfigPage: 'knob',
}
},
getters: {
profileIds: (state) => state.profiles.map(p => p.id),
selectedProfile: (state) => state.profiles.find(p => p.id === state.selectedProfileId),
currentConfigComponent: (state) => {
switch (state.currentConfigPage) {
case 'knob':
return KnobConfig
case 'a':
return KeyConfig
case 'b':
return KeyConfig
case 'c':
return KeyConfig
case 'd':
return KeyConfig
default:
return KnobConfig
}
},
},
actions: {
selectProfile(id) {
@@ -110,6 +129,9 @@ export const useStore = defineStore('main', {
}
return id
},
setCurrentConfigPage(page) {
this.currentConfigPage = page
},
},
})