Skip to content

Commit

Permalink
reflect repo page
Browse files Browse the repository at this point in the history
  • Loading branch information
gusibi committed Oct 20, 2024
1 parent 92a08d8 commit 92694bc
Show file tree
Hide file tree
Showing 11 changed files with 286 additions and 45 deletions.
40 changes: 40 additions & 0 deletions components/PostRepoInfo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template>
<div class="text-center text-white">
<div class="mb-2">
<a :href="repoUrl" class="underline decoration-sky-500 text-base font-semibold hover:underline">
{{ repoOwner }}/{{ repoName }} </a>
</div>
<h1 class="text-3xl font-extrabold mb-4">{{ title }}</h1>
<div class="flex items-center justify-center">
<img :src="avatarUrl" :alt="author" class="w-10 h-10 rounded-full mr-3">
<div class="text-left">
<div class="font-medium">{{ author }}</div>
<div class="text-sm opacity-75">{{ formattedDate }}</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed } from 'vue'
const props = defineProps<{
repoOwner: string
repoName: string
title: string
avatarUrl: string
author: string
createdAt: string
}>()
const repoUrl = computed(() => `/repo/${props.repoOwner}/${props.repoName}`)
const formattedDate = computed(() => {
const date = new Date(props.createdAt)
return new Intl.DateTimeFormat('en-US', {
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
}).format(date)
})
</script>
11 changes: 6 additions & 5 deletions components/RepoInfo.vue
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
<template>
<div class="bg-white dark:bg-gray-800 shadow-md pt-16 p-6 mb-8 w-full text-center">
<div class="bg-card-light dark:bg-card-dark shadow-md pt-16 p-6 mb-8 w-full text-center">
<!-- Labels row -->
<div class="flex items-center justify-center mb-4 relative">
<button @click="scrollLabels('left')" class="absolute left-0 bg-white dark:bg-gray-800 bg-opacity-75 p-1 rounded-full shadow-md z-10" v-show="showLeftArrow">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z" clip-rule="evenodd"></path>
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" />
</svg>
</button>
<div class="overflow-hidden mx-8" style="max-width: calc(100% - 4rem);">
Expand All @@ -15,8 +15,8 @@
</div>
</div>
<button @click="scrollLabels('right')" class="absolute right-0 bg-white dark:bg-gray-800 bg-opacity-75 p-1 rounded-full shadow-md z-10" v-show="showRightArrow">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z" clip-rule="evenodd"></path>
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
</svg>
</button>
</div>
Expand Down Expand Up @@ -59,6 +59,7 @@ const props = defineProps({
}
})
const getContrastColor = (hexColor: string) => {
// 将十六进制颜色转换为RGB
const r = parseInt(hexColor.slice(0, 2), 16);
Expand Down
132 changes: 132 additions & 0 deletions components/RepoInfoHtml.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<template>
<div class="w-full pt-16">
<!-- Labels row -->
<div class="flex items-center justify-center relative">
<button @click="scrollLabels('left')" class="absolute left-0 bg-white dark:bg-gray-800 bg-opacity-75 p-1 rounded-full shadow-md z-10" v-show="showLeftArrow">
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z" clip-rule="evenodd" />
</svg>
</button>
<div class="overflow-hidden mx-8" style="max-width: calc(100% - 4rem);">
<div class="flex space-x-2 overflow-x-auto scrollbar-hide" ref="labelContainer" @scroll="checkArrows">
<NuxtLink v-for="label in repo.labels" :key="label.name" :to="`/repo/${repo.owner_name}/${repo.name}/tag/${encodeURIComponent(label.name)}`" class="text-l rounded-full px-3 py-1 whitespace-nowrap cursor-pointer transition-opacity hover:opacity-80" :style="{ backgroundColor: `#${label.color}`, color: getContrastColor(label.color) }">
{{ label.name }}
</NuxtLink>
</div>
</div>
<button @click="scrollLabels('right')" class="absolute right-0 bg-white dark:bg-gray-800 bg-opacity-75 p-1 rounded-full shadow-md z-10" v-show="showRightArrow">
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z" clip-rule="evenodd" />
</svg>
</button>
</div>
<!-- Repo name -->
<h2 class="text-4xl pt-8 text-center font-bold mb-2">
<a :href="repo.repo_url" class="hover:underline">
{{ repoOwner }}/{{ repoName }} </a>
</h2>
<!-- Stars and Issues count -->
<div class="flex items-center justify-center space-x-4 text-m text-gray-600 py-2 dark:text-gray-400 mb-2">
<span class="flex items-center">
<svg class="w-5 h-5 mr-1" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</svg>
{{ repo.stars }} stars </span>
<span class="flex items-center">
<svg class="w-5 h-5 mr-1" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M12 8V12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
<path d="M12 16H12.01" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
</svg>
{{ repo.issues }} issues </span>
</div>
<!-- Repo description -->
<p class="text-gray-600 text-m pb-4 dark:text-gray-300">{{ repo.description }}</p>
</div>
</template>
<script setup lang="ts">
import { NuxtLink } from '#components'
import { ref, onMounted, watch, nextTick } from 'vue'
const props = defineProps({
repo: {
type: Object,
required: true
},
repoOwner: {
type: String,
required: true
},
repoName: {
type: String,
required: true
}
})
const getContrastColor = (hexColor: string) => {
// 将十六进制颜色转换为RGB
const r = parseInt(hexColor.slice(0, 2), 16);
const g = parseInt(hexColor.slice(2, 4), 16);
const b = parseInt(hexColor.slice(4, 6), 16);
// 计算亮度
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
// 如果亮度大于 128,返回黑色,否则返回白色
return brightness > 128 ? '#000000' : '#FFFFFF';
}
const labelContainer = ref(null)
const showLeftArrow = ref(false)
const showRightArrow = ref(false)
const checkArrows = () => {
if (labelContainer.value) {
showLeftArrow.value = labelContainer.value.scrollLeft > 0
showRightArrow.value = labelContainer.value.scrollWidth > labelContainer.value.clientWidth &&
labelContainer.value.scrollLeft < labelContainer.value.scrollWidth - labelContainer.value.clientWidth
}
}
const scrollLabels = (direction: 'left' | 'right') => {
if (labelContainer.value) {
const scrollAmount = labelContainer.value.clientWidth / 2
labelContainer.value.scrollBy({
left: direction === 'left' ? -scrollAmount : scrollAmount,
behavior: 'smooth'
})
nextTick(() => {
checkArrows()
})
}
}
onMounted(() => {
nextTick(() => {
checkArrows()
})
window.addEventListener('resize', checkArrows)
})
watch(() => props.repo, () => {
nextTick(() => {
checkArrows()
})
})
// Clean up event listener
onUnmounted(() => {
window.removeEventListener('resize', checkArrows)
})
</script>
<style scoped>
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
</style>
10 changes: 7 additions & 3 deletions layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,15 @@
</div>
</div>
</div>
<div v-if="showBanner" class="pt-8 relative h-64 overflow-hidden">
<div v-if="showBanner" class="pt-12 relative h-64 overflow-hidden w-full">
<img class="w-full h-full object-cover blur-sm" :src="bannerImageUrl" alt="Site Banner" />
<div class="absolute inset-0 flex items-center justify-center dark:bg-black dark:bg-opacity-50">
<div v-html="bannerContent"></div>
<div class="w-full max-w-screen-xl mx-auto px-4">
<div v-html="bannerContent"></div>
</div>
</div>
</div>
<main class="flex-grow pt-8 pb-8 ">
<main class="flex-grow pt-8 pb-8">
<slot />
</main>
<footer class="bg-card-light dark:bg-card-dark py-4">
Expand All @@ -113,6 +115,7 @@ import { useRouter } from 'vue-router'
const router = useRouter()
const { bannerContent, bannerImageUrl, showBanner } = useBannerContent()
const nightModeIcon = ref('🌙')
const mobileMenuOpen = ref(false)
const mobileFriendLinksOpen = ref(false)
Expand Down Expand Up @@ -198,6 +201,7 @@ onMounted(() => {
addScrollEventListener()
})
// SEO优化
useHead({
titleTemplate: (titleChunk) => {
Expand Down
3 changes: 2 additions & 1 deletion pages/about.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import { useAsyncData } from '#app'
import { useRoute } from 'vue-router'
import { useSupabaseUser } from '#imports'
import { useBannerContentInjection } from '~/composables/useBannerContent'
const { setBannerContent, setBannerImage } = useBannerContentInjection()
const { setBannerContent, setBannerImage, setShowBanner } = useBannerContentInjection()
const user = useSupabaseUser()
Expand Down Expand Up @@ -139,5 +139,6 @@ if (post.value) {
</div>
`)
setBannerImage('/banner3.jpeg')
setShowBanner(true)
}
</script>
5 changes: 3 additions & 2 deletions pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<script setup lang="ts">
import { ref, watch } from 'vue'
import { useBannerContentInjection } from '~/composables/useBannerContent'
const { setBannerContent, setBannerImage } = useBannerContentInjection()
const { setBannerContent, setBannerImage, setShowBanner } = useBannerContentInjection()
const config = useRuntimeConfig()
const blogPosts = ref([])
Expand Down Expand Up @@ -39,6 +39,7 @@ const onPageChange = async (page: number) => {
onMounted(async () => {
// 设置 banner 内容
setBannerContent('<h1 class="text-4xl font-extrabold text-center text-white mb-6">古思乱讲</h1>')
// setBannerImage('/banner2.jpeg')
setBannerImage('/banner2.jpeg')
setShowBanner(true)
})
</script>
41 changes: 23 additions & 18 deletions pages/repo/[repo_owner]/[repo_name]/blog/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@
</main>
</template>
<script setup lang="ts">
import { h, render, createApp } from 'vue'
import { useAsyncData } from '#app'
import { useRoute } from 'vue-router'
import { useSupabaseUser } from '#imports'
import { useBannerContentInjection } from '~/composables/useBannerContent'
const { setBannerContent, setBannerImage } = useBannerContentInjection()
const { setBannerContent, setBannerImage, setShowBanner } = useBannerContentInjection()
import PostRepoInfo from '~/components/PostRepoInfo.vue'
const user = useSupabaseUser()
Expand Down Expand Up @@ -126,23 +128,26 @@ const handleCommentSubmission = async (newComment: any) => {
}
if (post.value) {
setBannerContent(`
<div class="text-center text-white">
<div class="mb-2">
<a href="/repo/${route.params.repo_owner}/${route.params.repo_name}" class="underline decoration-sky-500 text-base font-semibold hover:underline">
${route.params.repo_owner}/${route.params.repo_name}
</a>
</div>
<h1 class="text-3xl font-extrabold mb-4 ">${post.value.title}</h1>
<div class="flex items-center justify-center">
<img src="${post.value.avatar_url}" alt="${post.value.author}" class="w-10 h-10 rounded-full mr-3">
<div class="text-left">
<div class="font-medium">${post.value.author}</div>
<div class="text-sm opacity-75">${formatDate(post.value.created_at)}</div>
</div>
</div>
</div>
`)
const app = createApp({
render() {
return h(PostRepoInfo, {
repoOwner: route.params.repo_owner,
repoName: route.params.repo_name,
title: post.value.title,
avatarUrl: post.value.avatar_url,
author: post.value.author,
createdAt: post.value.created_at
})
}
})
const container = document.createElement('div')
app.mount(container)
// 使用 nextTick 确保组件已经渲染
nextTick(() => {
setBannerContent(container.innerHTML)
app.unmount()
})
setBannerImage('/banner3.jpeg')
setShowBanner(true)
}
</script>
Loading

0 comments on commit 92694bc

Please sign in to comment.