ADD: Profile management functionality & store

This commit is contained in:
Robert Kossessa
2024-01-27 02:42:37 +01:00
parent 11c66766bf
commit b23df03df6
8 changed files with 273 additions and 85 deletions

View File

@@ -0,0 +1,114 @@
<template>
<div
class="h-12 flex profile-row"
@mouseenter="hover=true" @mouseleave="hover=false">
<button
:class="{'font-semibold bg-zinc-200 hover:bg-zinc-100 text-black' : selected,
'hover:bg-zinc-900 bg-opacity-50 text-white': !selected,
'text-ellipsis': !editing}"
class="flex-1 h-full text-left whitespace-nowrap overflow-hidden"
@click="!editing && $emit('select') && $refs.profileTitle.scramble()">
<FileDigit
:class="{'text-zinc-600': selected,
'text-muted-foreground': !selected,
'w-0': hover}"
class="h-4 ml-10 mb-1 inline-block" />
<input
v-if="editing" ref="profileNameInput" v-model="profile.name"
onfocus="this.select()" :placeholder="$t('profiles.name_placeholder')"
class="pl-10 w-full h-full bg-transparent focus-visible:ring-0 focus-visible:outline-none"
style="color: inherit; background: inherit">
<template v-else>
<ScrambleText
ref="profileTitle"
:class="{'text-black': selected, 'text-zinc-100': !selected}"
:text="profile.name" />
<span
class="text-xs text-zinc-600"
:class="{'hidden': hover}"> uID:{{ profile.id }}</span>
</template>
</button>
<template v-if="!confirmDelete">
<button
:class="{'bg-zinc-200 hover:bg-zinc-100 text-black' : selected,
'hover:bg-opacity-100 bg-zinc-900 text-zinc-100 bg-opacity-50': !selected,
'w-12': editing,
'w-0': !editing}"
class="flex h-12 justify-center items-center flex-shrink-0"
@click="editing=false">
<Check class="h-4 w-4" />
</button>
<button
:class="{'bg-zinc-200 hover:bg-zinc-100 text-black' : selected,
'hover:bg-opacity-100 bg-zinc-900 text-zinc-100 bg-opacity-50': !selected,
'w-12' : hover && !editing}"
class="flex w-0 h-12 justify-center items-center flex-shrink-0"
@click="editing=true; $nextTick(()=>{$refs.profileNameInput.focus()})">
<PenLine class="h-4 w-4" />
</button>
<button
:class="{'bg-zinc-200 hover:bg-zinc-100 text-black' : selected,
'hover:bg-opacity-100 bg-zinc-900 text-zinc-100 bg-opacity-50': !selected,
'w-12' : hover && !editing}"
class="flex w-0 h-12 justify-center items-center flex-shrink-0">
<Copy class="h-4 w-4" />
</button>
<button
:class="{'bg-orange-600 hover:bg-orange-500 text-black' : selected,
'hover:bg-opacity-100 bg-orange-900 text-zinc-100 bg-opacity-50': !selected,
'w-12' : hover && !editing}"
class="flex w-0 h-12 justify-center items-center flex-shrink-0"
@click="confirmDelete=true">
<Trash2 class="h-4 w-4" />
</button>
</template>
<template v-else>
<button
:class="{'bg-orange-600 hover:bg-orange-500 text-black' : selected,
'hover:bg-opacity-100 bg-orange-900 text-zinc-100 bg-opacity-50': !selected,
'w-12' : hover && !editing}"
class="flex w-0 h-12 justify-center items-center flex-shrink-0"
@click="$emit('delete', profile.id)">
<Check class="h-4 w-4" />
</button>
<button
:class="{'bg-zinc-200 hover:bg-zinc-100 text-black' : selected,
'hover:bg-opacity-100 bg-zinc-900 text-zinc-100 bg-opacity-50': !selected,
'w-12' : hover && !editing}"
class="flex w-0 h-12 justify-center items-center flex-shrink-0"
@click="confirmDelete=false">
<X class="h-4 w-4" />
</button>
</template>
</div>
</template>
<script setup>
import { Check, Copy, FileDigit, PenLine, Trash2, X } from 'lucide-vue-next'
import ScrambleText from '@/components/effects/ScrambleText.vue'
import { ref } from 'vue'
defineEmits(['select', 'duplicate', 'delete'])
const profile = defineModel({
type: Object,
required: true,
default: () => ({
id: '1234',
name: 'Profile Name',
}),
})
defineProps({
selected: {
type: Boolean,
default: false,
},
})
const editing = ref(false)
const confirmDelete = ref(false)
const hover = ref(false)
</script>

View File

