Tried to add keyboard shortcuts, it's awful... feat: add terminal window component and about news organization window; update localization for terminal; refactor database connection in hot_articles.py; remove sources.vue

This commit is contained in:
吳元皓 2025-05-13 16:33:06 +08:00
parent 5d77b2770d
commit 4c7f9b47d0
8 changed files with 151 additions and 11 deletions

View File

@ -32,6 +32,7 @@ App Design: [Freeform](https://www.icloud.com/freeform/026AxB798cViZ9jJ2DkNsXUCQ
- juice website
- MacOS
- Windows XP style X - UI
- Ghostty
## Stack:

View File

@ -0,0 +1,73 @@
<script setup lang="ts">
import { GlobeAltIcon } from "@heroicons/vue/24/outline";
import { gsap } from "gsap";
import { ScrambleTextPlugin } from "gsap/dist/ScrambleTextPlugin";
gsap.registerPlugin(ScrambleTextPlugin);
const loading = ref(true);
const { t, locale } = useI18n();
const props = defineProps({
values: {
type: String,
required: true,
}
});
const {
data: fetchNewsOrgInfo,
pending,
error,
} = useFetch("/api/getData/fetchNewsOrgInfo", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: {
lang: locale,
requestPage: props.values,
},
});
const orgNameAnimation = ref(null);
onMounted(() => {
gsap.to(orgNameAnimation.value, {
duration: 1,
scrambleText: fetchNewsOrgInfo.value?.title,
});
});
</script>
<template>
<div>
<div class="text-center align-center justify-center">
<div
class="flex flex-row bg-[#AAACAAFF] rounded-3xl p-3 gap-3 m-3 scale-5"
>
<NuxtImg
:src="fetchNewsOrgInfo?.logoUrl"
class="w-48 h-48 rounded-[10px]"
/>
<div class="flex flex-col gap-3 text-left">
<h1 class="text-4xl font-bold m-3 text-left">
{{ fetchNewsOrgInfo?.title }}
</h1>
<span class="text-ms m-1 mt-5 text-left text-wrap">{{
fetchNewsOrgInfo?.description
}}</span>
</div>
</div>
<div
class="gap-[3px] flex flex-row text-center align-center justify-center"
>
<a
:href="fetchNewsOrgInfo?.website"
target="_blank"
class="text-blue-200 hover:text-blue-300 transiton-all duration-100 flex flex-row"
><GlobeAltIcon class="w-6 h-6" />網站</a
>
</div>
</div>
</div>
</template>

View File

@ -0,0 +1,3 @@
<template>
</template>

View File

@ -59,6 +59,7 @@
"license": "License",
"search": "Search",
"chatbot": "Chatbot",
"starred": "Starred"
"starred": "Starred",
"terminal": "Terminal"
}
}

View File

@ -59,6 +59,7 @@
"license": "授權",
"search": "搜尋",
"chatbot": "聊天機器人",
"starred": "收藏"
"starred": "收藏",
"terminal": "終端機"
}
}

View File

@ -23,7 +23,6 @@ interface associAppWindowInterface {
// Import plugins
import { gsap } from "gsap";
import { TextPlugin } from "gsap/TextPlugin";
import { createApp } from "vue";
gsap.registerPlugin(TextPlugin);
// Import Windows
@ -32,6 +31,7 @@ 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 AboutNewsOrgWindow from "~/components/app/windows/aboutNewsOrg.vue";
import Error404Window from "~/components/app/windows/error404.vue";
// Icons
@ -59,7 +59,7 @@ const lang = ref(locale.value);
const alertOpen = ref(false);
const currentNavBar = ref<currentNavBarInterface[]>([]);
const bootingAnimation = ref(true);
const activeWindows = ref<associAppWindowInterface>([]);
const activeWindows = ref<associAppWindowInterface[]>([]);
const openApp = ref();
const openAppId = ref();
const openAppNameQuery = ref();
@ -67,6 +67,7 @@ const currentOpenAppId = ref(0);
const progress = ref(0);
const titleAppName = ref("Desktop");
const openingAppViaAnApp = ref(false);
const passedValues = ref();
// Key Data
const menuItems = [
@ -76,6 +77,7 @@ const menuItems = [
{ name: t("app.starred"), windowName: "starred" },
{ name: t("app.chatbot"), windowName: "chatbot" },
{ name: t("app.about"), windowName: "about" },
{ name: t("app.terminal"), windowName: "tty" },
{ name: t("app.settings"), windowName: "settings" },
{ name: t("app.login"), windowName: "login" },
{ name: t("app.leave"), windowName: "leave" },
@ -142,8 +144,67 @@ const associAppWindow = [
title: t("app.error404"),
component: Error404Window,
},
{
name: "aboutNewsOrg",
id: "10",
title: t("app.aboutNewsOrg"),
component: AboutNewsOrgWindow,
},
{
name: "tty",
id: "11",
title: t("app.terminal"),
component: Error404Window,
}
];
/*
const keyboardShortcuts = {
'Meta+k': {
action: () => toggleMenu(),
description: 'Toggle menu'
},
'Meta+q': {
action: () => router.push(localePath("/home")),
description: 'Quit to home'
},
'Meta+w': {
action: () => closeWindow(activeWindows.value[activeWindows.value.length - 1]?.id),
description: 'Close current window'
},
'Meta+t': {
action: () => findAndOpenWindow('tty'),
description: 'Open terminal'
},
}
// Keyboard shortcuts
const handleKeyboardActions = (e: KeyboardEvent) => {
const key = [
e.metaKey ? "Meta": "",
e.ctrlKey ? "Ctrl": "",
e.shiftKey ? "Shift": "",
e.altKey ? "Alt": "",
e.key.toLowerCase()
].filter(Boolean).join('+')
const shortcut = keyboardShortcuts[key];
if (shortcut) {
console.log(`Shortcut triggered: ${key}`);
e.preventDefault()
shortcut.action()
}
}
onMounted(() => {
window.addEventListener('keydown', handleKeyboardActions)
});
onUnmounted(() => {
window.removeEventListener('keydown', handleKeyboardActions)
});
*/
// Date
const currentDate = ref(
new Date().toLocaleDateString("zh-TW", {
@ -430,6 +491,7 @@ watchEffect((cleanupFn) => {
:is="window.component"
@error="console.error('Error:', $event)"
@windowopener="openNewWindowViaApp($event)"
:values="passedValues"
/>
</Suspense>
</DraggableWindow>

View File

@ -1 +0,0 @@
<template>1. Yahoo RSS Api 2. Google News Search</template>

View File

@ -12,12 +12,12 @@ dotenv.load_dotenv()
# Connect to PostgresDB
#conn = psycopg2.connect(database=os.getenv("POSTGRES_DB"),
# user=os.getenv("POSTGRES_USER"),
# password=os.getenv("POSTGRES_PASSWORD"),
# host=os.getenv("POSTGRES_HOST"),
# port=os.getenv("POSTGRES_PORT")
#)
conn = psycopg2.connect(database=os.getenv("POSTGRES_DB"),
user=os.getenv("POSTGRES_USER"),
password=os.getenv("POSTGRES_PASSWORD"),
host=os.getenv("POSTGRES_HOST"),
port=os.getenv("POSTGRES_PORT")
)
headers = {
'User-Agent': 'NewsSceraperBot/1.0 (https://github.com/hpware/news-analyze)'