mirror of
https://github.com/hpware/news-analyze.git
synced 2025-06-23 21:14:23 +00:00
Clean the code via prettier.
This commit is contained in:
parent
57aa0aba18
commit
eaa9b15b2d
10 changed files with 177 additions and 165 deletions
|
@ -1,5 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useThrottleFn } from '@vueuse/core'
|
import { useThrottleFn } from "@vueuse/core";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
title: string;
|
title: string;
|
||||||
|
@ -10,44 +10,52 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const emit = defineEmits(["close", "min", "maximize", "restore"]);
|
const emit = defineEmits(["close", "min", "maximize", "restore"]);
|
||||||
const title = computed(() => props.title || 'Draggable Window');
|
const title = computed(() => props.title || "Draggable Window");
|
||||||
|
|
||||||
|
|
||||||
const isDragging = ref(false);
|
const isDragging = ref(false);
|
||||||
const position = ref({
|
const position = ref({
|
||||||
x: props.initialX || Math.floor(window.innerWidth / 2 - (parseInt(props.width || '400') / 2)),
|
x:
|
||||||
y: props.initialY || Math.floor(window.innerHeight / 2 - (parseInt(props.height || '300') / 2)),
|
props.initialX ||
|
||||||
|
Math.floor(window.innerWidth / 2 - parseInt(props.width || "400") / 2),
|
||||||
|
y:
|
||||||
|
props.initialY ||
|
||||||
|
Math.floor(window.innerHeight / 2 - parseInt(props.height || "300") / 2),
|
||||||
});
|
});
|
||||||
|
|
||||||
const offset = ref({ x: 0, y: 0 });
|
const offset = ref({ x: 0, y: 0 });
|
||||||
|
|
||||||
const doDrag = useThrottleFn((e: MouseEvent) => {
|
const doDrag = useThrottleFn((e: MouseEvent) => {
|
||||||
if (!isDragging.value) return
|
if (!isDragging.value) return;
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
position.value = {
|
position.value = {
|
||||||
x: Math.max(0, Math.min(window.innerWidth - 400, e.clientX - offset.value.x)),
|
x: Math.max(
|
||||||
y: Math.max(0, Math.min(window.innerHeight - 300, e.clientY - offset.value.y))
|
0,
|
||||||
}
|
Math.min(window.innerWidth - 400, e.clientX - offset.value.x),
|
||||||
})
|
),
|
||||||
|
y: Math.max(
|
||||||
|
0,
|
||||||
|
Math.min(window.innerHeight - 300, e.clientY - offset.value.y),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
}, 16);
|
}, 16);
|
||||||
|
|
||||||
|
|
||||||
const startDrag = (e: MouseEvent) => {
|
const startDrag = (e: MouseEvent) => {
|
||||||
isDragging.value = true
|
isDragging.value = true;
|
||||||
offset.value = {
|
offset.value = {
|
||||||
x: e.clientX - position.value.x,
|
x: e.clientX - position.value.x,
|
||||||
y: e.clientY - position.value.y
|
y: e.clientY - position.value.y,
|
||||||
}
|
};
|
||||||
document.addEventListener('mousemove', doDrag)
|
document.addEventListener("mousemove", doDrag);
|
||||||
document.addEventListener('mouseup', stopDrag)
|
document.addEventListener("mouseup", stopDrag);
|
||||||
}
|
};
|
||||||
|
|
||||||
const stopDrag = () => {
|
const stopDrag = () => {
|
||||||
isDragging.value = false
|
isDragging.value = false;
|
||||||
document.removeEventListener('mousemove', doDrag)
|
document.removeEventListener("mousemove", doDrag);
|
||||||
document.removeEventListener('mouseup', stopDrag)
|
document.removeEventListener("mouseup", stopDrag);
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -11,7 +11,6 @@ try {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -3,36 +3,36 @@ import sha512 from "crypto-js/sha512";
|
||||||
const userAccount = ref("");
|
const userAccount = ref("");
|
||||||
const userPassword = ref("");
|
const userPassword = ref("");
|
||||||
const submitUserPassword = async () => {
|
const submitUserPassword = async () => {
|
||||||
// Encrypt password during transit
|
// Encrypt password during transit
|
||||||
const password = sha512(userPassword.value).toString();
|
const password = sha512(userPassword.value).toString();
|
||||||
|
|
||||||
// Send data.
|
// Send data.
|
||||||
const sendData = await fetch("/api/user/login", {
|
const sendData = await fetch("/api/user/login", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
username: userAccount.value,
|
username: userAccount.value,
|
||||||
password: password,
|
password: password,
|
||||||
}),
|
}),
|
||||||
})
|
});
|
||||||
const res = await sendData.json();
|
const res = await sendData.json();
|
||||||
|
|
||||||
if (res.status === "ok") {
|
if (res.status === "ok") {
|
||||||
// Store the token in local storage
|
// Store the token in local storage
|
||||||
localStorage.setItem("token", res.token);
|
localStorage.setItem("token", res.token);
|
||||||
// Redirect to the home page
|
// Redirect to the home page
|
||||||
window.location.href = "/";
|
window.location.href = "/";
|
||||||
success.value = true;
|
success.value = true;
|
||||||
} else {
|
} else {
|
||||||
alert("Login failed");
|
alert("Login failed");
|
||||||
error.value = true;
|
error.value = true;
|
||||||
}
|
}
|
||||||
// Clear the input fields
|
// Clear the input fields
|
||||||
userAccount.value = "";
|
userAccount.value = "";
|
||||||
userPassword.value = "";
|
userPassword.value = "";
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col items-center justify-center h-full">
|
<div class="flex flex-col items-center justify-center h-full">
|
||||||
|
|
|
@ -1,22 +1,26 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
const { t, locale } = useI18n();
|
const { t, locale } = useI18n();
|
||||||
|
|
||||||
const { data: source, pending, error } = await useFetch("/api/getData/fetchSources", {
|
const {
|
||||||
method: "POST",
|
data: source,
|
||||||
headers: {
|
pending,
|
||||||
"Content-Type": "application/json",
|
error,
|
||||||
},
|
} = await useFetch("/api/getData/fetchSources", {
|
||||||
body: {
|
method: "POST",
|
||||||
lang: locale,
|
headers: {
|
||||||
},
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
lang: locale,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div >
|
<div>
|
||||||
<div v-for="item in source?.data" :key="item.id">
|
<div v-for="item in source?.data" :key="item.id">
|
||||||
<h1>{{ item.title }}</h1>
|
<h1>{{ item.title }}</h1>
|
||||||
<span>{{ item.description }}</span>
|
<span>{{ item.description }}</span>
|
||||||
<a :href="item.url">{{ item.url }}</a>
|
<a :href="item.url">{{ item.url }}</a>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</div>
|
||||||
|
</template>
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
"startusing": "開始使用!",
|
"startusing": "開始使用!",
|
||||||
"learnmore": "了解更多",
|
"learnmore": "了解更多",
|
||||||
"whydes": "台灣的新聞是要痲是來自中國控制的媒體,或是來自只想獲得點閱的記者。",
|
"whydes": "台灣的新聞是要痲是來自中國控制的媒體,或是來自只想獲得點閱的記者。",
|
||||||
"howdes":" 我們使用使用 Python 寫的網頁爬蟲來搜尋最新的新聞,並將其存入Postgres資料庫中。"
|
"howdes": " 我們使用使用 Python 寫的網頁爬蟲來搜尋最新的新聞,並將其存入Postgres資料庫中。"
|
||||||
},
|
},
|
||||||
"dailybriefing": "今日報導",
|
"dailybriefing": "今日報導",
|
||||||
"Welcome": "歡迎",
|
"Welcome": "歡迎",
|
||||||
|
|
|
@ -135,7 +135,7 @@ onMounted(async () => {
|
||||||
if (openApp.value) {
|
if (openApp.value) {
|
||||||
openWindow(openApp.value);
|
openWindow(openApp.value);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const associAppWindow = [
|
const associAppWindow = [
|
||||||
{
|
{
|
||||||
|
@ -146,25 +146,32 @@ const associAppWindow = [
|
||||||
width: "700px",
|
width: "700px",
|
||||||
height: "500px",
|
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: "sources",
|
||||||
|
id: "3",
|
||||||
|
title: t("app.sources"),
|
||||||
|
component: SourcesWindow,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const currentOpenAppId = ref(0);
|
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);
|
||||||
|
|
||||||
// Prevent dual logins
|
// Prevent dual logins
|
||||||
if (windowName === "login" &&
|
if (
|
||||||
activeWindows.value.some((window) => window.name === "login")) {
|
windowName === "login" &&
|
||||||
return
|
activeWindows.value.some((window) => window.name === "login")
|
||||||
|
) {
|
||||||
|
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);
|
||||||
|
|
||||||
activeWindows.value.push({
|
activeWindows.value.push({
|
||||||
id: currentOpenAppId.value,
|
id: currentOpenAppId.value,
|
||||||
component: windowComponent,
|
component: windowComponent,
|
||||||
|
@ -172,10 +179,10 @@ const findAndOpenWindow = (windowName: string) => {
|
||||||
title: app.title,
|
title: app.title,
|
||||||
width: app.width || "400px",
|
width: app.width || "400px",
|
||||||
height: app.height || "300px",
|
height: app.height || "300px",
|
||||||
})
|
});
|
||||||
currentOpenAppId.value++;
|
currentOpenAppId.value++;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const closeWindow = (windowId: string) => {
|
const closeWindow = (windowId: string) => {
|
||||||
activeWindows.value = activeWindows.value.filter(
|
activeWindows.value = activeWindows.value.filter(
|
||||||
|
@ -196,7 +203,7 @@ const topWindow = (windowId: string) => {
|
||||||
|
|
||||||
useSeoMeta({
|
useSeoMeta({
|
||||||
title: "hi" + " - Desktop",
|
title: "hi" + " - Desktop",
|
||||||
})
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
@ -263,27 +270,27 @@ useSeoMeta({
|
||||||
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-x-0 inset-y-0 z-[-10]"
|
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-x-0 inset-y-0 z-[-10]"
|
||||||
id="desktop"
|
id="desktop"
|
||||||
></div>
|
></div>
|
||||||
<Transition>
|
<Transition>
|
||||||
<div>
|
<div>
|
||||||
<DraggableWindow
|
<DraggableWindow
|
||||||
v-for="window in activeWindows"
|
v-for="window in activeWindows"
|
||||||
:key="window.id"
|
:key="window.id"
|
||||||
:title="window.title"
|
:title="window.title"
|
||||||
@close="closeWindow(window.id)"
|
@close="closeWindow(window.id)"
|
||||||
@min="unMinWindow(window.id)"
|
@min="unMinWindow(window.id)"
|
||||||
:width="window.width"
|
:width="window.width"
|
||||||
:height="window.height"
|
:height="window.height"
|
||||||
@clicked="topWindow(window.id)"
|
@clicked="topWindow(window.id)"
|
||||||
>
|
>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<Component
|
<Component
|
||||||
:is="window.component"
|
:is="window.component"
|
||||||
@error="console.error('Error:', $event)"
|
@error="console.error('Error:', $event)"
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</DraggableWindow>
|
</DraggableWindow>
|
||||||
</div>
|
</div>
|
||||||
</Transition>
|
</Transition>
|
||||||
<!--Footer-->
|
<!--Footer-->
|
||||||
<div
|
<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"
|
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"
|
||||||
|
@ -319,4 +326,4 @@ useSeoMeta({
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="justify-center align-center text-center">
|
<div class="justify-center align-center text-center">
|
||||||
<span class="text-6xl text-bold">目前沒有手機版本</span>
|
<span class="text-6xl text-bold">目前沒有手機版本</span>
|
||||||
<span class="text-xl">請使用電腦版</span>
|
<span class="text-xl">請使用電腦版</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -78,18 +78,14 @@ onMounted(() => {
|
||||||
>
|
>
|
||||||
<h1 class="text-8xl mt-0">🤔</h1>
|
<h1 class="text-8xl mt-0">🤔</h1>
|
||||||
<h2 class="text-xl font-bold">Why?</h2>
|
<h2 class="text-xl font-bold">Why?</h2>
|
||||||
<span class="text-sm"
|
<span class="text-sm">{{ t("home.whydes") }}</span>
|
||||||
>{{ t("home.whydes")}}</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col justify-center items-center align-middle bg-[#C9C9C9]/60 rounded-xl shadow-lg p-5 m-5 w-[300px] h-[200px]"
|
class="flex flex-col justify-center items-center align-middle bg-[#C9C9C9]/60 rounded-xl shadow-lg p-5 m-5 w-[300px] h-[200px]"
|
||||||
>
|
>
|
||||||
<h1 class="text-8xl mt-0">🧐</h1>
|
<h1 class="text-8xl mt-0">🧐</h1>
|
||||||
<h2 class="text-xl font-bold">How?</h2>
|
<h2 class="text-xl font-bold">How?</h2>
|
||||||
<span class="text-sm"
|
<span class="text-sm">{{ t("home.howdes") }}</span>
|
||||||
>{{ t("home.howdes")}}</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br />
|
<br />
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
import sql from "~/server/components/postgres";
|
import sql from "~/server/components/postgres";
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const body = await readBody(event);
|
const body = await readBody(event);
|
||||||
const query = getQuery(event);
|
const query = getQuery(event);
|
||||||
/*const sources = await sql`SELECT * FROM sources`;
|
/*const sources = await sql`SELECT * FROM sources`;
|
||||||
return sources;*/
|
return sources;*/
|
||||||
// Fake data
|
// Fake data
|
||||||
return {
|
return {
|
||||||
status: "ok",
|
status: "ok",
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
title: "Source 1",
|
title: "Source 1",
|
||||||
url: "https://source1.com",
|
url: "https://source1.com",
|
||||||
description: "Description for Source 1",
|
description: "Description for Source 1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
title: "Source 2",
|
title: "Source 2",
|
||||||
url: "https://source2.com",
|
url: "https://source2.com",
|
||||||
description: "Description for Source 2",
|
description: "Description for Source 2",
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
};
|
||||||
})
|
});
|
||||||
|
|
|
@ -1,36 +1,34 @@
|
||||||
import sql from "~/server/components/postgres";
|
import sql from "~/server/components/postgres";
|
||||||
import argon2 from "argon2";
|
import argon2 from "argon2";
|
||||||
export default defineEventHandler(async (event) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const salt = process.env.PASSWORD_HASH_SALT;
|
const salt = process.env.PASSWORD_HASH_SALT;
|
||||||
if (!salt) {
|
if (!salt) {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 500,
|
statusCode: 500,
|
||||||
message: 'Internal server error'
|
message: "Internal server error",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const body = await readBody(event);
|
const body = await readBody(event);
|
||||||
const { username, password } = body;
|
const { username, password } = body;
|
||||||
if (!username || !password) {
|
if (!username || !password) {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
message: 'Username and password are required'
|
message: "Username and password are required",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const USERNAME_PATTERN = /^[a-zA-Z0-9_]{3,20}$/;
|
const USERNAME_PATTERN = /^[a-zA-Z0-9_]{3,20}$/;
|
||||||
if (!USERNAME_PATTERN.test(username)) {
|
if (!USERNAME_PATTERN.test(username)) {
|
||||||
throw createError({
|
throw createError({
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
message: 'Invalid username.'
|
message: "Invalid username.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Server side hashing
|
// Server side hashing
|
||||||
const hashedPassword = await argon2.hash(salt, password);
|
const hashedPassword = await argon2.hash(salt, password);
|
||||||
|
|
||||||
// Check if user exists, if not, create a user
|
// Check if user exists, if not, create a user
|
||||||
try {
|
try {
|
||||||
console.log(username);
|
console.log(username);
|
||||||
console.log(hashedPassword);
|
console.log(hashedPassword);
|
||||||
} catch (e) {
|
} catch (e) {}
|
||||||
|
});
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue