Initial commit

This commit is contained in:
root
2025-12-21 09:53:25 -05:00
committed by Sebastian Krupinski
commit fa24f1468f
32 changed files with 4972 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
anniversaries: any[]
}
defineProps<Props>()
const emit = defineEmits<{
'add-anniversary': []
'remove-anniversary': [index: number]
'update-anniversary-date': [anniversary: any, date: string]
}>()
const { copiedKey, copyToClipboard } = useClipboard()
const updateAnniversaryDate = (anniversary: any, date: string) => {
emit('update-anniversary-date', anniversary, date)
}
</script>
<template>
<div v-if="(anniversaries && anniversaries.length > 0) || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Anniversaries</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-anniversary')">
<v-icon left>mdi-plus</v-icon>
Add Anniversary
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(anniversary, index) in anniversaries" :key="index" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-cake-variant" size="small" class="mr-2" />
<strong>{{ anniversary.type || 'Unknown' }} Anniversary</strong>
</div>
<v-btn
:icon="copiedKey === index ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === index ? 'success' : undefined"
@click="copyToClipboard(anniversary.when?.date || '', index)"
/>
</div>
<div class="text-caption text-grey">
Date: {{ anniversary.when?.date || 'Not set' }} |
Location: {{ anniversary.location || 'Not set' }}
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(anniversary, index) in anniversaries" :key="index" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>Anniversary</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-anniversary', index)">
</v-btn>
</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-select
v-model="anniversary.type"
:items="['birth', 'death', 'nuptial']"
label="Type"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="anniversary.location"
label="Location"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-text-field
:model-value="anniversary.when?.date || ''"
@update:model-value="updateAnniversaryDate(anniversary, $event)"
label="Date"
type="date"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,108 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
emails: Record<string, any>
}
defineProps<Props>()
const emit = defineEmits<{
'add-email': []
'remove-email': [key: string]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
</script>
<template>
<div v-if="Object.keys(emails || {}).length > 0 || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Emails</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-email')">
<v-icon left>mdi-plus</v-icon>
Add Email
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(email, key) in emails" :key="key" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-email" size="small" class="mr-2" />
<strong>{{ email.address || 'No address' }}</strong>
</div>
<v-btn
:icon="copiedKey === key ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === key ? 'success' : undefined"
@click="copyToClipboard(email.address || '', key as string)"
/>
</div>
<div class="text-caption text-grey">
Context: {{ email.context || 'Not set' }} |
Priority: {{ email.priority || 'Not set' }}
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(email, index) in emails" :key="index" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>Email</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-email', index)">
</v-btn>
</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="email.address"
label="Address"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="email.context"
label="Context"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model.number="email.priority"
label="Priority"
type="number"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,61 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
label?: string | null
}
const props = defineProps<Props>()
const emit = defineEmits<{
'update:label': [label: string | null]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
const labelValue = computed({
get: () => props.label ?? '',
set: (value) => emit('update:label', value || null)
})
</script>
<template>
<div class="person-editor-section">
<div class="text-subtitle-1 mb-2">Label</div>
<!-- Read-only view -->
<div v-if="mode === 'view'" class="mb-4">
<div class="d-flex align-center justify-space-between pa-2">
<div class="d-flex align-center">
<v-icon icon="mdi-label" size="small" class="mr-2" />
<span>{{ labelValue || 'Not set' }}</span>
</div>
<v-btn
v-if="labelValue"
:icon="copiedKey === 'label' ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === 'label' ? 'success' : undefined"
@click="copyToClipboard(labelValue, 'label')"
/>
</div>
</div>
<!-- Edit view -->
<div v-else>
<v-text-field
v-model="labelValue"
label="Label"
variant="outlined"
density="compact"
/>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,117 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
languages: any[]
}
defineProps<Props>()
const emit = defineEmits<{
'add-language': []
'remove-language': [index: number]
}>()
const { copiedKey, copyToClipboard } = useClipboard()
</script>
<template>
<div v-if="(languages || []).length > 0 || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Languages</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-language')">
<v-icon left>mdi-plus</v-icon>
Add Language
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(lang, index) in languages" :key="index" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-translate" size="small" class="mr-2" />
<strong>{{ lang.Data || 'Unknown Language' }}</strong>
</div>
<v-btn
:icon="copiedKey === index ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === index ? 'success' : undefined"
@click="copyToClipboard(lang.Data || '', index)"
/>
</div>
<div class="text-caption text-grey">
ID: {{ lang.Id || 'Not set' }} |
Context: {{ lang.Context || 'Not set' }} |
Priority: {{ lang.Priority || 'Not set' }}
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(lang, index) in languages" :key="index" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>Language</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-language', index)">
</v-btn>
</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="lang.Data"
label="Language"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="lang.Id"
label="Language ID"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="lang.Context"
label="Context"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model.number="lang.Priority"
label="Priority"
type="number"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,148 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
media: Record<string, any>
}
defineProps<Props>()
const emit = defineEmits<{
'add-media': []
'remove-media': [key: string]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
</script>
<template>
<div v-if="Object.keys(media || {}).length > 0 || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Media</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-media')">
<v-icon left>mdi-plus</v-icon>
Add Media
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(item, key) in media" :key="key" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-image" size="small" class="mr-2" />
<strong>{{ item.label || item.uri || 'Unnamed Media' }}</strong>
</div>
<v-btn
:icon="copiedKey === key ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === key ? 'success' : undefined"
@click="copyToClipboard(item.uri || '', key as string)"
/>
</div>
<div class="text-caption text-grey">
Type: {{ item.type || 'Not set' }} |
Kind: {{ item.kind || 'Not set' }} |
Contexts: {{ (item.contexts || []).join(', ') || 'None' }} |
Pref: {{ item.pref || 'Not set' }}
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(item, index) in media" :key="index" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>Media</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-media', index)">
</v-btn>
</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="item.uri"
label="URI"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="item.label"
label="Label"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row class="mb-2">
<v-col cols="12" md="4">
<v-select
v-model="item.type"
:items="['photo', 'video', 'audio', 'document']"
label="Type"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="4">
<v-select
v-model="item.kind"
:items="['photo', 'sound', 'logo']"
label="Kind"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="item.mediaType"
label="Media Type"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="item.contexts"
label="Contexts (comma-separated)"
variant="outlined"
density="compact"
hint="Enter contexts separated by commas"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model.number="item.pref"
label="Preference"
type="number"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,117 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
members: Record<string, any>
}
defineProps<Props>()
const emit = defineEmits<{
'add-member': []
'remove-member': [key: string]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
</script>
<template>
<div v-if="Object.keys(members || {}).length > 0 || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Members</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-member')">
<v-icon left>mdi-plus</v-icon>
Add Member
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(member, key) in members" :key="key" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-account" size="small" class="mr-2" />
<strong>Entity ID: {{ member.entityId || 'Not set' }}</strong>
</div>
<v-btn
:icon="copiedKey === key ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === key ? 'success' : undefined"
@click="copyToClipboard(member.entityId || '', key as string)"
/>
</div>
<div class="text-caption text-grey">
Role: {{ member.role || 'Not set' }} |
Context: {{ member.context || 'Not set' }} |
Priority: {{ member.priority || 'Not set' }}
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(member, index) in members" :key="index" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>Member</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-member', index)">
</v-btn>
</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="member.entityId"
label="Entity ID"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="member.role"
label="Role"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="member.context"
label="Context"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model.number="member.priority"
label="Priority"
type="number"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,139 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
names: any
}
const props = defineProps<Props>()
const emit = defineEmits<{
'update:names': [names: any]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
const names = computed({
get: () => props.names,
set: (value) => emit('update:names', value)
})
const formatName = (names: any) => {
if (!names) return 'Not set'
const parts = []
if (names.prefix) parts.push(names.prefix)
if (names.given) parts.push(names.given)
if (names.additional) parts.push(names.additional)
if (names.family) parts.push(names.family)
if (names.suffix) parts.push(names.suffix)
return parts.join(' ') || 'Not set'
}
</script>
<template>
<div class="person-editor-section">
<div class="text-subtitle-1 mb-2">Name</div>
<!-- Read-only view -->
<div v-if="mode === 'view'" class="mb-4">
<div class="d-flex align-center justify-space-between pa-2">
<div class="d-flex align-center">
<v-icon icon="mdi-account" size="small" class="mr-2" />
<span>{{ formatName(names) }}</span>
</div>
<v-btn
v-if="formatName(names) !== 'Not set'"
:icon="copiedKey === 'name' ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === 'name' ? 'success' : undefined"
@click="copyToClipboard(formatName(names), 'name')"
/>
</div>
</div>
<!-- Edit view -->
<div v-else>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="names.given"
label="Given Name"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="names.family"
label="Family Name"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row class="mb-2">
<v-col cols="12" md="4">
<v-text-field
v-model="names.additional"
label="Additional Name"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="names.prefix"
label="Prefix"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="names.suffix"
label="Suffix"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<div class="text-subtitle-1 mb-2 mt-4">Phonetic Name</div>
<v-row class="mb-2">
<v-col cols="12" md="4">
<v-text-field
v-model="names.phoneticGiven"
label="Phonetic Given Name"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="names.phoneticAdditional"
label="Phonetic Additional Name"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="names.phoneticFamily"
label="Phonetic Family Name"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,160 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
notes: Record<string, any>
}
defineProps<Props>()
const emit = defineEmits<{
'add-note': []
'remove-note': [key: string]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
</script>
<template>
<div v-if="Object.keys(notes || {}).length > 0 || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Notes</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-note')">
<v-icon left>mdi-plus</v-icon>
Add Note
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(note, key) in notes" :key="key" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-note-text" size="small" class="mr-2" />
<strong>{{ note.content || 'Empty note' }}</strong>
</div>
<v-btn
:icon="copiedKey === key ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === key ? 'success' : undefined"
@click="copyToClipboard(note.content || '', key as string)"
/>
</div>
<div class="text-caption text-grey">
Date: {{ note.date?.date || 'Not set' }} |
Author: {{ note.authorName || note.authorUri || 'Unknown' }} |
Context: {{ note.context || 'Not set' }} |
Priority: {{ note.priority || 'Not set' }}
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(note, index) in notes" :key="index" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>Note</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-note', index)">
</v-btn>
</div>
<v-row class="mb-2">
<v-col cols="12">
<v-textarea
v-model="note.content"
label="Content"
variant="outlined"
density="compact"
rows="3"
/>
</v-col>
</v-row>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="note.authorName"
label="Author Name"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="note.authorUri"
label="Author URI"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="note.context"
label="Context"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model.number="note.priority"
label="Priority"
type="number"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-text-field
:model-value="note.date?.date || ''"
@update:model-value="updateNoteDate(note, $event)"
label="Date"
type="date"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<script lang="ts">
export default {
methods: {
updateNoteDate(note: any, date: string) {
if (!note.date) {
note.date = {
date: '',
timezone_type: 3,
timezone: 'UTC'
}
}
note.date.date = date
}
}
}
</script>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,131 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
organizations: Record<string, any>
}
defineProps<Props>()
const emit = defineEmits<{
'add-organization': []
'remove-organization': [key: string]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
</script>
<template>
<div v-if="(organizations || []).length > 0 || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Organizations</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-organization')">
<v-icon left>mdi-plus</v-icon>
Add Organization
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(org, key) in organizations" :key="key" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-domain" size="small" class="mr-2" />
<strong>{{ org.Label || 'Unnamed Organization' }}</strong>
</div>
<v-btn
:icon="copiedKey === key ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === key ? 'success' : undefined"
@click="copyToClipboard(org.Label || '', key as string)"
/>
</div>
<div class="text-caption text-grey">
Units: {{ (org.Units || []).join(', ') || 'None' }}
</div>
<div class="text-caption text-grey">
Context: {{ org.context || 'Not set' }} |
Priority: {{ org.priority || 'Not set' }}
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(org, index) in organizations" :key="index" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>Organization</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-organization', index)">
</v-btn>
</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="org.Label"
label="Label"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="org.sortName"
label="Sort Name"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="org.context"
label="Context"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model.number="org.priority"
label="Priority"
type="number"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12">
<v-text-field
v-model="org.Units"
label="Units (comma-separated)"
variant="outlined"
density="compact"
hint="Enter units separated by commas"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,117 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
phones: Record<string, any>
}
defineProps<Props>()
const emit = defineEmits<{
'add-phone': []
'remove-phone': [key: string]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
</script>
<template>
<div v-if="Object.keys(phones || {}).length > 0 || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Phones</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-phone')">
<v-icon left>mdi-plus</v-icon>
Add Phone
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(phone, key) in phones" :key="key" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-phone" size="small" class="mr-2" />
<strong>{{ phone.number || 'No number' }}</strong>
</div>
<v-btn
:icon="copiedKey === key ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === key ? 'success' : undefined"
@click="copyToClipboard(phone.number || '', key as string)"
/>
</div>
<div class="text-caption text-grey">
Label: {{ phone.label || 'Not set' }} |
Context: {{ phone.context || 'Not set' }} |
Priority: {{ phone.priority || 'Not set' }}
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(phone, index) in phones" :key="index" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>Phone</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-phone', index)">
</v-btn>
</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="phone.number"
label="Number"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="phone.label"
label="Label"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="phone.context"
label="Context"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model.number="phone.priority"
label="Priority"
type="number"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,206 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
physicalLocations: Record<string, any>
}
defineProps<Props>()
const emit = defineEmits<{
'add-physical-location': []
'remove-physical-location': [key: string]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
const formatAddress = (location: any) => {
if (!location) return 'Not set'
const parts = []
if (location.street) parts.push(location.street)
if (location.locality) parts.push(location.locality)
if (location.region) parts.push(location.region)
if (location.code) parts.push(location.code)
if (location.country) parts.push(location.country)
return parts.join(', ') || 'Not set'
}
</script>
<template>
<div v-if="Object.keys(physicalLocations || {}).length > 0 || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Physical Locations</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-physical-location')">
<v-icon left>mdi-plus</v-icon>
Add Location
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(location, key) in physicalLocations" :key="key" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-map-marker" size="small" class="mr-2" />
<strong>{{ location.label || `Location ${parseInt(key.split('_')[1]) || key}` }}</strong>
</div>
<v-btn
:icon="copiedKey === key ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === key ? 'success' : undefined"
@click="copyToClipboard(formatAddress(location), key as string)"
/>
</div>
<div class="text-caption text-grey">
{{ formatAddress(location) }}
<span v-if="location.context"> | Context: {{ location.context }}</span>
<span v-if="location.priority"> | Priority: {{ location.priority }}</span>
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(location, index) in physicalLocations" :key="index" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>{{ location.label || `Location` }}</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-physical-location', index)">
</v-btn>
</div>
<div class="text-subtitle-2 mb-2">Address</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="location.box"
label="Box"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="location.unit"
label="Unit"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row class="mb-2">
<v-col cols="12">
<v-text-field
v-model="location.street"
label="Street"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="location.locality"
label="City/Locality"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="location.region"
label="State/Region"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row class="mb-4">
<v-col cols="12" md="6">
<v-text-field
v-model="location.code"
label="Postal Code"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="location.country"
label="Country"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<div class="text-subtitle-2 mb-2">Additional Information</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="location.label"
label="Label"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="location.coordinates"
label="Coordinates"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row class="mb-2">
<v-col cols="12" md="4">
<v-text-field
v-model="location.timeZone"
label="Time Zone"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model="location.context"
label="Context"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="4">
<v-text-field
v-model.number="location.priority"
label="Priority"
type="number"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,130 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
titles: Record<string, any>
}
defineProps<Props>()
const emit = defineEmits<{
'add-title': []
'remove-title': [key: string]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
</script>
<template>
<div v-if="Object.keys(titles || {}).length > 0 || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Titles</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-title')">
<v-icon left>mdi-plus</v-icon>
Add Title
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(title, key) in titles" :key="key" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-badge-account" size="small" class="mr-2" />
<strong>{{ title.label || 'Untitled' }}</strong>
</div>
<v-btn
:icon="copiedKey === key ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === key ? 'success' : undefined"
@click="copyToClipboard(title.label || '', key as string)"
/>
</div>
<div class="text-caption text-grey">
Kind: {{ title.kind || 'Not set' }} |
Relation: {{ title.relation || 'Not set' }} |
Context: {{ title.context || 'Not set' }} |
Priority: {{ title.priority || 'Not set' }}
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(title, key) in titles" :key="key" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>Title</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-title', key)">
</v-btn>
</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-select
v-model="title.kind"
:items="['t', 'r']"
label="Kind"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="title.label"
label="Label"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="title.relation"
label="Relation"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="title.context"
label="Context"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model.number="title.priority"
label="Priority"
type="number"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>

View File

@@ -0,0 +1,117 @@
<script setup lang="ts">
import { useClipboard } from '@KTXC/composables/useClipboard'
interface Props {
mode: 'edit' | 'view'
virtualLocations: Record<string, any>
}
defineProps<Props>()
const emit = defineEmits<{
'add-virtual-location': []
'remove-virtual-location': [key: string]
}>()
const { copiedKey, copyToClipboard } = useClipboard<string>()
</script>
<template>
<div v-if="Object.keys(virtualLocations || {}).length > 0 || mode === 'edit'" class="person-editor-section">
<div class="d-flex align-center justify-space-between mb-2">
<div class="text-subtitle-1">Virtual Locations</div>
<v-btn v-if="mode === 'edit'"
size="small"
variant="outlined"
@click="$emit('add-virtual-location')">
<v-icon left>mdi-plus</v-icon>
Add Virtual Location
</v-btn>
</div>
<!-- Read-only view -->
<div v-if="mode === 'view'">
<div v-for="(virtualLocation, key) in virtualLocations" :key="key" class="mb-2 pa-2 border rounded">
<div class="d-flex align-center justify-space-between mb-1">
<div class="d-flex align-center">
<v-icon icon="mdi-web" size="small" class="mr-2" />
<strong>{{ virtualLocation.location || 'No location' }}</strong>
</div>
<v-btn
:icon="copiedKey === key ? 'mdi-check' : 'mdi-content-copy'"
size="x-small"
variant="text"
:color="copiedKey === key ? 'success' : undefined"
@click="copyToClipboard(virtualLocation.location || '', key as string)"
/>
</div>
<div class="text-caption text-grey">
Label: {{ virtualLocation.label || 'Not set' }} |
Context: {{ virtualLocation.context || 'Not set' }} |
Priority: {{ virtualLocation.priority || 'Not set' }}
</div>
</div>
</div>
<!-- Edit view -->
<div v-else>
<div v-for="(virtualLocation, index) in virtualLocations" :key="index" class="mb-4 pa-3 border rounded">
<div class="d-flex align-center justify-space-between mb-2">
<strong>Virtual Location</strong>
<v-btn
icon="mdi-delete"
size="small"
color="error"
variant="text"
@click="$emit('remove-virtual-location', index)">
</v-btn>
</div>
<v-row class="mb-2">
<v-col cols="12" md="6">
<v-text-field
v-model="virtualLocation.location"
label="Location (URL/Handle)"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="virtualLocation.label"
label="Label"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="virtualLocation.context"
label="Context"
variant="outlined"
density="compact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model.number="virtualLocation.priority"
label="Priority"
type="number"
variant="outlined"
density="compact"
/>
</v-col>
</v-row>
</div>
</div>
</div>
</template>
<style scoped>
.person-editor-section {
margin-bottom: 1.5rem;
}
</style>