feat: enhance UI components with improved styles and new windows; add error handling and copyright information

This commit is contained in:
yuanhau 2025-05-12 23:05:42 +08:00
parent eaa9b15b2d
commit 1065a982b0
10 changed files with 142 additions and 78 deletions

View file

@ -30,6 +30,8 @@ gsap.registerPlugin(TextPlugin);
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 Error404Window from "~/components/app/windows/error404.vue";
// Import Shadcn/UI components
import AlertComponent from "~/components/ui/alert/Alert.vue";
@ -62,6 +64,59 @@ const langMenuOpen = ref(false);
const lang = ref(locale.value);
const alertOpen = ref(false);
const currentNavBar = ref<currentNavBarInterface[]>([]);
const bootingAnimation = ref(true);
const bypassBoot = ref(false);
const activeWindows = ref<associAppWindowInterface>([]);
const openApp = ref();
const openAppId = ref();
const openAppNameQuery = ref();
const currentOpenAppId = ref(0);
const progress = ref(0);
// Key Data
const menuItems = [
{ name: t("app.hotnews"), windowName: "hotnews" },
{ name: t("app.news"), windowName: "news" },
{ name: t("app.sources"), windowName: "sources" },
{ name: t("app.starred"), windowName: "starred" },
{ name: t("app.about"), windowName: "about" },
{ name: t("app.settings"), windowName: "settings" },
{ name: t("app.login"), windowName: "login" },
{ name: t("app.leave"), windowName: "leave" },
];
const associAppWindow = [
{
name: "hotnews",
id: "1",
title: t("app.hotnews"),
component: HotNewsWindow,
width: "700px",
height: "500px",
},
{ 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: "settings",
id: "5",
title: t("app.settings"),
component: Error404Window,
},
{ name: "news", id: "6", title: t("app.news"), component: Error404Window },
{
name: "starred",
id: "7",
title: t("app.starred"),
component: Error404Window,
},
];
// Date
const currentDate = ref(
@ -105,14 +160,6 @@ const unMinWindow = (windowName?: string) => {
};
// menus
const menuItems = [
{ name: "Hot News", windowName: "hotnews" },
{ name: "News", windowName: "news" },
{ name: "Sources", windowName: "sources" },
{ name: "About This Website", windowName: "about" },
{ name: "Settings", windowName: "settings" },
{ name: "Leave", windowName: "leave" },
];
const toggleMenu = () => {
menuOpen.value = !menuOpen.value;
};
@ -121,14 +168,7 @@ const toggleLangMenu = () => {
langMenuOpen.value = !langMenuOpen.value;
};
// values
const activeWindows = ref<associAppWindowInterface>([]);
// ?opemapp= component
const openApp = ref();
const openAppId = ref();
const openAppNameQuery = ref();
// ?openapp= component
onMounted(async () => {
openApp.value = route.query.openapp;
openAppId.value = route.query.id;
@ -137,25 +177,6 @@ onMounted(async () => {
}
});
const associAppWindow = [
{
name: "hotnews",
id: "1",
title: "Hot News",
component: HotNewsWindow,
width: "700px",
height: "500px",
},
{ name: "login", id: "2", title: t("app.login"), component: LoginWindow },
{
name: "sources",
id: "3",
title: t("app.sources"),
component: SourcesWindow,
},
];
const currentOpenAppId = ref(0);
const findAndOpenWindow = (windowName: string) => {
const app = associAppWindow.find((app) => app.name === windowName);
@ -168,6 +189,14 @@ const findAndOpenWindow = (windowName: string) => {
return;
}
// Prevent dual about
if (
windowName === "about" &&
activeWindows.value.some((window) => window.name === "about")
) {
return;
}
if (app) {
// Use shallowRef for better performance with components
const windowComponent = shallowRef(app.component);
@ -201,13 +230,50 @@ const topWindow = (windowId: string) => {
}
};
// Title
useSeoMeta({
title: "hi" + " - Desktop",
});
// Booting animation
onMounted(() => {
// booting animation bypass
const bootingHeaderParams = route.query.bypass;
if (bootingHeaderParams) {
bypassBoot.value = true;
console.log("Bypass booting animation");
}
if (!bypassBoot.value) {
gsap.to(popMessage.value, {
duration: 0.5,
text: t("app.booting"),
ease: "none",
});
setTimeout(() => {
bootingAnimation.value = false;
}, 2000);
} else {
bootingAnimation.value = false;
}
})
watchEffect((cleanupFn) => {
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/>
<span class="text-xl text-bold mt-3"
>Launching your fancy desktop...</span>
</div>
</div>
<div
class="absolute inset-x-0 flex flex-row px-2 py-1 bg-[#7D7C7C]/70 text-white justify-between align-center text-center z-50"
v-else
>
<!--Menu container-->
<div class="flex flex-row g-2 text-gray-400 text-white z-9999">
@ -240,9 +306,17 @@ useSeoMeta({
</button>
</div>
</div>
<div class="flex flex-row gap-5">
<button
class="p-1 hover:text-blue-200 transition-all duration-100 hover:bg-gray-500 rounded"
@click="toggleLangMenu"
>
{{ t("localeflag") }}
</button>
<div class="text-center align-middle justify-center text-white">
{{ currentDate }}
</div>
</div>
</div>
<div class="w-full h-[2.5em]"></div>
<!--Menu-->
@ -291,39 +365,4 @@ useSeoMeta({
</DraggableWindow>
</div>
</Transition>
<!--Footer-->
<div
class="absolute w-[calc(100% - 5px)] inset-x-0 bottom-0 mx-[1.5px] p-3 justify-between align-center flex flex-row z-0"
>
<div class="">
<!--Lang-->
<span>Lang: </span>
<span class="text-lg">{{ t("localeflag") }}</span
>&nbsp;
<button
class="w-4 h-4 hover:text-blue-200 transition-all duration-100"
@click="toggleLangMenu"
>
<LanguageIcon />
</button>
</div>
<div class="gap-2 flex flex-row">
<!--版權資訊-->
<span class="text-sm">1.0.0</span>
<span class="text-sm">|</span>
<span class="text-sm">MIT {{ t("app.license") }}</span>
<span class="text-sm">|</span>
<span class="text-sm">{{ new Date().getFullYear() }} &copy yh</span>
</div>
<div class="">
<button
@click="openWindow('login')"
class="w-8 h-8 text-gray-400 flex flex-row"
>
<UserIcon
class="w-8 h-8 text-gray-400 hover:text-blue-500 transition-all duration-100"
/>
</button>
</div>
</div>
</template>