ADD: KnobConfig & KeyConfig
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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'),
|
||||
},
|
||||
}),
|
||||
|
||||
23
src/components/config/pages/KeyConfig.vue
Normal file
23
src/components/config/pages/KeyConfig.vue
Normal 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>
|
||||
99
src/components/config/pages/KnobConfig.vue
Normal file
99
src/components/config/pages/KnobConfig.vue
Normal 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>
|
||||
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
22
src/store.js
22
src/store.js
@@ -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
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user