mirror of
https://github.com/hpware/news-analyze.git
synced 2025-06-23 13:04:23 +00:00
Clean the awful code.
This commit is contained in:
parent
98ffbec764
commit
569cd087e7
15 changed files with 193 additions and 167 deletions
|
@ -1,6 +1,7 @@
|
|||
# 新聞解析 / News Analyze
|
||||
|
||||
## Stack:
|
||||
|
||||
- Postgres
|
||||
- Passport.js
|
||||
- Tailwind
|
||||
|
|
2
app.vue
2
app.vue
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
<script setup lang="ts">
|
||||
</script>
|
||||
<script setup lang="ts"></script>
|
||||
<template>
|
||||
<main>
|
||||
<slot />
|
||||
|
|
|
@ -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>
|
|
@ -1,3 +1 @@
|
|||
<template>
|
||||
|
||||
</template>
|
||||
<template></template>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
<template>
|
||||
|
||||
</template>
|
||||
<template></template>
|
||||
|
|
|
@ -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> <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> <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> <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> <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> <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> <span>Discord</span>
|
||||
</button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
|
|
@ -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");
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue