style modify

This commit is contained in:
Jeffrey Hsu 2025-01-13 01:03:16 +08:00
parent 75167ae9e7
commit fb109cd9ba
10 changed files with 73 additions and 46 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

@ -1,5 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import {computed} from "vue"; import {computed} from "vue";
import {pos} from "ipx";
const props = defineProps<{ const props = defineProps<{
post: IPost post: IPost
@ -15,28 +16,21 @@ const randomId = computed(() => pid.data.value!)
<template> <template>
<nuxt-link :title="post.title" <nuxt-link :title="post.title"
class="container relative h-56 overflow-hidden rounded-2xl text-white hover:cursor-pointer hover:text-amber-200 hover:shadow-lg" class="container relative overflow-hidden rounded-2xl bg-white transition-all duration-300 ease-in-out h-[31rem] hover:-translate-y-2 hover:cursor-pointer hover:shadow"
:to="{name: 'article-cid', params: {cid: post.cid}}"> :to="{name: 'article-cid', params: {cid: post.cid}}">
<!-- 图片 --> <!-- 图片 -->
<div class="container h-full"> <div class="relative">
<!-- 渐变 -->
<div class="absolute top-0 right-0 bottom-0 left-0 bg-gradient-to-t from-white"></div>
<img v-if="thumbUrl" :src="thumbUrl" alt="" <img v-if="thumbUrl" :src="thumbUrl" alt=""
class="h-full w-full object-cover object-center transition-all duration-300 hover:scale-110"> class="aspect-video w-full h-auto object-cover object-center">
<card-article-default-image :id="randomId"/> <card-article-default-image :id="randomId"/>
</div> </div>
<!-- 文字部分 --> <!-- 文字部分 -->
<div class="container relative"> <div class="px-5">
<div class="absolute bottom-0 h-12 w-full truncate bg-black bg-opacity-60 p-2 leading-8 backdrop-blur-3xl"> <!-- 标题 -->
<span class="px-1 text-xl font-bold transition-all">{{ post.title }}</span> <h4 class="text-2xl font-bold">{{ post.title }}</h4>
</div> <p class="mt-4 text-lg px-1 text-gray-700">{{ post.digest }}</p>
</div>
<!-- 分类 -->
<div class="absolute top-0 left-0 m-2 rounded-lg bg-black bg-opacity-60 px-2 text-white backdrop-blur-3xl">
<span>{{ post.category }}</span>
</div>
<!-- 日期 -->
<div class="absolute right-0 bottom-12 m-2 rounded-lg bg-black bg-opacity-60 px-2 text-white backdrop-blur-3xl">
<font-awesome-icon :icon="['far', 'clock']" class="mr-1 text-sm"/>
<span>{{ post.date.year }}-{{ post.date.month }}-{{ post.date.day }}</span>
</div> </div>
</nuxt-link> </nuxt-link>
</template> </template>

View File

@ -16,6 +16,6 @@ defineProps<{
<style scoped> <style scoped>
img { img {
@apply h-full w-full object-cover object-center transition-all duration-300 hover:scale-110 @apply aspect-[16/10] w-full h-auto object-cover object-center
} }
</style> </style>

View File

@ -1,25 +1,18 @@
<script lang="ts" setup> <script lang="ts" setup>
defineProps<{ defineProps<{
title: string title: string
mainColor: string
subColor: string
url: string
icon: string[] icon: string[]
}>() }>()
</script> </script>
<template> <template>
<div class="mb-4 flex justify-between text-2xl font-bold text-white"> <div class="my-16 relative">
<div :class="[mainColor]" class="flex w-max items-center justify-center overflow-hidden rounded-2xl"> <h3 class="text-5xl font-bold text-blue-400 relative z-10">{{ title }}</h3>
<div :class="[subColor]" class="flex h-full w-14 items-center justify-center rounded-2xl px-4 py-2 text-center"> <div class="h-12 w-auto text-5xl text-blue-200 absolute left-48 top-0 -translate-y-6">
<font-awesome-icon :icon="icon"/> <font-awesome-icon :icon="icon"/>
</div> </div>
<span class="px-4">{{ title }}</span>
</div>
<a :class="[mainColor]" :href="url" class="rounded-2xl px-4 py-2">
<font-awesome-icon :icon="['fas', 'chevron-right']"/>
</a>
</div> </div>
</template> </template>
<style scoped> <style scoped>

View File

@ -3,6 +3,7 @@ defineProps<{
loading: boolean loading: boolean
error: boolean error: boolean
empty: boolean empty: boolean
errMsg?: object
}>() }>()
const emit = defineEmits(['reload']) const emit = defineEmits(['reload'])
@ -24,13 +25,26 @@ const handleReload = () => {
</div> </div>
<div v-else class="w-full"> <div v-else class="w-full">
<!-- 错误处理 --> <!-- 错误处理 -->
<div v-if="error" class="flex h-56 flex-col items-center justify-center" @click="handleReload"> <div v-if="error" @click="handleReload">
<span class="mb-4 text-8xl"></span> <div class="flex items-center justify-center gap-8">
<span class="text-center text-2xl font-bold">载入错误</span> <p class="text-2xl text-gray-700 border-2 border-black py-2 px-8 rounded-full rounded-br-lg">载入错误</p>
<img class="h-32 w-auto relative" src="~/assets/images/common/plana_e.png" alt="">
</div>
<div v-if="errMsg" class="bg-white mt-4 p-4 border border-dashed rounded-md" style="font-family: 'LXGW WenKai Mono', monospace">
{{ errMsg }}
</div>
<p class="text-right text-xs">(点击重试)</p>
</div> </div>
<div v-else> <div v-else>
<!-- 正式内容 --> <!-- 正式内容 -->
<span v-if="empty" class="text-center text-2xl font-bold">最近没有动态</span> <div v-if="empty">
<div v-if="empty" class="flex items-center justify-center gap-8" @click="handleReload">
<p class="text-2xl text-gray-700 border-2 border-black py-2 px-8 rounded-full rounded-br-lg">最近没有动态~</p>
<img class="h-32 w-auto relative" src="~/assets/images/common/plana_e.png" alt="">
</div>
<p class="text-right text-xs">(点击重试)</p>
</div>
<slot v-else name="default"/> <slot v-else name="default"/>
</div> </div>
</div> </div>

View File

@ -43,7 +43,9 @@ export function get<DataT, ErrorT>(url: string, options?: UseFetchOptions<DataT>
return async (): Promise<DataT> => { return async (): Promise<DataT> => {
if (result != null) { if (result != null) {
await result.refresh() await result.refresh()
return result.data.value if (result.status.value === 'success')
return result.data.value
throw result.error
} }
result = await requestCore(url, { result = await requestCore(url, {

View File

@ -0,0 +1,4 @@
export default defineNuxtRouteMiddleware(() => {
const {$mitt} = useNuxtApp()
$mitt.emit('startLoading', true)
})

View File

@ -1,5 +1,5 @@
export default defineNuxtRouteMiddleware((to, from) =>{ export default defineNuxtRouteMiddleware((to, _) => {
if (to.meta.maintenance === true && !import.meta.env.DEV) if (to.meta.maintenance === true && import.meta.env.DEV)
return navigateTo('/error/maintenance') return navigateTo('/error/maintenance')
return true return true
}) })

View File

@ -47,5 +47,8 @@ export default defineNuxtConfig({
gitApiKey: 'fb8aec429ea7d0a36f7238dbffda9d2d66c7b045', gitApiKey: 'fb8aec429ea7d0a36f7238dbffda9d2d66c7b045',
baseURL: 'https://cantyonion.site' baseURL: 'https://cantyonion.site'
} }
},
devServer: {
host: '0.0.0.0'
} }
}) })

View File

@ -1,6 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import {computed, onMounted, ref} from "vue"; import {computed, onMounted, ref} from "vue";
type errObj = {
blog?: object,
git?: object
}
const {$mitt} = useNuxtApp() const {$mitt} = useNuxtApp()
const recentPosts = ref<IPost[] | null>(null); const recentPosts = ref<IPost[] | null>(null);
const recentActivities = ref<IActivity[] | null>(null); const recentActivities = ref<IActivity[] | null>(null);
@ -12,9 +17,18 @@ const isError = ref({
blog: false, blog: false,
git: false git: false
}); });
const errMsg = ref<errObj>({
blog: undefined,
git: undefined
})
const config = useRuntimeConfig() const config = useRuntimeConfig()
const getBlogRecentPost = get<IBlogResponse<IPostsData>, any>('/blog/index.php/api/posts') const getBlogRecentPost = get<IBlogResponse<IPostsData>, any>('/blog/index.php/api/posts', {
params: {
showDigest: "excerpt",
limit: 100
}
})
const getActivity = get<IActivity[], any>('/git/api/v1/users/cantyonion/activities/feeds', { const getActivity = get<IActivity[], any>('/git/api/v1/users/cantyonion/activities/feeds', {
headers: { headers: {
Authorization: ` ${config.public.gitApiKey}` Authorization: ` ${config.public.gitApiKey}`
@ -51,10 +65,13 @@ const activitiesData = computed((): IActivity<IContent>[] => {
const reloadPosts = async () => { const reloadPosts = async () => {
try { try {
isLoading.value.blog = true isLoading.value.blog = true
isError.value.blog = false
const postData = await getBlogRecentPost() const postData = await getBlogRecentPost()
recentPosts.value = postData!.data.dataSet if (postData !== null)
recentPosts.value = postData.data.dataSet
} catch (e) { } catch (e) {
isError.value.blog = true isError.value.blog = true
errMsg.value.blog = e as object
} }
finally { finally {
isLoading.value.blog = false isLoading.value.blog = false
@ -64,16 +81,18 @@ const reloadPosts = async () => {
const reloadActivities = async () => { const reloadActivities = async () => {
try { try {
isLoading.value.git = true isLoading.value.git = true
isError.value.git = false
recentActivities.value = await getActivity() recentActivities.value = await getActivity()
} catch (e) { } catch (e) {
isError.value.git = true isError.value.git = true
errMsg.value.git = e as object
} }
finally { finally {
isLoading.value.git = false isLoading.value.git = false
} }
} }
await Promise.all([reloadPosts(), reloadActivities()]) await Promise.allSettled([reloadPosts(), reloadActivities()])
onMounted(() => { onMounted(() => {
$mitt.emit('startLoading', false) $mitt.emit('startLoading', false)
@ -84,16 +103,15 @@ onMounted(() => {
<!-- 个人介绍 --> <!-- 个人介绍 -->
<card-full-screen-intro-card/> <card-full-screen-intro-card/>
<div class="container mx-auto mt-8 xl:max-w-screen-xl"> <div class="container mx-auto xl:max-w-screen-xl">
<!-- 博客部分 --> <!-- 博客部分 -->
<section class="w-full px-4 sm:px-0"> <section class="w-full px-4 sm:px-0">
<!-- 标题部分 --> <!-- 标题部分 -->
<card-title :icon="['fas', 'blog']" main-color="bg-rose-500" sub-color="bg-rose-600" title="最新博文" <card-title :icon="['fas', 'blog']" title="最近文章"/>
url="/blog/"/>
<card-section-card :empty="!hasPosts" :error="isError.blog" :loading="isLoading.blog" @reload="reloadPosts"> <card-section-card :empty="!hasPosts" :error="isError.blog" :loading="isLoading.blog" @reload="reloadPosts" :err-msg="errMsg.blog">
<template v-slot:default> <template v-slot:default>
<div class="grid w-full grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4"> <div class="grid w-full grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3">
<card-article-card v-for="item in postsData" :key="item.cid" :post="item"/> <card-article-card v-for="item in postsData" :key="item.cid" :post="item"/>
</div> </div>
</template> </template>
@ -102,10 +120,9 @@ onMounted(() => {
<!-- Git部分 --> <!-- Git部分 -->
<section class="my-4 w-full px-4 sm:px-0"> <section class="my-4 w-full px-4 sm:px-0">
<card-title :icon="['fas', 'code']" main-color="bg-green-500" sub-color="bg-green-600" title="最近活动" <card-title :icon="['fas', 'code']" title="最近活动"/>
url="/git/"/>
<card-section-card :empty="!hasActivities" :error="isError.git" :loading="isLoading.git" @reload="reloadActivities"> <card-section-card :empty="!hasActivities" :error="isError.git" :loading="isLoading.git" @reload="reloadActivities" :err-msg="errMsg.git">
<template v-slot:default> <template v-slot:default>
<div class="grid w-full grid-cols-1 gap-4 lg:grid-cols-2"> <div class="grid w-full grid-cols-1 gap-4 lg:grid-cols-2">
<card-git-card v-for="item in activitiesData" :key="item.id" :commit="item"/> <card-git-card v-for="item in activitiesData" :key="item.id" :commit="item"/>