feat: add possibility to list specific repositories
ListRepositories will now fetch repos with FetchRepositories only if no repositories are already passed to the component in its default slot.
This commit is contained in:
parent
1678100198
commit
1e3e15ab4e
@ -1,7 +1,8 @@
|
|||||||
import { defineClientConfig } from '@vuepress/client';
|
import { defineClientConfig } from '@vuepress/client';
|
||||||
import ResponsiveImage from './components/ResponsiveImage.vue';
|
import ResponsiveImage from './components/ResponsiveImage.vue';
|
||||||
import ListRepositories from './components/GitRepos/ListRepositories.vue';
|
import ListRepositories from './components/GitHub/ListRepositories.vue';
|
||||||
import GithubRepository from './components/GitRepos/GithubRepository.vue';
|
import FetchRepositories from './components/GitHub/FetchRepositories.vue';
|
||||||
|
import GithubRepository from './components/GitHub/GithubRepository.vue';
|
||||||
import ApiLoader from './components/ApiLoader.vue';
|
import ApiLoader from './components/ApiLoader.vue';
|
||||||
import Loader from './components/Loader.vue';
|
import Loader from './components/Loader.vue';
|
||||||
import Cache from './components/Cache.vue';
|
import Cache from './components/Cache.vue';
|
||||||
@ -10,6 +11,7 @@ export default defineClientConfig({
|
|||||||
enhance({ app }) {
|
enhance({ app }) {
|
||||||
app.component('ResponsiveImage', ResponsiveImage);
|
app.component('ResponsiveImage', ResponsiveImage);
|
||||||
app.component('ListRepositories', ListRepositories);
|
app.component('ListRepositories', ListRepositories);
|
||||||
|
app.component('FetchRepositories', FetchRepositories);
|
||||||
app.component('GithubRepository', GithubRepository);
|
app.component('GithubRepository', GithubRepository);
|
||||||
app.component('ApiLoader', ApiLoader);
|
app.component('ApiLoader', ApiLoader);
|
||||||
app.component('Loader', Loader);
|
app.component('Loader', Loader);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<Cache
|
<Cache
|
||||||
:name="props.cacheName"
|
:name="props.cacheName"
|
||||||
:callback="fetchData"
|
:callback="fetchData"
|
||||||
:data="alreadyKnownData"
|
:already-known-data="alreadyKnownData"
|
||||||
@cached="processCachedData"
|
@cached="processCachedData"
|
||||||
/>
|
/>
|
||||||
<slot v-if="loading" name="loader">
|
<slot v-if="loading" name="loader">
|
||||||
|
@ -19,7 +19,7 @@ const props = defineProps({
|
|||||||
required: false,
|
required: false,
|
||||||
type: Number,
|
type: Number,
|
||||||
},
|
},
|
||||||
data: {
|
alreadyKnownData: {
|
||||||
default: null,
|
default: null,
|
||||||
type: Object,
|
type: Object,
|
||||||
},
|
},
|
||||||
@ -50,14 +50,20 @@ const storeInCache = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (isDataOutdated(props.name)) {
|
if (isDataOutdated(props.name)) {
|
||||||
emits('cached', storeInCache(props.callback, props.data, props.name));
|
emits(
|
||||||
|
'cached',
|
||||||
|
storeInCache(props.callback, props.alreadyKnownData, props.name)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
let data = localStorage.getItem(props.name);
|
let data = localStorage.getItem(props.name);
|
||||||
try {
|
try {
|
||||||
emits('cached', of(JSON.parse(data)));
|
emits('cached', of(JSON.parse(data)));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(`Could not parse data found in cache: ${err}`);
|
console.error(`Could not parse data found in cache: ${err}`);
|
||||||
emits('cached', storeInCache(props.callback, props.data, props.name));
|
emits(
|
||||||
|
'cached',
|
||||||
|
storeInCache(props.callback, props.alreadyKnownData, props.name)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
48
content/.vuepress/components/GitHub/FetchRepositories.vue
Normal file
48
content/.vuepress/components/GitHub/FetchRepositories.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<template>
|
||||||
|
<ApiLoader :url="fetchUrl" @dataLoaded="filterRepos" cache-name="repos" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { PropType } from 'vue';
|
||||||
|
import { GithubRepo } from '../../composables/github';
|
||||||
|
const props = defineProps({
|
||||||
|
sortBy: {
|
||||||
|
default: 'none',
|
||||||
|
required: false,
|
||||||
|
type: String as PropType<'stars' | 'forks' | 'pushed_at'>,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
default: 5,
|
||||||
|
required: false,
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emits = defineEmits(['dataLoaded']);
|
||||||
|
|
||||||
|
const fetchUrl = `https://api.github.com/users/${props.user}/repos?per_page=100`;
|
||||||
|
|
||||||
|
const filterRepos = (response: GithubRepo[]) => {
|
||||||
|
emits(
|
||||||
|
'dataLoaded',
|
||||||
|
response
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (props.sortBy === 'stars') {
|
||||||
|
return b.stargazers_count - a.stargazers_count;
|
||||||
|
}
|
||||||
|
if (props.sortBy === 'pushed_at') {
|
||||||
|
const dateA = new Date(a.pushed_at);
|
||||||
|
const dateB = new Date(b.pushed_at);
|
||||||
|
return dateB.getTime() - dateA.getTime();
|
||||||
|
}
|
||||||
|
return b.forks_count - a.forks_count;
|
||||||
|
})
|
||||||
|
.slice(0, +props.limit)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
</script>
|
@ -1,5 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="githubRepo flex-row flex-space-between gap-1rem rounded-corners">
|
<div
|
||||||
|
class="githubRepo flex-row flex-space-between gap-1rem rounded-corners center"
|
||||||
|
>
|
||||||
<ApiLoader
|
<ApiLoader
|
||||||
:cache-name="repoName()"
|
:cache-name="repoName()"
|
||||||
:url="fetchUrl"
|
:url="fetchUrl"
|
||||||
@ -7,16 +9,16 @@
|
|||||||
@data-loaded="(repo: GithubRepo) => (repository = repo)"
|
@data-loaded="(repo: GithubRepo) => (repository = repo)"
|
||||||
>
|
>
|
||||||
<div class="flex-col info">
|
<div class="flex-col info">
|
||||||
<h3>{{ props.data.name }}</h3>
|
<h3>{{ repository.name }}</h3>
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
{{ props.data.description }}
|
{{ repository.description }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-col flex-start gap-1rem stats">
|
<div class="flex-col flex-start gap-1rem stats">
|
||||||
<p>Stars: {{ data.stargazers_count }}</p>
|
<p>Stars: {{ repository.stargazers_count }}</p>
|
||||||
<p>Forks: {{ data.forks_count }}</p>
|
<p>Forks: {{ repository.forks_count }}</p>
|
||||||
</div>
|
</div>
|
||||||
</ApiLoader>
|
</ApiLoader>
|
||||||
</div>
|
</div>
|
||||||
@ -31,7 +33,6 @@ import { PropType, Ref, ref } from 'vue';
|
|||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
data: Object as PropType<GithubRepo>,
|
data: Object as PropType<GithubRepo>,
|
||||||
repoName: String,
|
repoName: String,
|
||||||
fetcher: String as PropType<'gitea' | 'github'>,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const repoName = (): string => {
|
const repoName = (): string => {
|
50
content/.vuepress/components/GitHub/ListRepositories.vue
Normal file
50
content/.vuepress/components/GitHub/ListRepositories.vue
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<template>
|
||||||
|
<div v-if="props.user !== ''" class="list-repos flex-col gap-1rem">
|
||||||
|
<FetchRepositories
|
||||||
|
:sort-by="props.sortBy"
|
||||||
|
:user="props.user"
|
||||||
|
:limit="props.limit"
|
||||||
|
@data-loaded="(response: GithubRepo[]) => (repos = response)"
|
||||||
|
/>
|
||||||
|
<GithubRepository :data="repo" type="repositories" v-for="repo in repos" />
|
||||||
|
</div>
|
||||||
|
<div v-else class="list-repos flex-col gap-1rem">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import FetchRepositories from './FetchRepositories.vue';
|
||||||
|
import GithubRepository from './GithubRepository.vue';
|
||||||
|
|
||||||
|
import { PropType, Ref, ref } from 'vue';
|
||||||
|
import { GithubRepo } from '../../composables/github';
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
sortBy: {
|
||||||
|
default: 'none',
|
||||||
|
required: false,
|
||||||
|
type: String as PropType<'stars' | 'forks' | 'pushed_at'>,
|
||||||
|
},
|
||||||
|
user: {
|
||||||
|
default: '',
|
||||||
|
required: false,
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
limit: {
|
||||||
|
default: 5,
|
||||||
|
required: false,
|
||||||
|
type: Number,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const repos: Ref<GithubRepo[]> = ref(null);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="less">
|
||||||
|
@import '../../styles/classes.less';
|
||||||
|
|
||||||
|
.list-repos {
|
||||||
|
margin: 2rem auto;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,63 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="flex-col gap-1rem list-repos">
|
|
||||||
<ApiLoader :url="fetchUrl" @dataLoaded="filterRepos" cache-name="repos">
|
|
||||||
<GithubRepository
|
|
||||||
:data="repo"
|
|
||||||
type="repositories"
|
|
||||||
v-for="repo in repos"
|
|
||||||
class="center"
|
|
||||||
/>
|
|
||||||
</ApiLoader>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { PropType, Ref, ref } from 'vue';
|
|
||||||
import { GithubRepo } from '../../composables/github';
|
|
||||||
import GithubRepository from './GithubRepository.vue';
|
|
||||||
const props = defineProps({
|
|
||||||
sortBy: {
|
|
||||||
default: 'pushed_at',
|
|
||||||
required: false,
|
|
||||||
type: String as PropType<'stars' | 'forks' | 'pushed_at'>,
|
|
||||||
},
|
|
||||||
user: {
|
|
||||||
default: '',
|
|
||||||
required: true,
|
|
||||||
type: String,
|
|
||||||
},
|
|
||||||
limit: {
|
|
||||||
default: 5,
|
|
||||||
required: false,
|
|
||||||
type: Number,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
let repos: Ref<GithubRepo[]> = ref(null);
|
|
||||||
|
|
||||||
const fetchUrl = `https://api.github.com/users/${props.user}/repos?per_page=100`;
|
|
||||||
|
|
||||||
const filterRepos = (response: GithubRepo[]) => {
|
|
||||||
repos.value = response
|
|
||||||
.sort((a, b) => {
|
|
||||||
if (props.sortBy === 'stars') {
|
|
||||||
return b.stargazers_count - a.stargazers_count;
|
|
||||||
}
|
|
||||||
if (props.sortBy === 'pushed_at') {
|
|
||||||
const dateA = new Date(a.pushed_at);
|
|
||||||
const dateB = new Date(b.pushed_at);
|
|
||||||
return dateB.getTime() - dateA.getTime();
|
|
||||||
}
|
|
||||||
return b.forks_count - a.forks_count;
|
|
||||||
})
|
|
||||||
.slice(0, +props.limit);
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="less">
|
|
||||||
@import '../../styles/classes.less';
|
|
||||||
|
|
||||||
.list-repos {
|
|
||||||
margin: 2rem auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
Loading…
Reference in New Issue
Block a user