Clean the awful code.

This commit is contained in:
yuanhau 2025-05-07 10:53:14 +08:00
parent 98ffbec764
commit 569cd087e7
15 changed files with 193 additions and 167 deletions

View file

@ -1,6 +1,7 @@
# 新聞解析 / News Analyze
## Stack:
- Postgres
- Passport.js
- Tailwind

View file

@ -2,7 +2,7 @@
import "bootstrap-icons/font/bootstrap-icons.css";
import "animate.css";
import "@fontsource/fira-sans";
import '@fontsource-variable/noto-sans-tc';
import "@fontsource-variable/noto-sans-tc";
const { t } = useI18n();
</script>
<template>

View file

@ -13,7 +13,6 @@ const availableLocales = computed(() => {
const toggleDropdown = () => {
dropdownOpen.value = !dropdownOpen.value;
};
</script>
<template>
<!--Spent too much time trying to set a Navbar....-->
@ -23,7 +22,9 @@ const toggleDropdown = () => {
<div class="text-3xl text-bold">
<NuxtLink :to="localePath('home')" ref="title">BlindSpec</NuxtLink>
</div>
<div class="text-[0.9em] left-1/2 absolute transform -translate-x-1/2 space-x-4 items-center">
<div
class="text-[0.9em] left-1/2 absolute transform -translate-x-1/2 space-x-4 items-center"
>
<NuxtLink
:to="localePath('/home')"
class="hover:text-blue-500 cursor-pointer transiton-all duration-100"
@ -37,54 +38,56 @@ const toggleDropdown = () => {
>
</div>
<div class="flex flex-row align-center justify-center text-center">
<div class="relative ml-0">
<button
@click="toggleDropdown"
class="flex items-center space-x-1 px-4 py-2 rounded hover:bg-gray-900 transition-all duration-100 mr-5"
>
<span>{{ locale }}</span>
<svg
class="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
<div class="relative ml-0">
<button
@click="toggleDropdown"
class="flex items-center space-x-1 px-4 py-2 rounded hover:bg-gray-900 transition-all duration-100 mr-5"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
/>
</svg>
</button>
<Transition
enter-active-class="animate__animated animate__fadeInDown animate_fastest"
leave-active-class="animate__animated animate__fadeOutUp animate_fastest"
>
<div
v-if="dropdownOpen"
class="absolute top-full right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1"
>
<a
v-for="loc in availableLocales"
:key="loc.code"
:href="switchLocalePath(loc.code)"
v-on:click="dropdownOpen = false"
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-all duration-100"
<span>{{ locale }}</span>
<svg
class="w-4 h-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
{{ loc.name || loc.code }}
</a>
</div>
</Transition>
</div>
<div class="mr-2 ml-0">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
/>
</svg>
</button>
<Transition
enter-active-class="animate__animated animate__fadeInDown animate_fastest"
leave-active-class="animate__animated animate__fadeOutUp animate_fastest"
>
<div
v-if="dropdownOpen"
class="absolute top-full right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1"
>
<a
v-for="loc in availableLocales"
:key="loc.code"
:href="switchLocalePath(loc.code)"
v-on:click="dropdownOpen = false"
class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 transition-all duration-100"
>
{{ loc.name || loc.code }}
</a>
</div>
</Transition>
</div>
<div class="mr-2 ml-0">
<NuxtLink :to="localePath('/system/login')">
<button class="text-white hover:text-[#C6C6C6] transition-all duration-150">
<button
class="text-white hover:text-[#C6C6C6] transition-all duration-150"
>
<i class="bi bi-person text-3xl"></i>
</button>
</NuxtLink>
</div>
</div>
</div>
</div>
</template>
<style scoped>

View file

@ -25,7 +25,7 @@ create table if not exists newsProviders (
logoUrl text not null,
lean text not null
)
`
`;
const createAdminPosts = await sql`
create table if not exists adminPosts (
@ -35,7 +35,7 @@ create table if not exists adminPosts (
created_at timestampz default current_timestamp,
byUser text not null
)
`
`;
const adminUsers = await sql`
create table if not exists adminUsers (
uuid text primary key,
@ -44,7 +44,6 @@ create table if not exists adminUsers (
created_at timestampz default current_timestamp,
lastlogged_at timestampz default current_timestamp,
)
`
`;
console.log("Creation Complete");

View file

@ -1,5 +1,4 @@
<script setup lang="ts">
</script>
<script setup lang="ts"></script>
<template>
<main>
<slot />

View file

@ -1,12 +1,12 @@
<script lang="ts" setup>
definePageMeta({
layout: "admin"
})
layout: "admin",
});
</script>
<template>
<div class="flex justify-center min-h-screen w-full">
<input type="text"/>
<input type="password" />
<button>登入</button>
</div>
<div class="flex justify-center min-h-screen w-full">
<input type="text" />
<input type="password" />
<button>登入</button>
</div>
</template>

View file

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

View file

@ -1,47 +1,62 @@
<script setup lang="ts">
import { gsap } from 'gsap'
import { TextPlugin } from 'gsap/TextPlugin'
gsap.registerPlugin(TextPlugin)
import { gsap } from "gsap";
import { TextPlugin } from "gsap/TextPlugin";
gsap.registerPlugin(TextPlugin);
const { t } = useI18n();
const popMessage = ref(null);
const messages = [t("home.moving.newsPlatform"), t("home.moving.miniWikipedia"), t("home.moving.newsComparePlatform"), "BlindSpec"];
const messages = [
t("home.moving.newsPlatform"),
t("home.moving.miniWikipedia"),
t("home.moving.newsComparePlatform"),
"BlindSpec",
];
onMounted(() => {
const tl = gsap.timeline({ repeat: -1 })
const tl = gsap.timeline({ repeat: -1 });
messages.forEach((message) => {
tl.to(popMessage.value, {
duration:0.5,
text:message,
ease: "none."
duration: 0.5,
text: message,
ease: "none.",
}).to(popMessage.value, {
duration:2,
text:message,
ease: "none."
})
duration: 2,
text: message,
ease: "none.",
});
for (let i = message.length; i >=0; i--) {
for (let i = message.length; i >= 0; i--) {
tl.to(popMessage.value, {
duration:0.06,
text:message.substring(0, i),
ease: "none"
})
duration: 0.06,
text: message.substring(0, i),
ease: "none",
});
}
})
})
});
});
</script>
<template>
<div>
<div class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-x-0 inset-y-0">
<span class="text-3xl">
<span class="bg-gradient-to-b from-[#eee] to-[#333] bg-clip-text text-transparent">{{ t("home.nonMoving") }}</span>
<span ref="popMessage" class="bg-gradient-to-r from-[#2a7b9b] then-[#8d57c7] to-[#ed4242] bg-clip-text text-transparent"></span></span>
<NuxtLink>
<button class="m-4 bg-[#8C9393] text-white p-3 rounded-full bg-gradient-to-l from-sky-500 to-purple-600 transition-all duration-100">
<span>{{ t("home.startusing") }}</span>
</button>
</NuxtLink>
<div
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-x-0 inset-y-0"
>
<span class="text-3xl">
<span
class="bg-gradient-to-b from-[#eee] to-[#333] bg-clip-text text-transparent"
>{{ t("home.nonMoving") }}</span
>
<span
ref="popMessage"
class="bg-gradient-to-r from-[#2a7b9b] then-[#8d57c7] to-[#ed4242] bg-clip-text text-transparent"
></span
></span>
<NuxtLink>
<button
class="m-4 bg-[#8C9393] text-white p-3 rounded-full bg-gradient-to-l from-sky-500 to-purple-600 transition-all duration-100"
>
<span>{{ t("home.startusing") }}</span>
</button>
</NuxtLink>
</div>
<div class="h-screen"></div>
</div>

