Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v3.1 - Full Static #28

Merged
merged 17 commits into from
Feb 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions api/stats.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Octokit } from '@octokit/rest'

const octokit = new Octokit({
auth: process.env.GITHUB_TOKEN,
})

export default async (_request, response) => {
const pagination = {
total: 1,
current: 1,
}

const per_page = 100

const authors = new Set()
const languages = new Set()
let repositories = 0

do {
const response = await octokit.search.repos({
q: 'topic:uanl',
page: pagination.current,
per_page,
})

repositories = Math.max(response.data.total_count)

pagination.total = Math.ceil(repositories / per_page)

response.data.items.forEach((repository) => {
authors.add(repository.owner.login)

if (repository.language) {
languages.add(repository.language)
}
})

++pagination.current
} while (pagination.current <= pagination.total)

response.setHeader(
'Cache-Control',
// Cache response on client for 5 minutes and on network for 1 day
'max-age=300, s-maxage=86400, stale-while-revalidate'
)
response.status(200).json({
authors: authors.size,
languages: languages.size,
repositories,
})
}
85 changes: 85 additions & 0 deletions components/Filters.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<template>
<div class="grid gap-x-8 gap-y-4 md:grid-cols-2 text-blue-900">
<!-- Search bar -->
<input
v-model.lazy="search"
class="w-full md:max-w-lg bg-gray-100 focus:bg-white placeholder-blue-900 placeholder-opacity-80 border-blue-900 rounded-lg"
type="search"
placeholder="Buscar Repositorios"
aria-label="Buscar Repositorios"
/>

<!-- Sorting -->
<label
class="min-w-0 flex items-center justify-between md:justify-end space-x-2"
>
<span class="whitespace-nowrap">Ordenar por</span>

<select
v-model="filter"
class="min-w-0 bg-gray-100 focus:bg-white border-blue-900 rounded-lg truncate pl-2 md:pl-4 py-2"
>
<option :value="{ sort: undefined, order: undefined }">
Mejor resultado
</option>
<option :value="{ sort: 'stars', order: 'desc' }">
Más estrellas &nbsp;
</option>
<option :value="{ sort: 'stars', order: 'asc' }">
Menos estrellas
</option>
<option :value="{ sort: 'forks', order: 'desc' }">
Más copias (Forks)
</option>
<option :value="{ sort: 'forks', order: 'asc' }">
Menos copias (Forks)
</option>
<option :value="{ sort: 'updated', order: 'desc' }">
Actualizaciones recientes
</option>
<option :value="{ sort: 'updated', order: 'asc' }">
Actualizaciones menos recientes
</option>
</select>
</label>
</div>
</template>

<script lang="ts">
import { defineComponent, ref, watch } from '@nuxtjs/composition-api'
import { RepositorySearchParameters } from '~/hooks/octokit'
import { repos } from '~/hooks/repos'
import { searchFilters, searchPagination } from '~/hooks/search'

export default defineComponent({
name: 'Filters',

setup(_props, { emit }) {
const search = ref<string>('')
const filter = ref<Pick<RepositorySearchParameters, 'sort' | 'order'>>({
sort: undefined,
order: undefined,
})

watch([search, filter], () => {
searchFilters.q = search.value

searchFilters.sort = filter.value.sort

searchFilters.order = filter.value.order

repos.clear()

searchPagination.total = 1
searchPagination.current = 1

emit('update')
})

return {
search,
filter,
}
},
})
</script>
39 changes: 39 additions & 0 deletions components/IntersectionObserver.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<div ref="root" class="observer" />
</template>

<script lang="ts">
import {
defineComponent,
onMounted,
onUnmounted,
ref,
} from '@nuxtjs/composition-api'

