mirror of
https://github.com/hpware/news-analyze.git
synced 2025-06-23 13:04:23 +00:00
feat: enhance typography with new font sources, update footer layout, and improve navigation structure
This commit is contained in:
parent
7c7601a38b
commit
d773473eb0
13 changed files with 172 additions and 31 deletions
2
app.vue
2
app.vue
|
@ -1,6 +1,8 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
import "bootstrap-icons/font/bootstrap-icons.css";
|
||||||
import "animate.css";
|
import "animate.css";
|
||||||
|
import "@fontsource/fira-sans";
|
||||||
|
import '@fontsource-variable/noto-sans-tc';
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
|
|
9
bun.lock
9
bun.lock
|
@ -4,6 +4,9 @@
|
||||||
"": {
|
"": {
|
||||||
"name": "nuxt-app",
|
"name": "nuxt-app",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource-variable/noto-sans-tc": "^5.2.5",
|
||||||
|
"@fontsource/fira-code": "^5.2.6",
|
||||||
|
"@fontsource/fira-sans": "^5.2.5",
|
||||||
"@heroicons/vue": "^2.2.0",
|
"@heroicons/vue": "^2.2.0",
|
||||||
"@nuxt/image": "1.10.0",
|
"@nuxt/image": "1.10.0",
|
||||||
"@nuxtjs/i18n": "9.5.4",
|
"@nuxtjs/i18n": "9.5.4",
|
||||||
|
@ -176,6 +179,12 @@
|
||||||
|
|
||||||
"@fastify/busboy": ["@fastify/busboy@3.1.1", "", {}, "sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw=="],
|
"@fastify/busboy": ["@fastify/busboy@3.1.1", "", {}, "sha512-5DGmA8FTdB2XbDeEwc/5ZXBl6UbBAyBOOLlPuBnZ/N1SwdH9Ii+cOX3tBROlDgcTXxjOYnLMVoKk9+FXAw0CJw=="],
|
||||||
|
|
||||||
|
"@fontsource-variable/noto-sans-tc": ["@fontsource-variable/noto-sans-tc@5.2.5", "", {}, "sha512-oaAn5hkLxraNBOWuiqyJ6+t1SmQ9Sszmcs+wJpmAmUO/1dsaHjDU5HXEjutvPpucqVeqdvVNr/kHRx+ghdiPeA=="],
|
||||||
|
|
||||||
|
"@fontsource/fira-code": ["@fontsource/fira-code@5.2.6", "", {}, "sha512-wCkIpPm0BqlkCPLYeY4Vui96ODmVUV0/GpEe3OfJ4v8EJn/BF2SlyxvarFsTs1CKiGjrO2cXlIZbBrKi9F+hUQ=="],
|
||||||
|
|
||||||
|
"@fontsource/fira-sans": ["@fontsource/fira-sans@5.2.5", "", {}, "sha512-N+GrTGOTIeYE/Wi5tY0RAnc1Tl3ddCdwfZQncvA1zH/lOpKerj9ZS5nfniSXDZ9wrXFRdWTH7anyrRDc+cMpCg=="],
|
||||||
|
|
||||||
"@heroicons/vue": ["@heroicons/vue@2.2.0", "", { "peerDependencies": { "vue": ">= 3" } }, "sha512-G3dbSxoeEKqbi/DFalhRxJU4mTXJn7GwZ7ae8NuEQzd1bqdd0jAbdaBZlHPcvPD2xI1iGzNVB4k20Un2AguYPw=="],
|
"@heroicons/vue": ["@heroicons/vue@2.2.0", "", { "peerDependencies": { "vue": ">= 3" } }, "sha512-G3dbSxoeEKqbi/DFalhRxJU4mTXJn7GwZ7ae8NuEQzd1bqdd0jAbdaBZlHPcvPD2xI1iGzNVB4k20Un2AguYPw=="],
|
||||||
|
|
||||||
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
class="flex flex-row justify-center align-center text-center absolute inset-x-0"
|
class="flex flex-col justify-center align-center text-center absolute inset-x-0"
|
||||||
>
|
>
|
||||||
<span class="text-xs m-4"
|
<span class="text-sm m-4 mb-0 text-center align-center justify-center"
|
||||||
>{{ new Date().getFullYear() }} © 吳元皓</span
|
>{{ new Date().getFullYear() }} © yh</span
|
||||||
>
|
>
|
||||||
|
<span class="text-xs mt-0 m-2 text-center align-center justify-center">
|
||||||
|
Inspired by Ground.News
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { gsap } from "gsap";
|
|
||||||
import { ScrambleTextPlugin } from "gsap/dist/ScrambleTextPlugin";
|
|
||||||
gsap.registerPlugin(ScrambleTextPlugin);
|
|
||||||
|
|
||||||
const { t, locale, locales } = useI18n();
|
const { t, locale, locales } = useI18n();
|
||||||
|
const localePath = useLocalePath();
|
||||||
const switchLocalePath = useSwitchLocalePath();
|
const switchLocalePath = useSwitchLocalePath();
|
||||||
|
|
||||||
const dropdownOpen = ref(false);
|
const dropdownOpen = ref(false);
|
||||||
|
@ -17,39 +14,32 @@ const toggleDropdown = () => {
|
||||||
dropdownOpen.value = !dropdownOpen.value;
|
dropdownOpen.value = !dropdownOpen.value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const runAnimation = () => {
|
|
||||||
gsap.to(title.value, {
|
|
||||||
duration: 1,
|
|
||||||
scrambleText: "BlindSpec",
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<!--Spent too much time trying to set a Navbar....-->
|
<!--Spent too much time trying to set a Navbar....-->
|
||||||
<div
|
<div
|
||||||
class="fixed top-0 inset-x-0 bg-[#81611a]/70 backdrop-blur-sm h-[55px] flex align-center flex-row text-white pl-4 pt-2 gap-x-5 justify-between z-50 rounded-3xl m-2"
|
class="fixed top-0 inset-x-0 bg-[#81611a]/70 backdrop-blur-sm h-[55px] flex align-center items-center flex-row text-white pl-4 gap-x-5 justify-between z-50 rounded-3xl m-2"
|
||||||
>
|
>
|
||||||
<div class="text-3xl text-bold">
|
<div class="text-3xl text-bold">
|
||||||
<!--Use mouseenter instead of hover-->
|
<NuxtLink :to="localePath('home')" ref="title">BlindSpec</NuxtLink>
|
||||||
<a href="/" @mouseenter="runAnimation" ref="title"> BlindSpec </a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="text-[0.9em] text-center align-center">
|
<div class="text-[0.9em] left-1/2 absolute transform -translate-x-1/2 space-x-4 items-center">
|
||||||
<a
|
<NuxtLink
|
||||||
href="/"
|
:to="localePath('home')"
|
||||||
class="hover:text-blue-500 cursor-pointer transiton-all duration-100"
|
class="hover:text-blue-500 cursor-pointer transiton-all duration-100"
|
||||||
>{{ t("nav.home") }}</a
|
>{{ t("nav.home") }}</NuxtLink
|
||||||
>
|
>
|
||||||
|
|
||||||
<a
|
<NuxtLink
|
||||||
href="/dailybriefing"
|
:to="localePath('dailybriefing')"
|
||||||
class="hover:text-blue-500 cursor-pointer transiton-all duration-100"
|
class="hover:text-blue-500 cursor-pointer transiton-all duration-100"
|
||||||
>{{ t("nav.dailybriefing") }}</a
|
>{{ t("nav.dailybriefing") }}</NuxtLink
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<button
|
<button
|
||||||
@click="toggleDropdown"
|
@click="toggleDropdown"
|
||||||
class="flex items-center space-x-2 px-4 py-2 rounded hover:bg-gray-900 transition-all duration-100"
|
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>
|
<span>{{ locale }}</span>
|
||||||
<svg
|
<svg
|
||||||
|
@ -68,8 +58,8 @@ const runAnimation = () => {
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<Transition
|
<Transition
|
||||||
enter-active-class="animate__animated animate__fadeInDown animate__faster"
|
enter-active-class="animate__animated animate__fadeInDown animate_fastest"
|
||||||
leave-active-class="animate__animated animate__fadeOutUp animate__faster"
|
leave-active-class="animate__animated animate__fadeOutUp animate_fastest"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="dropdownOpen"
|
v-if="dropdownOpen"
|
||||||
|
@ -89,3 +79,8 @@ const runAnimation = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
<style scoped>
|
||||||
|
.animate_fastest {
|
||||||
|
--animate-duration: 0.2s;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -6,6 +6,15 @@
|
||||||
"home": "Home",
|
"home": "Home",
|
||||||
"dailybriefing": "Daily Briefing"
|
"dailybriefing": "Daily Briefing"
|
||||||
},
|
},
|
||||||
|
"home": {
|
||||||
|
"nonMoving": "Hi! This is your ",
|
||||||
|
"moving": {
|
||||||
|
"newsPlatform": "News Platform",
|
||||||
|
"miniWikipedia": "Mini Wikipedia",
|
||||||
|
"newsComparePlatform": "news comparison platform"
|
||||||
|
},
|
||||||
|
"startusing": "Let's Start!"
|
||||||
|
},
|
||||||
"dailybriefing": "Daily Briefing",
|
"dailybriefing": "Daily Briefing",
|
||||||
"Welcome": "Welcome",
|
"Welcome": "Welcome",
|
||||||
"loading": "Loading..."
|
"loading": "Loading..."
|
||||||
|
|
|
@ -6,6 +6,15 @@
|
||||||
"home": "首頁",
|
"home": "首頁",
|
||||||
"dailybriefing": "今日報導"
|
"dailybriefing": "今日報導"
|
||||||
},
|
},
|
||||||
|
"home": {
|
||||||
|
"nonMoving": "嗨!這是你的",
|
||||||
|
"moving": {
|
||||||
|
"newsPlatform": "新聞平台",
|
||||||
|
"miniWikipedia": "米你維基百科",
|
||||||
|
"newsComparePlatform": "新聞觀點比對平台"
|
||||||
|
},
|
||||||
|
"startusing": "開始使用!"
|
||||||
|
},
|
||||||
"dailybriefing": "今日報導",
|
"dailybriefing": "今日報導",
|
||||||
"Welcome": "歡迎",
|
"Welcome": "歡迎",
|
||||||
"loading": "載入中..."
|
"loading": "載入中..."
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
"prettier": "prettier --write ."
|
"prettier": "prettier --write ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource-variable/noto-sans-tc": "^5.2.5",
|
||||||
|
"@fontsource/fira-code": "^5.2.6",
|
||||||
|
"@fontsource/fira-sans": "^5.2.5",
|
||||||
"@heroicons/vue": "^2.2.0",
|
"@heroicons/vue": "^2.2.0",
|
||||||
"@nuxt/image": "1.10.0",
|
"@nuxt/image": "1.10.0",
|
||||||
"@nuxtjs/i18n": "9.5.4",
|
"@nuxtjs/i18n": "9.5.4",
|
||||||
|
|
3
pages/dailybriefing.vue
Normal file
3
pages/dailybriefing.vue
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
|
@ -1,5 +1,48 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
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"];
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
const tl = gsap.timeline({ repeat: -1 })
|
||||||
|
messages.forEach((message) => {
|
||||||
|
tl.to(popMessage.value, {
|
||||||
|
duration:0.5,
|
||||||
|
text:message,
|
||||||
|
ease: "none."
|
||||||
|
}).to(popMessage.value, {
|
||||||
|
duration:2,
|
||||||
|
text:message,
|
||||||
|
ease: "none."
|
||||||
|
})
|
||||||
|
|
||||||
|
for (let i = message.length; i >=0; i--) {
|
||||||
|
tl.to(popMessage.value, {
|
||||||
|
duration:0.06,
|
||||||
|
text:message.substring(0, i),
|
||||||
|
ease: "none"
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1 class="text-3xl font-bold text-center">嗨!</h1>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
|
@ -26,6 +26,20 @@ const {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: fetchOtherData,
|
||||||
|
pending: fetchOtherDataPending,
|
||||||
|
error: fetchOtherDataError,
|
||||||
|
} = useFetch("/api/getData/fetchSidebarData", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
lang: locale,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
loading.value = pending.value;
|
loading.value = pending.value;
|
||||||
});
|
});
|
||||||
|
@ -46,10 +60,10 @@ onMounted(() => {
|
||||||
import { GlobeAltIcon } from "@heroicons/vue/24/outline";
|
import { GlobeAltIcon } from "@heroicons/vue/24/outline";
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="flex flex-row flex-wrap w-full mt-2">
|
||||||
<div class="text-center align-center justify-center">
|
<div class="text-center align-center justify-center w-[70%]">
|
||||||
<div
|
<div
|
||||||
class="flex flex-row bg-[#AAACAAFF] rounded-3xl p-3 gap-3 m-3 scale-5"
|
class="flex flex-row bg-[#AAACAA61] rounded-3xl p-3 gap-3 m-3 scale-5"
|
||||||
>
|
>
|
||||||
<NuxtImg
|
<NuxtImg
|
||||||
:src="fetchNewsOrgInfo?.logoUrl"
|
:src="fetchNewsOrgInfo?.logoUrl"
|
||||||
|
@ -76,5 +90,28 @@ import { GlobeAltIcon } from "@heroicons/vue/24/outline";
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
||||||
|
<h3 class="text-2xl mt-2s">其他媒體</h3>
|
||||||
|
<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>
|
||||||
|
</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">
|
||||||
|
<span>查看更多</span>
|
||||||
|
</button>
|
||||||
|
</NuxtLink>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
3
pages/newsOrgs.vue
Normal file
3
pages/newsOrgs.vue
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
13
server/api/getData/fetchSidebarData.ts
Normal file
13
server/api/getData/fetchSidebarData.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
const body = await readBody(event);
|
||||||
|
return {
|
||||||
|
0: {
|
||||||
|
id: "1",
|
||||||
|
image: "whatever",
|
||||||
|
tags: [],
|
||||||
|
title: "三立新聞",
|
||||||
|
lean: "left",
|
||||||
|
score: "40"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
|
@ -9,4 +9,16 @@
|
||||||
body {
|
body {
|
||||||
@apply bg-black m-0 p-0 min-h-screen text-white;
|
@apply bg-black m-0 p-0 min-h-screen text-white;
|
||||||
}
|
}
|
||||||
|
html,body {
|
||||||
|
font-family: 'Noto Sans TC Variable', "Fira Sans", sans-serif;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* noto-sans-tc-chinese-traditional-wght-normal */
|
||||||
|
@font-face {
|
||||||
|
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');
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue