mirror of
https://github.com/hpware/news-analyze.git
synced 2025-06-24 00:01:03 +08:00
feat: enhance UI components with improved styles and new windows; add error handling and copyright information
This commit is contained in:
parent
eaa9b15b2d
commit
1065a982b0
@ -76,13 +76,13 @@ const stopDrag = () => {
|
|||||||
<div class="flex flex-row gap-1">
|
<div class="flex flex-row gap-1">
|
||||||
<button
|
<button
|
||||||
@click="emit('min')"
|
@click="emit('min')"
|
||||||
class="p-1 hover:bg-gray-300 dark:hover:bg-gray-600 rounded"
|
class="p-1 hover:bg-gray-300 dark:hover:bg-gray-600 rounded transition duration-200"
|
||||||
>
|
>
|
||||||
━
|
━
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
@click="emit('maximize')"
|
@click="emit('maximize')"
|
||||||
class="p-1 hover:bg-gray-300 dark:hover:bg-gray-600 rounded"
|
class="p-1 hover:bg-gray-300 dark:hover:bg-gray-600 rounded transition duration-200"
|
||||||
>
|
>
|
||||||
⬜
|
⬜
|
||||||
</button>
|
</button>
|
||||||
|
13
components/app/info/copyright.vue
Normal file
13
components/app/info/copyright.vue
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
const { t } = useI18n();
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<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() }} © yh</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
2
components/app/windows/about.vue
Normal file
2
components/app/windows/about.vue
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<template>
|
||||||
|
</template>
|
10
components/app/windows/error404.vue
Normal file
10
components/app/windows/error404.vue
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<template>
|
||||||
|
<div class="justify-center align-center text-center flex flex-col">
|
||||||
|
<span class="text-7xl m-4 m-1 mb-0 text-center align-center justify-center"
|
||||||
|
>404</span
|
||||||
|
>
|
||||||
|
<span class="text-2xl text-center align-center justify-center"
|
||||||
|
>User interface Not Found</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</template>
|
@ -43,7 +43,7 @@ try {
|
|||||||
<ul v-for="ititit in itit">
|
<ul v-for="ititit in itit">
|
||||||
<li v-if="ititit.content?.[0].content[0] !== item.title">
|
<li v-if="ititit.content?.[0].content[0] !== item.title">
|
||||||
-
|
-
|
||||||
<a :href="ititit.content?.[0].attributes?.href">{{
|
<a :href="ititit.content?.[0].attributes?.href" target="_blank">{{
|
||||||
ititit.content?.[0].content[0]
|
ititit.content?.[0].content[0]
|
||||||
}}</a>
|
}}</a>
|
||||||
-
|
-
|
||||||
|
@ -20,7 +20,7 @@ const toggleDropdown = () => {
|
|||||||
class="fixed top-0 inset-x-0 bg-[#81611a]/70 backdrop-blur-sm h-[55px] flex align-center items-center flex-row text-white pl-4 gap-x-5 justify-between z-50 rounded-3xl m-2"
|
class="fixed top-0 inset-x-0 bg-[#81611a]/70 backdrop-blur-sm h-[55px] flex align-center items-center flex-row text-white pl-4 gap-x-5 justify-between z-50 rounded-3xl m-2"
|
||||||
>
|
>
|
||||||
<div class="text-3xl text-bold">
|
<div class="text-3xl text-bold">
|
||||||
<NuxtLink :to="localePath('home')" ref="title">BlindSpec</NuxtLink>
|
<NuxtLink :to="localePath('home')" ref="title">{{ t("core.sitename") }}</NuxtLink>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="text-[0.9em] left-1/2 absolute transform -translate-x-1/2 space-x-4 items-center"
|
class="text-[0.9em] left-1/2 absolute transform -translate-x-1/2 space-x-4 items-center"
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"nonMoving": "嗨!這是你的",
|
"nonMoving": "嗨!這是你的",
|
||||||
"moving": {
|
"moving": {
|
||||||
"newsPlatform": "新聞平台",
|
"newsPlatform": "新聞平台",
|
||||||
"miniWikipedia": "米你維基百科",
|
"miniWikipedia": "迷你維基百科",
|
||||||
"newsComparePlatform": "新聞觀點比對平台"
|
"newsComparePlatform": "新聞觀點比對平台"
|
||||||
},
|
},
|
||||||
"startusing": "開始使用!",
|
"startusing": "開始使用!",
|
||||||
|
@ -42,8 +42,8 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
|
|
||||||
site: {
|
site: {
|
||||||
url: "https://news.yuanhau.com",
|
url: "https://news.yuanhau.com/",
|
||||||
title: "BlindSpec",
|
title: "新聞盲點平台",
|
||||||
description: "",
|
description: "",
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "BlindSpec",
|
"name": "blindspec",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -30,6 +30,8 @@ gsap.registerPlugin(TextPlugin);
|
|||||||
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";
|
||||||
import SourcesWindow from "~/components/app/windows/sources.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 Shadcn/UI components
|
||||||
import AlertComponent from "~/components/ui/alert/Alert.vue";
|
import AlertComponent from "~/components/ui/alert/Alert.vue";
|
||||||
@ -62,6 +64,59 @@ const langMenuOpen = ref(false);
|
|||||||
const lang = ref(locale.value);
|
const lang = ref(locale.value);
|
||||||
const alertOpen = ref(false);
|
const alertOpen = ref(false);
|
||||||
const currentNavBar = ref<currentNavBarInterface[]>([]);
|
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
|
// Date
|
||||||
const currentDate = ref(
|
const currentDate = ref(
|
||||||
@ -105,14 +160,6 @@ const unMinWindow = (windowName?: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// menus
|
// 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 = () => {
|
const toggleMenu = () => {
|
||||||
menuOpen.value = !menuOpen.value;
|
menuOpen.value = !menuOpen.value;
|
||||||
};
|
};
|
||||||
@ -121,14 +168,7 @@ const toggleLangMenu = () => {
|
|||||||
langMenuOpen.value = !langMenuOpen.value;
|
langMenuOpen.value = !langMenuOpen.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// values
|
// ?openapp= component
|
||||||
const activeWindows = ref<associAppWindowInterface>([]);
|
|
||||||
|
|
||||||
// ?opemapp= component
|
|
||||||
const openApp = ref();
|
|
||||||
const openAppId = ref();
|
|
||||||
const openAppNameQuery = ref();
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
openApp.value = route.query.openapp;
|
openApp.value = route.query.openapp;
|
||||||
openAppId.value = route.query.id;
|
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 findAndOpenWindow = (windowName: string) => {
|
||||||
const app = associAppWindow.find((app) => app.name === windowName);
|
const app = associAppWindow.find((app) => app.name === windowName);
|
||||||
@ -168,6 +189,14 @@ const findAndOpenWindow = (windowName: string) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Prevent dual about
|
||||||
|
if (
|
||||||
|
windowName === "about" &&
|
||||||
|
activeWindows.value.some((window) => window.name === "about")
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (app) {
|
if (app) {
|
||||||
// Use shallowRef for better performance with components
|
// Use shallowRef for better performance with components
|
||||||
const windowComponent = shallowRef(app.component);
|
const windowComponent = shallowRef(app.component);
|
||||||
@ -201,13 +230,50 @@ const topWindow = (windowId: string) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Title
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title: "hi" + " - Desktop",
|
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>
|
</script>
|
||||||
<template>
|
<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
|
<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"
|
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-->
|
<!--Menu container-->
|
||||||
<div class="flex flex-row g-2 text-gray-400 text-white z-9999">
|
<div class="flex flex-row g-2 text-gray-400 text-white z-9999">
|
||||||
@ -240,10 +306,18 @@ useSeoMeta({
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="text-center align-middle justify-center text-white">
|
||||||
{{ currentDate }}
|
{{ currentDate }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div class="w-full h-[2.5em]"></div>
|
<div class="w-full h-[2.5em]"></div>
|
||||||
<!--Menu-->
|
<!--Menu-->
|
||||||
<Transition
|
<Transition
|
||||||
@ -291,39 +365,4 @@ useSeoMeta({
|
|||||||
</DraggableWindow>
|
</DraggableWindow>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</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
|
|
||||||
>
|
|
||||||
<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() }} © 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>
|
</template>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user