feat: enhance UI components and add accordion functionality

- Updated DraggableWindow.vue to improve shadow effects.
- Refactored AboutWindow.vue for better structure and readability.
- Added chatbot functionality in chatbot.vue with cookie management.
- Improved navigation component for better code clarity.
- Created a new chat history table in the database schema.
- Modified error handling in error.vue to display error messages correctly.
- Integrated ChatbotWindow into the desktop application layout.
- Implemented accordion component in home.vue for Q/A section.
- Enhanced API for chat functionality with improved error handling.
- Removed unused routes for cleaner codebase.
- Added custom animations for accordion components in tailwind.config.js.
- Developed accordion UI components (Accordion, AccordionContent, AccordionItem, AccordionTrigger) for better user interaction.
This commit is contained in:
yuanhau 2025-05-13 09:40:37 +08:00
parent f89e6aaa48
commit 5bf857f3cd
21 changed files with 402 additions and 182 deletions

View file

@ -31,15 +31,9 @@ import LoginWindow from "~/components/app/windows/login.vue";
import HotNewsWindow from "~/components/app/windows/hotnews.vue";
import SourcesWindow from "~/components/app/windows/sources.vue";
import AboutWindow from "~/components/app/windows/about.vue";
import ChatbotWindow from "~/components/app/windows/chatbot.vue";
import Error404Window from "~/components/app/windows/error404.vue";
// Import Shadcn/UI components
import AlertComponent from "~/components/ui/alert/Alert.vue";
import ButtonComponent from "~/components/ui/button/Button.vue";
import DialogComponent from "~/components/ui/dialog/Dialog.vue";
import ProgressComponent from "~/components/ui/progress/Progress.vue";
import HoverCardComponent from "~/components/ui/hover-card/HoverCard.vue";
// Icons
import {
ComputerDesktopIcon,
@ -71,7 +65,7 @@ const openAppId = ref();
const openAppNameQuery = ref();
const currentOpenAppId = ref(0);
const progress = ref(0);
const titleAppName = ref("Desktop");
// Key Data
const menuItems = [
@ -95,27 +89,56 @@ const associAppWindow = [
width: "700px",
height: "500px",
},
{ name: "login", id: "2", title: t("app.login"), component: LoginWindow },
{
name: "login",
id: "2",
title: t("app.login"),
component: LoginWindow,
},
{
name: "sources",
id: "3",
title: t("app.sources"),
component: SourcesWindow,
},
{ name: "about", id: "4", title: t("app.about"), component: AboutWindow },
{
name: "about",
id: "4",
title: t("app.about"),
component: AboutWindow,
},
{
name: "settings",
id: "5",
title: t("app.settings"),
component: Error404Window,
},
{ name: "news", id: "6", title: t("app.news"), component: Error404Window },
{
name: "news",
id: "6",
title: t("app.news"),
component: Error404Window,
},
{
name: "starred",
id: "7",
title: t("app.starred"),
component: Error404Window,
},
{
name: "chatbot",
id: "8",
title: t("app.chatbot"),
component: ChatbotWindow,
width: "400px",
height: "600px",
},
{
name: "error404",
id: "9",
title: t("app.error404"),
component: Error404Window,
},
];
// Date
@ -176,7 +199,6 @@ onMounted(async () => {
}
});
const findAndOpenWindow = (windowName: string) => {
const app = associAppWindow.find((app) => app.name === windowName);
@ -199,6 +221,7 @@ const findAndOpenWindow = (windowName: string) => {
if (app) {
// Use shallowRef for better performance with components
const windowComponent = shallowRef(app.component);
titleAppName.value = app.title;
activeWindows.value.push({
id: currentOpenAppId.value,
@ -216,12 +239,12 @@ const obtainTopWindowPosition = (windowId: string) => {
const windowIndex = activeWindows.value.findIndex(
(window) => window.id === windowId,
);
console.log(windowIndex)
console.log(windowIndex);
if (windowIndex !== -1) {
const [window] = activeWindows.value.splice(windowIndex, 1);
activeWindows.value.push(window);
}
}
};
const closeWindow = (windowId: string) => {
activeWindows.value = activeWindows.value.filter(
@ -234,17 +257,17 @@ const maxWindow = (windowId: string) => {};
// Title
useSeoMeta({
title: "hi" + " - Desktop",
title: titleAppName.value + " - Desktop",
});
// Booting animation
onMounted(() => {
// booting animation bypass
const bootingHeaderParams = route.query.bypass;
if (bootingHeaderParams) {
bootingAnimation.value = false;
return;
}
const bootingHeaderParams = route.query.bypass;
if (bootingHeaderParams) {
bootingAnimation.value = false;
return;
}
if (bootingAnimation.value) {
gsap.to(popMessage.value, {
duration: 0.5,
@ -255,20 +278,26 @@ if (bootingHeaderParams) {
bootingAnimation.value = false;
}, 2000);
}
})
});
watchEffect((cleanupFn) => {
const timer = setTimeout(() => progress.value = 100, 500)
cleanupFn(() => clearTimeout(timer))
})
const timer = setTimeout(() => (progress.value = 100), 500);
cleanupFn(() => clearTimeout(timer));
});
</script>
<template>
<div v-if="bootingAnimation">
<div class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-0 ">
<Progress v-model="progress" class="w-3/5 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2" />
<br/>
<div
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-0"
>
<Progress
v-model="progress"
class="w-3/5 absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
/>
<br />
<span class="text-xl text-bold mt-3"
>Launching your fancy desktop...</span>
>Launching your fancy desktop...</span
>
</div>
</div>
<div
@ -307,15 +336,15 @@ watchEffect((cleanupFn) => {
</div>
</div>
<div class="flex flex-row gap-5">
<button
<button
class="p-1 hover:text-blue-200 transition-all duration-100 hover:bg-gray-500 rounded"
@click="toggleLangMenu"
>
{{ t("localeflag") }}
{{ t("localeflag") }}
</button>
<div class="text-center align-middle justify-center text-white">
{{ currentDate }}
</div>
<div class="text-center align-middle justify-center text-white">
{{ currentDate }}
</div>
</div>
</div>
<div class="w-full h-[2.5em]"></div>
@ -339,6 +368,26 @@ watchEffect((cleanupFn) => {
</div>
</div>
</Transition>
<Transition
enter-active-class="animate__animated animate__fadeInDown animate_fast03"
leave-active-class="animate__animated animate__fadeOutUp animate_fast03"
>
<div v-if="langMenuOpen">
<div
class="w-48 bg-white rounded-md shadow-lg py-1 flex flex-col gap-y-5"
>
<a
v-for="loc in availableLocales"
:key="loc.code"
:href="switchLocalePath(loc.code)"
v-on:click="langMenuOpen = false"
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-all duration-100"
>
{{ loc.name || loc.code }}
</a>
</div>
</div>
</Transition>
<!--Main desktop contents-->
<div
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-x-0 inset-y-0 z-[-10]"