a6af22859a
Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
174 lines
4.4 KiB
Vue
174 lines
4.4 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
import { CollectionObject } from '@ChronoManager/models/collection';
|
|
|
|
// Props
|
|
const props = defineProps<{
|
|
collections: CollectionObject[]
|
|
selectedCollection?: CollectionObject | null
|
|
type?: 'calendar' | 'tasklist'
|
|
}>()
|
|
|
|
// Emits
|
|
const emit = defineEmits<{
|
|
'create': []
|
|
'select': [collection: CollectionObject]
|
|
'edit': [collection: CollectionObject]
|
|
'toggle-visibility': [collection: CollectionObject]
|
|
}>()
|
|
|
|
// Computed
|
|
const filteredCollections = computed(() => {
|
|
if (!props.type) return props.collections
|
|
|
|
return props.collections.filter(collection => {
|
|
if (props.type === 'calendar') {
|
|
return collection.properties.content?.includes('event')
|
|
} else if (props.type === 'tasklist') {
|
|
return collection.properties.content?.includes('task')
|
|
}
|
|
return true
|
|
})
|
|
})
|
|
|
|
const displayTitle = computed(() => {
|
|
if (props.type === 'calendar') return 'Calendars'
|
|
if (props.type === 'tasklist') return 'Task Lists'
|
|
return 'Collections'
|
|
})
|
|
|
|
const displayIcon = computed(() => {
|
|
if (props.type === 'calendar') return 'mdi-calendar'
|
|
if (props.type === 'tasklist') return 'mdi-checkbox-marked-outline'
|
|
return 'mdi-folder'
|
|
})
|
|
|
|
const createLabel = computed(() => {
|
|
if (props.type === 'calendar') return 'New Calendar'
|
|
if (props.type === 'tasklist') return 'New Task List'
|
|
return 'New Collection'
|
|
})
|
|
|
|
// Functions
|
|
const onCollectionSelect = (collection: CollectionObject) => {
|
|
console.log('[Chrono] - Collection selected', collection)
|
|
emit('select', collection)
|
|
}
|
|
|
|
const onCollectionEdit = (collection: CollectionObject) => {
|
|
emit('edit', collection)
|
|
}
|
|
|
|
const onToggleVisibility = (collection: CollectionObject) => {
|
|
emit('toggle-visibility', collection)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="collection-selector">
|
|
<div class="collection-selector-header">
|
|
<div class="d-flex align-center justify-space-between mb-1">
|
|
<div class="d-flex align-center">
|
|
<v-icon :icon="displayIcon" size="14" class="mr-2 text-medium-emphasis" />
|
|
<span class="sidebar-section-label">{{ displayTitle }}</span>
|
|
</div>
|
|
<v-btn
|
|
icon="mdi-plus"
|
|
size="x-small"
|
|
variant="text"
|
|
:aria-label="createLabel"
|
|
:title="createLabel"
|
|
@click="emit('create')"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<v-divider class="mb-2" />
|
|
|
|
<div class="collection-selector-content">
|
|
<v-list density="compact" nav class="pa-0">
|
|
<v-list-item
|
|
v-for="collection in filteredCollections"
|
|
:key="collection.identifier"
|
|
:value="collection.identifier"
|
|
:active="selectedCollection?.identifier === collection.identifier"
|
|
@click="onCollectionSelect(collection)"
|
|
rounded="lg"
|
|
class="mb-1"
|
|
>
|
|
<template #prepend>
|
|
<v-checkbox-btn
|
|
:model-value="collection.properties.visibility !== false"
|
|
:color="collection.properties.color || 'primary'"
|
|
hide-details
|
|
@click.stop="onToggleVisibility(collection)"
|
|
/>
|
|
</template>
|
|
|
|
<v-list-item-title>{{ collection.properties.label || 'Unnamed Collection' }}</v-list-item-title>
|
|
|
|
<template #append>
|
|
<v-btn
|
|
icon="mdi-pencil"
|
|
size="x-small"
|
|
variant="text"
|
|
class="collection-edit-btn"
|
|
@click.stop="onCollectionEdit(collection)"
|
|
/>
|
|
</template>
|
|
</v-list-item>
|
|
</v-list>
|
|
|
|
<v-alert v-if="filteredCollections.length === 0" type="info" variant="tonal" density="compact" class="mt-2">
|
|
No {{ displayTitle.toLowerCase() }} found
|
|
</v-alert>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.collection-selector {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
}
|
|
|
|
.collection-selector-header {
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.collection-selector-content {
|
|
flex: 1;
|
|
overflow-y: auto;
|
|
min-height: 0;
|
|
}
|
|
|
|
.v-list-item {
|
|
cursor: pointer;
|
|
}
|
|
|
|
.sidebar-section-label {
|
|
font-size: 11px;
|
|
font-weight: 600;
|
|
letter-spacing: 0.09em;
|
|
text-transform: uppercase;
|
|
color: rgba(var(--v-theme-on-surface), 0.6);
|
|
}
|
|
|
|
.collection-edit-btn {
|
|
opacity: 0;
|
|
transition: opacity 0.15s ease;
|
|
}
|
|
|
|
.v-list-item:hover .collection-edit-btn,
|
|
.v-list-item:focus-within .collection-edit-btn {
|
|
opacity: 1;
|
|
}
|
|
|
|
@media (hover: none) {
|
|
.collection-edit-btn {
|
|
opacity: 1;
|
|
}
|
|
}
|
|
</style>
|