continue scaffolding and refine the basic foundation
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
<script setup lang="ts">
|
||||
const route = useRoute();
|
||||
const appState = useAppState();
|
||||
const topicsListRef = ref<HTMLElement | null>(null);
|
||||
const topicsListHeight = ref('auto');
|
||||
const topicsListOpacity = ref(1);
|
||||
const topicsListScale = ref(1);
|
||||
const { topicsForActiveAgent, createTopic } = await useTopics();
|
||||
const { activeAgent } = await useAgents();
|
||||
|
||||
const creatingTopic = ref(false);
|
||||
const topicsOpen = ref(true);
|
||||
|
||||
function easeInOutQuad(x: number): number {
|
||||
return x < 0.5 ? 2 * x * x : 1 - Math.pow(-2 * x + 2, 2) / 2;
|
||||
}
|
||||
|
||||
const toggleAgentsList = () => {
|
||||
if (!topicsListRef.value) return;
|
||||
let animationLength = 200;
|
||||
let animationStart: number | null = null;
|
||||
|
||||
let startHeight: number;
|
||||
let startOpacity = topicsListOpacity.value;
|
||||
let startScale = topicsListScale.value;
|
||||
if (topicsListHeight.value === 'auto') {
|
||||
startHeight = topicsListRef.value.clientHeight;
|
||||
} else {
|
||||
startHeight = Number(topicsListHeight.value.replace('px', ''));
|
||||
}
|
||||
|
||||
let targetHeight = topicsOpen.value ? 0 : topicsListRef.value.scrollHeight;
|
||||
let targetOpacity = topicsOpen.value ? 0 : 1;
|
||||
let targetScale = topicsOpen.value ? 0.95 : 1;
|
||||
topicsOpen.value = !topicsOpen.value;
|
||||
|
||||
const animate = (timestamp: number) => {
|
||||
if (!animationStart) animationStart = timestamp;
|
||||
|
||||
const elapsed = timestamp - animationStart;
|
||||
const progress = Math.min(elapsed / animationLength, 1);
|
||||
|
||||
const currentHeight = startHeight + (targetHeight - startHeight) * easeInOutQuad(progress);
|
||||
const currentOpacity = startOpacity + (targetOpacity - startOpacity) * easeInOutQuad(progress);
|
||||
const currentScale = startScale + (targetScale - startScale) * easeInOutQuad(progress);
|
||||
|
||||
topicsListOpacity.value = currentOpacity;
|
||||
topicsListScale.value = currentScale;
|
||||
topicsListHeight.value = `${currentHeight}px`;
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(animate);
|
||||
} else {
|
||||
if (topicsOpen.value) {
|
||||
topicsListHeight.value = 'auto';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
const newTopic = async () => {
|
||||
if (!activeAgent.value) return;
|
||||
|
||||
creatingTopic.value = true;
|
||||
try {
|
||||
const newTopic = await createTopic('New Topic', activeAgent.value.id);
|
||||
// Navigate to new topic
|
||||
await navigateTo(`/agent/${activeAgent.value.id}/topic/${newTopic.id}`);
|
||||
} catch (error) {
|
||||
console.error('Failed to create topic:', error);
|
||||
} finally {
|
||||
creatingTopic.value = false;
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-2">
|
||||
<!-- Header -->
|
||||
<button @click="toggleAgentsList"
|
||||
class="flex items-center justify-between gap-2 px-2 py-2 rounded-lg bg-transparent hover:bg-[var(--color-highlight)] transition-colors w-full text-left">
|
||||
<span class="text-sm font-medium">Topics</span>
|
||||
<Icon name="mynaui:chevron-down" :class="['w-4 h-4', topicsOpen ? '' : '-rotate-90']" />
|
||||
</button>
|
||||
|
||||
<div ref="topicsListRef"
|
||||
:style="{ height: topicsListHeight, opacity: topicsListOpacity, transform: `scale(${topicsListScale})` }"
|
||||
class="mt-1 gap-1 flex flex-col overflow-hidden transform-origin-center-top">
|
||||
<button @click="newTopic" :disabled="creatingTopic"
|
||||
class="flex items-center gap-2 px-1 h-9 shrink-0 rounded-lg text-sm text-[var(--color-subtle)] bg-transparent hover:bg-[var(--color-highlight)] transition-colors disabled:opacity-50 w-full">
|
||||
<div class="h-7 w-7 flex items-center justify-center">
|
||||
<Icon v-if="creatingTopic" class="text-4.5" name="svg-spinners:ring-resize" />
|
||||
<Icon v-else class="text-4.5" name="mynaui:plus" />
|
||||
</div>
|
||||
<span>{{ creatingTopic ? 'Creating...' : 'New Topic' }}</span>
|
||||
</button>
|
||||
|
||||
<NuxtLink v-for="topic in topicsForActiveAgent" :to="`/agent/${activeAgent?.id}/topic/${topic.id}`"
|
||||
class="decoration-none text-[var(--color-subtle)]">
|
||||
<SidenavItem :name="topic.name" icon="mynaui:check-hexagon" />
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user