mirror of
https://github.com/hpware/news-analyze.git
synced 2025-06-24 00:01:03 +08:00
feat: refactor login and hot news components; integrate DraggableWindow for dynamic window management in desktop layout
This commit is contained in:
parent
163f613058
commit
542a22f168
@ -13,7 +13,6 @@ try {
|
|||||||
const title = ref("Hot News");
|
const title = ref("Hot News");
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<DraggableWindow :title="title" width="600px" height="400px">
|
|
||||||
<div
|
<div
|
||||||
v-for="item in ffeed"
|
v-for="item in ffeed"
|
||||||
class="justify-center align-center text-center p-4 border border-black rounded-lg m-4"
|
class="justify-center align-center text-center p-4 border border-black rounded-lg m-4"
|
||||||
@ -62,5 +61,5 @@ const title = ref("Hot News");
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div> </DraggableWindow>
|
</div>
|
||||||
</template>
|
</template>
|
@ -1,10 +1,5 @@
|
|||||||
<script setup lang="ts">
|
|
||||||
import DraggableWindow from "~/components/DraggableWindow.vue";
|
|
||||||
|
|
||||||
const title = ref("Login");
|
|
||||||
</script>
|
|
||||||
<template>
|
<template>
|
||||||
<DraggableWindow :title="title">
|
|
||||||
<div class="flex flex-col items-center justify-center h-full">
|
<div class="flex flex-col items-center justify-center h-full">
|
||||||
<form class="flex flex-col items-center justify-center h-full">
|
<form class="flex flex-col items-center justify-center h-full">
|
||||||
<div class="text-xl mb-4 text-bold">Login / Register</div>
|
<div class="text-xl mb-4 text-bold">Login / Register</div>
|
||||||
@ -16,5 +11,4 @@ const title = ref("Login");
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</DraggableWindow>
|
|
||||||
</template>
|
</template>
|
@ -1,15 +1,118 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
// Imports
|
// No layout
|
||||||
|
definePageMeta({
|
||||||
|
layout: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
// interfaces
|
||||||
|
interface currentNavBarInterface {
|
||||||
|
name: string;
|
||||||
|
icon: string;
|
||||||
|
action: any;
|
||||||
|
flash: boolean;
|
||||||
|
windowAssociated: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import plugins
|
||||||
|
import { gsap } from "gsap";
|
||||||
|
import { TextPlugin } from "gsap/TextPlugin";
|
||||||
|
import { createApp } from "vue";
|
||||||
|
gsap.registerPlugin(TextPlugin);
|
||||||
|
|
||||||
|
// Import Windows
|
||||||
import LoginWindow from "~/components/app/windows/login.vue";
|
import LoginWindow from "~/components/app/windows/login.vue";
|
||||||
import HotNewsWindow from "~/components/app/windows/hotnews.vue";
|
import HotNewsWindow from "~/components/app/windows/hotnews.vue";
|
||||||
|
|
||||||
definePageMeta({
|
// Import Shadcn/UI components
|
||||||
layout: "macui",
|
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, UserIcon, LanguageIcon, ChevronRightIcon } from "@heroicons/vue/24/outline";
|
||||||
|
|
||||||
|
// i18n
|
||||||
|
const { t, locale, locales } = useI18n();
|
||||||
|
const switchLocalePath = useSwitchLocalePath();
|
||||||
|
const localePath = useLocalePath();
|
||||||
|
|
||||||
// Router
|
// Router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
|
// values
|
||||||
|
const popMessage = ref(null);
|
||||||
|
const menuOpen = ref(false);
|
||||||
|
const langMenuOpen = ref(false);
|
||||||
|
const lang = ref(locale.value);
|
||||||
|
const alertOpen = ref(false);
|
||||||
|
const currentNavBar = ref<currentNavBarInterface[]>([]);
|
||||||
|
|
||||||
|
// Date
|
||||||
|
const currentDate = ref(
|
||||||
|
new Date().toLocaleDateString("zh-TW", {
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
hour12: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
onMounted(() => {
|
||||||
|
setInterval(() => {
|
||||||
|
currentDate.value = new Date().toLocaleDateString("zh-TW", {
|
||||||
|
month: "2-digit",
|
||||||
|
day: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
second: "2-digit",
|
||||||
|
hour12: false,
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
// functions
|
||||||
|
const openWindow = (windowName?: string) => {
|
||||||
|
if (windowName === "leave") {
|
||||||
|
router.push(localePath("/home"));
|
||||||
|
} else {
|
||||||
|
if (windowName) findAndOpenWindow(windowName);
|
||||||
|
}
|
||||||
|
console.log(windowName);
|
||||||
|
menuOpen.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unMinWindow = (windowName?: string) => {
|
||||||
|
console.log(windowName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
// Lang Menu
|
||||||
|
const toggleLangMenu = () => {
|
||||||
|
langMenuOpen.value = !langMenuOpen.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// values
|
||||||
|
const activeWindows = ref();
|
||||||
|
|
||||||
// ?opemapp= component
|
// ?opemapp= component
|
||||||
const openApp = ref(false);
|
const openApp = ref(false);
|
||||||
const openAppId = ref();
|
const openAppId = ref();
|
||||||
@ -17,17 +120,123 @@ watch(() => route.query.openapp, (newVal) => {
|
|||||||
if (newVal) {
|
if (newVal) {
|
||||||
openApp.value = true;
|
openApp.value = true;
|
||||||
openAppId.value = newVal;
|
openAppId.value = newVal;
|
||||||
// Remove query parameter without page reload
|
console.log("openAppId", openAppId.value);
|
||||||
router.replace({
|
router.replace({
|
||||||
path: route.path,
|
path: route.path,
|
||||||
query: {},
|
query: {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const associAppWindow = [
|
||||||
|
{ name: "hotnews", component: HotNewsWindow },
|
||||||
|
{ name: "login", component: LoginWindow },
|
||||||
|
]
|
||||||
|
|
||||||
|
const findAndOpenWindow = (windowName: string) => {
|
||||||
|
const app = associAppWindow.find((app) => app.name === windowName);
|
||||||
|
console.log("app", app);
|
||||||
|
console.log("windowName", windowName);
|
||||||
|
console.log("activeWindows.value", activeWindows.value);
|
||||||
|
console.log("associAppWindow", associAppWindow);
|
||||||
|
if (app) {
|
||||||
|
activeWindows.value.push({
|
||||||
|
id: `${windowName}-${Date.now()}`,
|
||||||
|
component: app.component,
|
||||||
|
title: windowName
|
||||||
|
});
|
||||||
|
console.log("html.value", activeWindows.value);
|
||||||
|
} else {
|
||||||
|
console.error("Window not found");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const closeWindow = (windowId: string) => {
|
||||||
|
activeWindows.value = activeWindows.value.filter((window) => window.id !== windowId);
|
||||||
|
console.log("activeWindows.value", activeWindows.value);
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div
|
||||||
<LoginWindow data-app-id="login" />
|
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"
|
||||||
<HotNewsWindow data-app-id="hotnews" />
|
>
|
||||||
|
<!--Menu container-->
|
||||||
|
<div class="flex flex-row g-2 text-gray-400 text-white z-9999">
|
||||||
|
<button @click="toggleMenu" class="w-8 h-8 text-white hover:text-blue-500 transition-all duration-100 flex flex-row">
|
||||||
|
<ComputerDesktopIcon/>
|
||||||
|
</button>
|
||||||
|
<span class="ml-1 mr-2 text-[20px]">|</span>
|
||||||
|
<!--navbar icons for min and max application window-->
|
||||||
|
<button
|
||||||
|
class="flex flex-row items-center gap-x-2 text-gray-400 hover:text-gray-600 transition-all duration-100"
|
||||||
|
>
|
||||||
|
</button>
|
||||||
|
<div v-for="item in currentNavBar" :key="item.name" class="flex flex-row items-center gap-x-2 hover:bg-gray-100 transition-all duration-100 px-4 py-2 cursor-pointer">
|
||||||
|
<button @click="unMinWindow(item.windowAssociated)" class="flex flex-row items-center gap-x-2 text-gray-400 hover:text-gray-600 transition-all duration-100">
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<span v-if="item.flash" class="animate-ping absolute inline-flex h-3 w-3 rounded-full bg-red-400 opacity-75"></span>
|
||||||
|
<span v-if="item.icon" :class="item.icon">
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center align-middle justify-center text-white">{{ currentDate }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
<div class="w-full h-[2.5em]"></div>
|
||||||
|
<!--Menu-->
|
||||||
|
<Transition
|
||||||
|
enter-active-class="animate__animated animate__fadeInDown animate_fast03"
|
||||||
|
leave-active-class="animate__animated animate__fadeOutUp animate_fast03"
|
||||||
|
>
|
||||||
|
<div class="m-2 p-2 bg-gray-800 shadow-lg w-fit rounded-[10px] v-9998" v-if="menuOpen">
|
||||||
|
<div v-for="item in menuItems" :key="item.name" class="">
|
||||||
|
<button @click="openWindow(item.windowName)" class="flex flex-row items-center gap-x-2 text-gray-400 hover:text-gray-600 transition-all duration-100">
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<ChevronRightIcon class="w-4 h-4 justify-center align-center" />
|
||||||
|
</button>
|
||||||
|
</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-[-1]"
|
||||||
|
id="desktop"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<DraggableWindow
|
||||||
|
v-for="window in activeWindows"
|
||||||
|
:key="window.id"
|
||||||
|
:title="window.title"
|
||||||
|
@close="closeWindow(window.id)"
|
||||||
|
>
|
||||||
|
<component :is="window.component" />
|
||||||
|
</DraggableWindow>
|
||||||
|
</div>
|
||||||
|
<!--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"
|
||||||
|
>
|
||||||
|
<div class="">
|
||||||
|
<!--Lang-->
|
||||||
|
<span>Lang: </span>
|
||||||
|
<span class="text-lg">{{ t("localeflag") }}</span>
|
||||||
|
<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 License</span>
|
||||||
|
<span class="text-sm">|</span>
|
||||||
|
<span class="text-sm">{{ new Date().getFullYear() }} © 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>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user