export default defineComponent({
setup(_props, { emit }) {
const root = ref<Element | null>(null)
let observer: IntersectionObserver | null = null

onMounted(() => {
observer = new IntersectionObserver(([entry]) => {
if (entry && entry.isIntersecting) {
emit('intersect')
}
})

if (root.value) {
observer.observe(root.value)
}
})

onUnmounted(() => {
observer?.disconnect()
})

return {
root,
}
},
})
</script>
55 changes: 19 additions & 36 deletions components/Repo/RepoCard.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
<template>
<div
class="flex flex-col justify-between bg-white rounded-lg hover:shadow-xl divide-y overflow-hidden transform ease-out duration-200 hover:-translate-y-1"
class="flex flex-col justify-between bg-white rounded-lg shadow hover:shadow-xl divide-y overflow-hidden transform ease-out duration-200 hover:-translate-y-1"
>
<!-- Repo Description -->
<a
:href="url"
:href="repository.html_url"
class="relative block p-4 sm:p-6 group"
target="_blank"
rel="noopener"
>
<div class="flex flex-col space-y-2">
<img
class="w-14 h-14 rounded-full"
:src="image"
:src="repository.owner.avatar_url"
alt="Author's Avatar"
/>
<h2 class="text-gray-900 text-xl overflow-hidden overflow-ellipsis">
{{ name }}
</h2>
<h2
class="text-gray-900 text-xl overflow-hidden overflow-ellipsis"
v-text="repository.name"
/>
<p
class="text-gray-500 group-hover:text-gray-900 transition-colors ease-out duration-200"
>
{{ description }}
</p>
v-if="repository.description"
class="text-gray-700 group-hover:text-gray-900 line-clamp-3 transition-colors ease-out duration-200"
v-text="repository.description"
/>
</div>

<div class="fixed right-0 top-0 p-4">
Expand All @@ -44,22 +45,22 @@
class="flex-shrink-0 w-4 sm:w-5 h-4 sm:h-5 group-hover:text-blue-500"
/>

<span v-if="language">{{ language }}</span>
<span v-if="repository.language" v-text="repository.language" />
<span v-else class="italic">N/A</span>
</div>

<!-- Stars -->
<a
class="flex items-center justify-center hover:bg-gray-200 hover:text-gray-900 p-4 sm:p-6 space-x-1 group"
:href="`${url}/stargazers`"
:href="`${repository.html_url}/stargazers`"
target="_blank"
rel="noopener"
>
<star-icon
class="flex-shrink-0 w-4 sm:w-5 h-4 sm:h-5 group-hover:text-amber-600"
/>

<span>{{ stars }}</span>
<span v-text="repository.stargazers_count" />
</a>

<!-- License -->
Expand All @@ -68,43 +69,25 @@
>
<scale-icon class="flex-shrink-0 w-4 sm:w-5 h-4 sm:h-5" />

<span v-if="license">
{{ license }}
</span>
<span v-if="repository.license" v-text="repository.license.spdx_id" />
<span v-else class="group-hover:text-gray-500 italic">N/A</span>
</div>
</div>
</div>
</template>

<script>
<script lang="ts">
import { defineComponent } from '@nuxtjs/composition-api'

import ExternalLinkIcon from '@/components/icons/ExternalLinkIcon.vue'
import CodeIcon from '@/components/icons/CodeIcon'
import StarIcon from '@/components/icons/StarIcon'
import ScaleIcon from '@/components/icons/ScaleIcon'
import { Repository } from '~/hooks/octokit'

export default defineComponent({
name: 'RepoCard',
components: { ExternalLinkIcon, ScaleIcon, StarIcon, CodeIcon },

props: {
repository: {
type: Object,
type: Object as () => Repository,
required: true,
},
},

setup({ repository }) {
return {
url: repository.html_url,
name: repository.name,
description: repository.description,
image: repository.owner.avatar_url,
language: repository.language,
stars: repository.stargazers_count,
license: repository.license?.spdx_id,
}
},
})
</script>
11 changes: 0 additions & 11 deletions components/Repo/RepoPlaceholder.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,3 @@
</div>
</div>
</template>

<script>
import CodeIcon from '@/components/icons/CodeIcon'
import StarIcon from '@/components/icons/StarIcon'
import ScaleIcon from '@/components/icons/ScaleIcon'

export default {
name: 'RepoPlaceholder',
components: { ScaleIcon, StarIcon, CodeIcon },
}
</script>
Loading