mirror of https://github.com/nocodb/nocodb
DarkPhoenix2704
2 months ago
8 changed files with 295 additions and 50 deletions
@ -1,25 +1,15 @@ |
|||||||
<script setup lang="ts"> |
<script setup lang="ts"> |
||||||
const releases = ref< |
const { loadGithubFeed, githubFeed } = useProductFeed() |
||||||
{ |
|
||||||
body: string |
|
||||||
id: string |
|
||||||
published_at: string |
|
||||||
}[] |
|
||||||
>([]) |
|
||||||
|
|
||||||
const fetchReleaseNotes = async () => { |
|
||||||
const response = await fetch('https://api.github.com/repos/nocodb/nocodb/releases') |
|
||||||
const data = await response.json() |
|
||||||
return data |
|
||||||
} |
|
||||||
|
|
||||||
onMounted(async () => { |
onMounted(async () => { |
||||||
releases.value = await fetchReleaseNotes() |
await loadGithubFeed() |
||||||
}) |
}) |
||||||
</script> |
</script> |
||||||
|
|
||||||
<template> |
<template> |
||||||
<FeedChangelogItem v-for="feed in releases" :key="feed.id" :date="feed.published_at" :body="feed?.body" /> |
<div class="max-w-260 mx-auto"> |
||||||
|
<FeedChangelogItem v-for="feed in githubFeed" :key="feed.id" :date="feed.published_at" :body="feed?.body" /> |
||||||
|
</div> |
||||||
</template> |
</template> |
||||||
|
|
||||||
<style scoped lang="scss"></style> |
<style scoped lang="scss"></style> |
||||||
|
@ -0,0 +1,49 @@ |
|||||||
|
<script setup lang="ts"> |
||||||
|
const iFrame = ref<HTMLIFrameElement | null>(null) |
||||||
|
|
||||||
|
const isLoaded = ref(false) |
||||||
|
|
||||||
|
const handleIframeLoad = () => { |
||||||
|
if (!iFrame.value) { |
||||||
|
return |
||||||
|
} |
||||||
|
const iframeDocument = iFrame.value?.contentDocument || iFrame.value?.contentWindow?.document |
||||||
|
|
||||||
|
const classList = ['.nc-table-topbar', '.nc-table-toolbar'] |
||||||
|
|
||||||
|
for (const className of classList) { |
||||||
|
nextTick(() => { |
||||||
|
const element = iframeDocument?.querySelector(className) |
||||||
|
|
||||||
|
if (element) { |
||||||
|
element.remove() |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
isLoaded.value = true |
||||||
|
} |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<div |
||||||
|
:class="{ |
||||||
|
'hidden': !isLoaded, |
||||||
|
'block h-full': isLoaded, |
||||||
|
}" |
||||||
|
> |
||||||
|
<iframe |
||||||
|
ref="iFrame" |
||||||
|
src="http://localhost:3000/#/nc/kanban/dc9d297d-2d89-4a33-9804-87924148913a" |
||||||
|
width="100%" |
||||||
|
height="100%" |
||||||
|
style="border: none" |
||||||
|
@load="handleIframeLoad" |
||||||
|
></iframe> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div v-if="!isLoaded" class="flex items-center justify-center h-full"> |
||||||
|
<NcLoader /> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<style scoped lang="scss"></style> |
@ -0,0 +1,53 @@ |
|||||||
|
<script setup lang="ts"> |
||||||
|
import Plyr from 'plyr' |
||||||
|
import 'plyr/dist/plyr.css' |
||||||
|
|
||||||
|
defineProps<{ |
||||||
|
body: string |
||||||
|
name: string |
||||||
|
published_at: string |
||||||
|
embed_url: string |
||||||
|
html_url: string |
||||||
|
}>() |
||||||
|
|
||||||
|
const videoPlayer = ref<HTMLElement>() |
||||||
|
|
||||||
|
const player = ref() |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
if (!videoPlayer.value) return |
||||||
|
player.value = new Plyr(videoPlayer.value, { |
||||||
|
previewThumbnails: {}, |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
onBeforeUnmount(() => { |
||||||
|
if (player.value) { |
||||||
|
player.value.destroy() |
||||||
|
} |
||||||
|
}) |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<div class="flex flex-col gap-5"> |
||||||
|
<div class="aspect-video !rounded-lg mx-auto !h-[428px]"> |
||||||
|
<div id="player" ref="videoPlayer" class="plyr__video-embed"> |
||||||
|
<iframe |
||||||
|
:src="`${embed_url}?origin=https://plyr.io&iv_load_policy=3&modestbranding=1&playsinline=1&showinfo=0&rel=0&enablejsapi=1`" |
||||||
|
allowfullscreen |
||||||
|
allowtransparency |
||||||
|
allow="autoplay" |
||||||
|
></iframe> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
{{ name }} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<style lang="scss"> |
||||||
|
.plyr--video { |
||||||
|
@apply !rounded-lg; |
||||||
|
} |
||||||
|
</style> |
@ -0,0 +1,23 @@ |
|||||||
|
<script setup lang="ts"> |
||||||
|
const { youtubeFeed, loadYoutubeFeed } = useProductFeed() |
||||||
|
|
||||||
|
onMounted(() => { |
||||||
|
loadYoutubeFeed() |
||||||
|
}) |
||||||
|
</script> |
||||||
|
|
||||||
|
<template> |
||||||
|
<div class="flex gap-2 flex-col"> |
||||||
|
<FeedYoutubePlayer |
||||||
|
v-for="feed in youtubeFeed" |
||||||
|
:key="feed.id" |
||||||
|
:html_url="feed.html_url" |
||||||
|
:name="feed.name" |
||||||
|
:body="feed.body" |
||||||
|
:published_at="feed.published_at" |
||||||
|
:embed_url="feed.embed_url" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</template> |
||||||
|
|
||||||
|
<style scoped lang="scss"></style> |
@ -0,0 +1,92 @@ |
|||||||
|
import axios from 'axios' |
||||||
|
|
||||||
|
const axiosInstance = axios.create({ |
||||||
|
// baseURL: 'https://nocodb.com/api',
|
||||||
|
baseURL: 'http://localhost:8000/api/v1', |
||||||
|
headers: { |
||||||
|
'Content-Type': 'application/json', |
||||||
|
}, |
||||||
|
}) |
||||||
|
|
||||||
|
export const useProductFeed = createSharedComposable(() => { |
||||||
|
const activeTab = ref('recents') |
||||||
|
|
||||||
|
const youtubeFeed = ref< |
||||||
|
{ |
||||||
|
id: string |
||||||
|
body: string |
||||||
|
name: string |
||||||
|
published_at: string |
||||||
|
thumbnails: { |
||||||
|
default: { |
||||||
|
height: number |
||||||
|
url: string |
||||||
|
width: number |
||||||
|
} |
||||||
|
high: { |
||||||
|
height: number |
||||||
|
url: string |
||||||
|
width: number |
||||||
|
} |
||||||
|
medium: { |
||||||
|
height: number |
||||||
|
url: string |
||||||
|
width: number |
||||||
|
} |
||||||
|
} |
||||||
|
embed_url: string |
||||||
|
html_url: string |
||||||
|
}[] |
||||||
|
>([]) |
||||||
|
const githubFeed = ref< |
||||||
|
{ |
||||||
|
body: string |
||||||
|
html_url: string |
||||||
|
id: string |
||||||
|
name: string |
||||||
|
published_at: string |
||||||
|
}[] |
||||||
|
>([]) |
||||||
|
|
||||||
|
const socialFeed = ref([]) |
||||||
|
|
||||||
|
const ytNextPageToken = ref('') |
||||||
|
|
||||||
|
const loadYoutubeFeed = async (loadMore?: boolean) => { |
||||||
|
const { data } = await axiosInstance.get('/social/youtube', { |
||||||
|
params: loadMore |
||||||
|
? { |
||||||
|
pageToken: ytNextPageToken.value, |
||||||
|
per_page: 10, |
||||||
|
} |
||||||
|
: { |
||||||
|
per_page: 10, |
||||||
|
}, |
||||||
|
}) |
||||||
|
ytNextPageToken.value = data.nextPageToken |
||||||
|
youtubeFeed.value = data.videos |
||||||
|
} |
||||||
|
|
||||||
|
const loadGithubFeed = async (loadMore?: boolean) => { |
||||||
|
const { data } = await axiosInstance.get('/social/github', { |
||||||
|
params: loadMore |
||||||
|
? { |
||||||
|
page: githubFeed.value.length / 10 + 1, |
||||||
|
per_page: 10, |
||||||
|
} |
||||||
|
: { |
||||||
|
per_page: 10, |
||||||
|
}, |
||||||
|
}) |
||||||
|
githubFeed.value = data |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
activeTab, |
||||||
|
youtubeFeed, |
||||||
|
githubFeed, |
||||||
|
socialFeed, |
||||||
|
loadYoutubeFeed, |
||||||
|
loadGithubFeed, |
||||||
|
} |
||||||
|
}) |
Loading…
Reference in new issue