style modify
This commit is contained in:
parent
75167ae9e7
commit
fb109cd9ba
BIN
assets/images/common/plana_e.png
Normal file
BIN
assets/images/common/plana_e.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
@ -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>
|
||||||
|
@ -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>
|
@ -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>
|
||||||
|
@ -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>
|
||||||
|
@ -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()
|
||||||
|
if (result.status.value === 'success')
|
||||||
return result.data.value
|
return result.data.value
|
||||||
|
throw result.error
|
||||||
}
|
}
|
||||||
|
|
||||||
result = await requestCore(url, {
|
result = await requestCore(url, {
|
||||||
|
4
middleware/00.loading.global.ts
Normal file
4
middleware/00.loading.global.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export default defineNuxtRouteMiddleware(() => {
|
||||||
|
const {$mitt} = useNuxtApp()
|
||||||
|
$mitt.emit('startLoading', true)
|
||||||
|
})
|
@ -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
|
||||||
})
|
})
|
@ -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'
|
||||||
}
|
}
|
||||||
})
|
})
|
@ -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"/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user