mirror of
https://github.com/hpware/news-analyze.git
synced 2025-06-23 13:04:23 +00:00
After a few hours debugging css, It finally looks really good, like xfce :D
refactor: update localization files and remove unused login page
This commit is contained in:
parent
ed383d6404
commit
dc30310cfe
7 changed files with 50 additions and 75 deletions
|
@ -24,13 +24,13 @@ App Design: [Freeform](https://www.icloud.com/freeform/026AxB798cViZ9jJ2DkNsXUCQ
|
||||||
## Stack:
|
## Stack:
|
||||||
|
|
||||||
- Postgres
|
- Postgres
|
||||||
- Passport.js
|
|
||||||
- Tailwind
|
- Tailwind
|
||||||
- Nuxt
|
- Nuxt
|
||||||
- Animate.css
|
- Animate.css
|
||||||
- GSAP
|
- GSAP
|
||||||
- Zeabur
|
|
||||||
- Minio S3
|
- Minio S3
|
||||||
- Nuxt i18N
|
- Nuxt i18n
|
||||||
- BunJS
|
- BunJS
|
||||||
- Groq
|
- Groq
|
||||||
|
- Clerk
|
||||||
|
- Custom Infra
|
1
app.vue
1
app.vue
|
@ -1,5 +1,4 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
|
||||||
import "animate.css";
|
import "animate.css";
|
||||||
import "@fontsource/fira-sans";
|
import "@fontsource/fira-sans";
|
||||||
import "@fontsource-variable/noto-sans-tc";
|
import "@fontsource-variable/noto-sans-tc";
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
{
|
|
||||||
"dailybriefing": "",
|
|
||||||
"Welcome": ""
|
|
||||||
}
|
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"localeflag": "🇺🇸",
|
||||||
"core": {
|
"core": {
|
||||||
"sitename": "BlindSpec"
|
"sitename": "BlindSpec"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
"localeflag": "🇹🇼",
|
||||||
"core": {
|
"core": {
|
||||||
"sitename": "新聞盲點平台"
|
"sitename": "新聞盲點平台"
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,22 +4,26 @@ definePageMeta({
|
||||||
});
|
});
|
||||||
import { gsap } from "gsap";
|
import { gsap } from "gsap";
|
||||||
import { TextPlugin } from "gsap/TextPlugin";
|
import { TextPlugin } from "gsap/TextPlugin";
|
||||||
|
import { createApp } from "vue";
|
||||||
gsap.registerPlugin(TextPlugin);
|
gsap.registerPlugin(TextPlugin);
|
||||||
|
|
||||||
// Import Windows
|
// Import Windows
|
||||||
import SignIn from "~/components/app/windows/login.vue";
|
import SignIn from "~/components/app/windows/login.vue";
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
import { ComputerDesktopIcon, UserIcon } from "@heroicons/vue/24/outline";
|
import { ComputerDesktopIcon, UserIcon, LanguageIcon, ChevronRightIcon} from "@heroicons/vue/24/outline";
|
||||||
|
|
||||||
// i18n
|
// i18n
|
||||||
const { t, locale, locales } = useI18n();
|
const { t, locale, locales } = useI18n();
|
||||||
|
const switchLocalePath = useSwitchLocalePath();
|
||||||
const localePath = useLocalePath();
|
const localePath = useLocalePath();
|
||||||
// Router
|
// Router
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
// values
|
// values
|
||||||
const popMessage = ref(null);
|
const popMessage = ref(null);
|
||||||
const menuOpen = ref(false);
|
const menuOpen = ref(false);
|
||||||
|
const langMenuOpen = ref(false);
|
||||||
|
const lang = ref(locale.value);
|
||||||
// Date
|
// Date
|
||||||
const currentDate = ref(
|
const currentDate = ref(
|
||||||
new Date().toLocaleDateString("zh-TW", {
|
new Date().toLocaleDateString("zh-TW", {
|
||||||
|
@ -48,12 +52,15 @@ onMounted(() => {
|
||||||
|
|
||||||
// functions
|
// functions
|
||||||
const showLogin = () => {
|
const showLogin = () => {
|
||||||
|
const desktopEl = document.getElementById('desktop');
|
||||||
|
if (!desktopEl) return;
|
||||||
|
|
||||||
const loginWindow = document.createElement("div");
|
const loginWindow = document.createElement("div");
|
||||||
loginWindow.className = "login-window";
|
loginWindow.className = "login-window absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2";
|
||||||
document.body.appendChild(loginWindow);
|
desktopEl.appendChild(loginWindow);
|
||||||
const app = createApp(SignIn);
|
const app = createApp(SignIn);
|
||||||
app.component("SignIn", SignIn);
|
|
||||||
app.mount(loginWindow);
|
app.mount(loginWindow);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
gsap.fromTo(
|
gsap.fromTo(
|
||||||
loginWindow,
|
loginWindow,
|
||||||
|
@ -61,44 +68,43 @@ const showLogin = () => {
|
||||||
{ opacity: 1, scale: 1, duration: 0.5 },
|
{ opacity: 1, scale: 1, duration: 0.5 },
|
||||||
);
|
);
|
||||||
}, 100);
|
}, 100);
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
gsap.to(loginWindow, {
|
gsap.to(loginWindow, {
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
scale: 0.5,
|
scale: 0.5,
|
||||||
duration: 0.5,
|
duration: 0.5,
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
document.body.removeChild(loginWindow);
|
desktopEl.removeChild(loginWindow);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}, 5000);
|
}, 5000);
|
||||||
}
|
}
|
||||||
// menu
|
const openWindow = (windowName?: string) => {
|
||||||
|
console.log(windowName);
|
||||||
|
}
|
||||||
|
// menus
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ name: "Hot News", action: () => router.push(localePath("/app/hotnews")) },
|
{ name: "Hot News", windowName: "hotnews"} ,
|
||||||
{ name: "News", action: () => router.push(localePath("/app/news")) },
|
{ name: "News", windowName: "news"},
|
||||||
{ name: "Sources", action: () => router.push(localePath("/sources")) },
|
{ name: "Sources", windowName: "sources"},
|
||||||
{ type: "separator" },
|
{ name: 'About This Website', },
|
||||||
{ name: 'About This Website', action: () => console.log('About') },
|
{ name: 'Settings', windowName: "settings"},
|
||||||
{ name: 'Settings', action: () => router.push('/settings') },
|
{ name: 'Leave', windowName: "leave"},
|
||||||
{ type: 'separator' },
|
|
||||||
{ name: 'Leave', action: () => router.push(localePath('/')) },
|
|
||||||
]
|
]
|
||||||
const toggleMenu = () => {
|
const toggleMenu = () => {
|
||||||
menuOpen.value = !menuOpen.value
|
menuOpen.value = !menuOpen.value
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
// Lang Menu
|
||||||
document.addEventListener('click', (e) => {
|
const toggleLangMenu = () => {
|
||||||
if (!(e.target as HTMLElement).closest('.menu-container')) {
|
langMenuOpen.value = !langMenuOpen.value
|
||||||
menuOpen.value = false
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="absolute inset-x-0 flex flex-row px-2 py-1 bg-white dark:bg-gray-900 justify-between align-center text-center z-50"
|
class="absolute inset-x-0 flex flex-row px-2 py-1 bg-white dark:bg-gray-900 justify-between align-center text-center z-50"
|
||||||
>
|
>
|
||||||
<div class="flex flex-row g-2 text-gray-400 dark:text-gray-500 z-100">
|
<div class="flex flex-row g-2 text-gray-400 dark:text-gray-500">
|
||||||
<button @click="toggleMenu" class="w-8 h-8 text-gray-400 dark:text-gray-500 hover:text-blue-500 transition-all duration-100 flex flex-row">
|
<button @click="toggleMenu" class="w-8 h-8 text-gray-400 dark:text-gray-500 hover:text-blue-500 transition-all duration-100 flex flex-row">
|
||||||
<ComputerDesktopIcon/>
|
<ComputerDesktopIcon/>
|
||||||
</button>
|
</button>
|
||||||
|
@ -107,8 +113,16 @@ onMounted(() => {
|
||||||
<div class="text-gray-400">{{ currentDate }}</div>
|
<div class="text-gray-400">{{ currentDate }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="w-full h-[2.5em]"></div>
|
<div class="w-full h-[2.5em]"></div>
|
||||||
|
<div class="m-2 p-2 bg-gray-800 shadow-lg w-fit rounded-[10px]" v-if="menuOpen">
|
||||||
|
<div v-for="item in menuItems" :key="item.name" class="">
|
||||||
|
<button @click="openWindow(item.windowName)" class="flex flex-row items-center gap-x-2 text-gray-400 hover:text-gray-600 transition-all duration-100">
|
||||||
|
<span>{{ item.name }}</span>
|
||||||
|
<ChevronRightIcon class="w-4 h-4 justify-center align-center" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-x-0 inset-y-0"
|
class="flex flex-col justify-center align-center text-center absolute w-full h-screen inset-x-0 inset-y-0 z-[-1]"
|
||||||
id="desktop"
|
id="desktop"
|
||||||
>
|
>
|
||||||
|
|
||||||
|
@ -117,9 +131,15 @@ onMounted(() => {
|
||||||
class="absolute w-[calc(100% - 5px)] inset-x-0 bottom-0 mx-[1.5px] p-3 justify-between align-center flex flex-row"
|
class="absolute w-[calc(100% - 5px)] inset-x-0 bottom-0 mx-[1.5px] p-3 justify-between align-center flex flex-row"
|
||||||
>
|
>
|
||||||
<div class="">
|
<div class="">
|
||||||
Lang: <span class="text-sm">{{ locale }}</span>
|
<!--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>
|
||||||
<div class="gap-2 flex flex-row">
|
<div class="gap-2 flex flex-row">
|
||||||
|
<!--版權資訊-->
|
||||||
<span class="text-sm">1.0.0</span>
|
<span class="text-sm">1.0.0</span>
|
||||||
<span class="text-sm">|</span>
|
<span class="text-sm">|</span>
|
||||||
<span class="text-sm">MIT License</span>
|
<span class="text-sm">MIT License</span>
|
||||||
|
@ -127,6 +147,7 @@ onMounted(() => {
|
||||||
<span class="text-sm">{{ new Date().getFullYear() }} © yh</span>
|
<span class="text-sm">{{ new Date().getFullYear() }} © yh</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
|
<!--Clerk-->
|
||||||
<SignedOut>
|
<SignedOut>
|
||||||
<SignInButton>
|
<SignInButton>
|
||||||
<button @click="showLogin" class="w-8 h-8 text-gray-400 dark:text-gray-500 flex flex-row">
|
<button @click="showLogin" class="w-8 h-8 text-gray-400 dark:text-gray-500 flex flex-row">
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
<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>
|
|
||||||
</template>
|
|
||||||
<style scoped>
|
|
||||||
@keyframes animateLoginLoad {
|
|
||||||
0% {
|
|
||||||
transform: translateY(-5%);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
Loading…
Add table
Add a link
Reference in a new issue