View file

@ -33,12 +33,12 @@ const {
} = useFetch("/api/getData/fetchSidebarData", {
method: "POST",
headers: {
"Content-Type": "application/json"
"Content-Type": "application/json",
},
body: {
lang: locale,
}
})
},
});
watchEffect(() => {
loading.value = pending.value;
@ -90,25 +90,31 @@ import { GlobeAltIcon } from "@heroicons/vue/24/outline";
>
</div>
</div>
<div class="flex flex-col gap-3 text-left justify-right align-right bg-[#AAACAA61] w-[28%] rounded-3xl p-3 mt-3 h-screen">
<div
class="flex flex-col gap-3 text-left justify-right align-right bg-[#AAACAA61] w-[28%] rounded-3xl p-3 mt-3 h-screen"
>
<h3 class="text-2xl mt-2s">其他媒體</h3>
<hr/>
<hr />
<div v-for="data in fetchOtherData" :key="data.id" class="flex flex-col">
<NuxtImg :src="data.image"></NuxtImg>
<div class="flex flex-row">
<h1 class="text-xl text-bold">{{ data.title }}</h1>
<span class="text-ms ml-2 align-center justify-center text-center">
(
<span>{{ data.lean }}</span>
-
<span>文章分數:
<span>{{ data.score }}</span>
</span> )
</span>
<h1 class="text-xl text-bold">{{ data.title }}</h1>
<span class="text-ms ml-2 align-center justify-center text-center">
(
<span>{{ data.lean }}</span>
-
<span
>文章分數:
<span>{{ data.score }}</span>
</span>
)
</span>
</div>
</div>
<NuxtLink class="justify-center align-center text-center">
<button class="bg-red-500 text-black p-2 rounded-full justify-center align-center">
<button
class="bg-red-500 text-black p-2 rounded-full justify-center align-center"
>
<span>查看更多</span>
</button>
</NuxtLink>

View file

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

View file

@ -1,25 +1,33 @@
<template>
<div class="w-full min-h-screen flex items-center justify-center text-center">
<div class="border border-white w-[40%] p-16 justify-center align-center text-center rounded-md backdrop-blur-sm bg-gray-900">
<h1 class="text-2xl">Login / Register</h1>
<h4 class="text-sm">via OAuth Providers</h4>
<div class="m-4 flex flex-col gap-2">
<a href="/api/auth/google">
<button class="gap-3 px-10 justify-between align-center text-center bg-gray-500 hover:bg-gray-700 p-2 rounded-md transition-all duration-150">
<i class="bi bi-google"></i>&nbsp;&nbsp;<span>Google</span>
</button>
</a>
<a href="/api/auth/github">
<button class="gap-3 px-10 bg-gray-500 hover:bg-gray-700 p-2 rounded-md transition-all duration-150">
<i class="bi bi-github"></i>&nbsp;&nbsp;<span>Github</span>
</button>
</a>
<a href="/api/auth/discord">
<button class="gap-3 px-10 bg-gray-500 hover:bg-gray-700 p-2 rounded-md transition-all duration-150">
<i class="bi bi-discord"></i>&nbsp;&nbsp;<span>Discord</span>
</button>
</a>
</div>
</div>
<div class="w-full min-h-screen flex items-center justify-center text-center">
<div
class="border border-white w-[40%] p-16 justify-center align-center text-center rounded-md backdrop-blur-sm bg-gray-900"
>
<h1 class="text-2xl">Login / Register</h1>
<h4 class="text-sm">via OAuth Providers</h4>
<div class="m-4 flex flex-col gap-2">
<a href="/api/auth/google">
<button
class="gap-3 px-10 justify-between align-center text-center bg-gray-500 hover:bg-gray-700 p-2 rounded-md transition-all duration-150"
>
<i class="bi bi-google"></i>&nbsp;&nbsp;<span>Google</span>
</button>
</a>
<a href="/api/auth/github">
<button
class="gap-3 px-10 bg-gray-500 hover:bg-gray-700 p-2 rounded-md transition-all duration-150"
>
<i class="bi bi-github"></i>&nbsp;&nbsp;<span>Github</span>
</button>
</a>
<a href="/api/auth/discord">
<button
class="gap-3 px-10 bg-gray-500 hover:bg-gray-700 p-2 rounded-md transition-all duration-150"
>
<i class="bi bi-discord"></i>&nbsp;&nbsp;<span>Discord</span>
</button>
</a>
</div>
</div>
</div>
</template>

View file

@ -1,8 +1,5 @@
export default defineEventHandler(async (event) => {
})
export default defineEventHandler(async (event) => {});
async function findUser(githubUser: any) {
console.log("Github User: " + githubUser);
console.log("Github User: " + githubUser);
}

View file

@ -1,16 +1,16 @@
import crypto from "node:crypto"
import crypto from "node:crypto";
export default defineEventHandler(async (event) => {
const baseUrl = event.node.req.headers.host
const protocol = process.env.NODE_ENV === "production" ? "https": "http"
const clientId = process.env.NUXT_GITHUB_CLIENT_ID;
const callbackUrl = `${protocol}://${baseUrl}/api/auth/github/callback`;
const state = crypto.randomBytes(16).toString("hex");
setCookie(event, 'oauth_state', state, {
const baseUrl = event.node.req.headers.host;
const protocol = process.env.NODE_ENV === "production" ? "https" : "http";
const clientId = process.env.NUXT_GITHUB_CLIENT_ID;
const callbackUrl = `${protocol}://${baseUrl}/api/auth/github/callback`;
const state = crypto.randomBytes(16).toString("hex");
setCookie(event, "oauth_state", state, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
secure: process.env.NODE_ENV === "production",
maxAge: 60 * 10,
path: '/',
})
const authorizationUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(callbackUrl)}&scope=read:user,user:email&state=${state}`
await sendRedirect(event, authorizationUrl, 302)
})
path: "/",
});
const authorizationUrl = `https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(callbackUrl)}&scope=read:user,user:email&state=${state}`;
await sendRedirect(event, authorizationUrl, 302);
});

View file

@ -2,12 +2,12 @@ export default defineEventHandler(async (event) => {
const body = await readBody(event);
return {
0: {
id: "1",
image: "whatever",
tags: [],
title: "三立新聞",
lean: "left",
score: "40"
}
id: "1",
image: "whatever",
tags: [],
title: "三立新聞",
lean: "left",
score: "40",
},
};
});

View file

@ -9,15 +9,17 @@
body {
@apply bg-black m-0 p-0 min-h-screen text-white;
}
html,body {
font-family: 'Noto Sans TC Variable', "Fira Sans", sans-serif;
html,
body {
font-family: "Noto Sans TC Variable", "Fira Sans", sans-serif;
}
}
@font-face {
font-family: 'Noto Sans TC Variable';
font-family: "Noto Sans TC Variable";
font-style: normal;
font-display: auto;
font-weight: 100 900;
src: url(@fontsource-variable/noto-sans-tc/files/noto-sans-tc-chinese-traditional-wght-normal.woff2) format('woff2-variations');
src: url(@fontsource-variable/noto-sans-tc/files/noto-sans-tc-chinese-traditional-wght-normal.woff2)
format("woff2-variations");
}