@@ -23,7 +23,8 @@
v-model="filter"
:placeholder="$t('profiles.filter_placeholder')"
class="grow h-full bg-transparent text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-0 disabled:cursor-not-allowed disabled:opacity-50">
<button class="h-full flex text-zinc-200 bg-zinc-900 justify-center items-center aspect-square border-solid border-0 border-l hover:bg-zinc-800">
<button
class="h-full flex text-zinc-200 bg-zinc-900 justify-center items-center aspect-square border-solid border-0 border-l hover:bg-zinc-800">
<Plus />
</button>
</div>
@@ -37,7 +38,8 @@
</div>
<div>
<Collapsible
v-for="[profileTag, tagProfiles] in filteredProfilesByTag" :key="profileTag" v-model:open="collapse[profileTag]"
v-for="[profileTag, tagProfiles] in filteredProfilesByTag" :key="profileTag"
v-model:open="collapse[profileTag]"
:default-open="true">
<CollapsibleTrigger
class="w-full h-12 py-2 text-left text-muted-foreground text-sm hover:bg-zinc-900">
@@ -45,53 +47,33 @@
{{ profileTag }}<span class="font-heading text-sm text-zinc-600"> ({{ tagProfiles.length }})</span>
</CollapsibleTrigger>
<CollapsibleContent>
<div
v-for="profile in tagProfiles" :key="profile.id"
class="h-12 flex profile-row">
<button
:data-selected="currentProfile===profile.id"
class="flex-1 h-full text-left data-[selected=true]:font-semibold hover:bg-zinc-900 data-[selected=true]:bg-zinc-200 hover:data-[selected=true]:bg-zinc-100 data-[selected=true]:text-black flex-nowrap text-ellipsis overflow-hidden whitespace-nowrap"
@click="currentProfile=profile.id; profileTitles[profile.id].scramble()">
<FileDigit
:data-selected="currentProfile===profile.id"
class="h-4 w-4 mb-1 ml-10 mr-2 inline-block text-muted-foreground data-[selected=true]:text-zinc-600" />
<ScrambleText :ref="el => { profileTitles[profile.id] = el }" :text="profile.name" />
<span class="text-xs text-zinc-600"> uID:{{ profile.id }}</span>
</button>
<button
:data-selected="currentProfile===profile.id"
class="flex w-0 h-12 transition-all text-zinc-100 justify-center items-center profile-button hover:bg-opacity-100 bg-opacity-50 bg-zinc-900 data-[selected=true]:bg-zinc-200 hover:data-[selected=true]:bg-zinc-100 data-[selected=true]:text-black">
<Copy class="h-4 w-4" />
</button>
<button
:data-selected="currentProfile===profile.id"
class="flex w-0 h-12 transition-all bg-orange-900 text-zinc-100 justify-center items-center profile-button hover:bg-orange-700 data-[selected=true]:bg-orange-600 hover:data-[selected=true]:bg-orange-500 data-[selected=true]:text-black">
<Trash2 class="h-4 w-4" />
</button>
</div>
<ProfileButton
v-for="(profile, index) in tagProfiles" :key="profile.id" v-model="tagProfiles[index]"
:selected="currentProfile===profile.id"
@select="currentProfile=profile.id" />
</CollapsibleContent>
</Collapsible>
</div>
</div>
<SchemaTest />
</div>
</template>
<script setup>
import SchemaTest from '@/components/SchemaTest.vue'
import { Separator } from '@/components/ui/separator/index.js'
import { FileDigit, ChevronRight, Search, Trash2, Copy, Plus } from 'lucide-vue-next'
import axios from 'axios'
import { computed, onMounted, ref } from 'vue'
import {
Collapsible,
CollapsibleContent,
CollapsibleTrigger,
} from '@/components/ui/collapsible'
import { ChevronRight, Plus, Search } from 'lucide-vue-next'
import { computed, ref } from 'vue'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible'
import ScrambleText from '@/components/effects/ScrambleText.vue'
import { store } from '@/store.js'
import ProfileButton from '@/components/ProfileButton.vue'
const maxProfiles = 32
const profiles = ref([])
const editingId = ref(null)
const profiles = computed({
get: () => store.device.profiles,
set: val => store.device.profiles = val,
})
const filter = ref('')
const collapse = ref({})
@@ -122,25 +104,10 @@ const filteredProfilesByTag = computed(() => {
})
return map
})
function fetchProfiles() {
axios.get('http://localhost:3001/profiles').then(res => {
profiles.value = res.data
}).catch(err => {
console.error(err)
})
}
onMounted(() => {
fetchProfiles()
})
</script>
<style scoped>
[data-state=open] > .chevrot {
transform: rotate(90deg);
}
.profile-row:hover .profile-button {
width: 3rem /* 48px */;
}
</style>