Skip to content
Open
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
7 changes: 7 additions & 0 deletions components/Navbar.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
<template>
<!-- Navbar Header -->
<header class="w-full py-4 border-b border-ink-200 bg-ink-400">
<nav class="flex items-center justify-center flex-wrap">
<!-- App Logo and Home Link -->
<NuxtLink to="/" class="flex items-center text-gray-700 font-bold">
<img src="~/assets/gfi-logo-white.svg" alt="Good First Issue" class="h-12" />
</NuxtLink>

<!-- Active Language Tag Display -->
<span v-if="activeTag" class="text-2xl cursor-pointer">
<span class="font-normal ml-2 mr-1 text-slate">/</span>
<span class="font-semibold text-juniper">{{ activeTag.language }}</span>
Expand All @@ -13,10 +17,13 @@
</template>

<script setup>
// Import available tags from JSON file
import Tags from '~/data/tags.json'

// Access the current route using Nuxt's useRoute composable
const route = useRoute()

// Compute which tag is currently active based on the route parameter
const activeTag = computed(() => {
return Tags.find(tag => tag.slug === route.params.slug)
})
Expand Down
71 changes: 49 additions & 22 deletions components/RepoBox.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<template>
<!-- Repository Card -->
<div
:id="`repo-${repo.id}`"
:class="{
Expand All @@ -9,6 +10,7 @@
@click="toggle(repo.id)"
>
<div class="px-5 py-3">
<!-- Repo Header -->
<div class="flex flex-row">
<a
:title="`Open ${repo.owner}/${repo.name} on GitHub`"
Expand All @@ -17,21 +19,29 @@
rel="noopener noreferrer"
class="text-lg font-semibold group-hover:text-juniper"
:class="{ 'text-juniper': isCardOpen }"
>{{ repo.owner }} / {{ repo.name }}</a
>
{{ repo.owner }} / {{ repo.name }}
</a>
<span class="flex-1"></span>

<!-- Issue Counter -->
<span
class="hidden md:inline text-sm border px-3 py-1 ml-2 rounded-full font-semibold"
:class="{
'text-ink-400 bg-juniper border-transparent': isCardOpen,
'text-vanilla-200': !isCardOpen
}"
>{{ issuesDisplay }}</span
>
{{ issuesDisplay }}
</span>
</div>

<!-- Repo Description -->
<div class="flex-row flex text-sm py-1 overflow-auto">
{{ repo.description }}
</div>

<!-- Repo Metadata -->
<div
class="flex-row flex text-sm py-1 font-mono"
:class="{ 'text-honey': isCardOpen, 'text-vanilla-400': !isCardOpen }"
Expand All @@ -43,25 +53,42 @@
</div>
</div>
</div>

<!-- Repo Issues -->
<ol v-if="isCardOpen" class="px-5 py-3 text-base leading-loose border-t border-ink-200">
<li v-for="issue in repo.issues" :key="issue.url" class="flex flex-row items-start justify-start py-1">
<span class="text-slate text-right px-2 leading-snug font-mono" style="min-width: 70px">#{{ issue.number }}</span>
<li
v-for="issue in repo.issues"
:key="issue.url"
class="flex flex-row items-start justify-start py-1"
>
<span
class="text-slate text-right px-2 leading-snug font-mono"
style="min-width: 70px"
>
#{{ issue.number }}
</span>

<div class="flex items-start flex-row flex-auto">
<a
title="Open issue on GitHub"
title="Open this issue on GitHub"
:href="issue.url"
target="_blank"
rel="noopener noreferrer"
class="leading-snug font-medium hover:text-juniper text-vanilla-300 block flex-auto"
>{{ issue.title }}</a
>
{{ issue.title }}
</a>

<!-- Issue Comments Count -->
<div
v-if="issue.comments_count > 0"
class="flex flex-row items-center justify-end mt-1 w-10"
:title="getIssueCommentsCounterTooltip(issue)"
>
<ChatBubbleLeftRightIcon class="mt-px w-3.5 h-3.5" />
<span class="ml-1 text-sm leading-snug font-mono">{{ issue.comments_count }}</span>
<span class="ml-1 text-sm leading-snug font-mono">
{{ issue.comments_count }}
</span>
</div>
</div>
</li>
Expand All @@ -83,34 +110,34 @@ const props = defineProps({
}
})

// Shared store for open repository state
const openRepoId = useOpenRepoId()

// Display number of issues (pluralization handled)
const issuesDisplay = computed(() => {
const numIssues = props.repo.issues.length
return numIssues > 1 ? `${numIssues} issues` : `${numIssues} issue`
const issueCount = props.repo.issues.length
return issueCount > 1 ? `${issueCount} issues` : `${issueCount} issue`
})

// Show relative time since last modification
const lastModifiedDisplay = computed(() => {
return dayjs(props.repo.last_modified).fromNow()
})

const isCardOpen = computed(() => {
return openRepoId.value === props.repo.id
})
// Check if this card is currently open
const isCardOpen = computed(() => openRepoId.value === props.repo.id)

// Toggle open/close state of a repo card
function toggle(repoId) {
if (isCardOpen.value) {
openRepoId.value = null
} else {
openRepoId.value = repoId
}
openRepoId.value = isCardOpen.value ? null : repoId
}

// Tooltip for issue comment count
function getIssueCommentsCounterTooltip(issue) {
const numComments = issue.comments_count
if (numComments === 0) {
return `There are no comments on this issue`
}
return numComments > 1 ? `There are ${numComments} comments on this issue` : `There is one comment on this issue`
const count = issue.comments_count
if (count === 0) return `There are no comments on this issue`
return count > 1
? `There are ${count} comments on this issue`
: `There is one comment on this issue`
}
</script>
101 changes: 25 additions & 76 deletions components/Sidebar.vue
Original file line number Diff line number Diff line change
@@ -1,79 +1,28 @@
<template>
<section class="masthead font-sans pt-6 border-r border-ink-200 px-6 text-vanilla-300 flex-none w-full md:max-w-sm">
<div>
<h3 class="section-heading">About</h3>
<p class="text-sm">
Good First Issue curates easy pickings from popular open-source projects, and helps you make your first
contribution to open-source.
</p>
</div>
<div class="pt-6">
<h3 class="section-heading">Browse by language</h3>
<div>
<nuxt-link
v-for="tag in Tags"
:key="tag.slug"
:to="'/language/' + tag.slug"
:class="{
'active-pill': $route.params.slug === tag.slug,
'border-slate hover:text-juniper hover:border-juniper': $route.params.slug !== tag.slug
}"
class="group mx-1 border px-2 py-1 inline-block rounded-sm my-1 text-sm"
>{{ tag.language }}
<span
:class="{
'text-vanilla-400 group-hover:text-juniper': $route.params.slug !== tag.slug
}"
>&times; {{ tag.count }}</span
></nuxt-link
>
</div>
</div>
<div class="pt-6">
<a
class="bg-juniper hover:bg-light_juniper text-ink-400 uppercase rounded-md font-bold text-center px-1 py-3 flex flex-row items-center justify-center space-x-1"
href="https://github.com/deepsourcelabs/good-first-issue#adding-a-new-project"
target="_blank"
rel="noopener noreferrer"
>
<PlusCircleIcon class="h-5 w-5 stroke-2" />
<span>Add your project</span>
</a
>
</div>
<!-- Sidebar Section: Displays project info and navigation links -->
<section class="masthead font-sans pt-6 border-r border-ink-200 px-6 text-vanilla-300 flex-none w-full md:max-w-sm">

<div class="text-sm pt-6">
<a
class="flex flex-row justify-center items-center"
target="_blank"
rel="noopener noreferrer"
href="https://deepsource.com?ref=gfi"
>
<HeartIcon class="w-4 h-4 text-cherry" />
<span class="ml-2"
>A
<span class="inline hover:underline text-juniper" title="Visit DeepSource website">DeepSource</span>
initative</span
>
</a>
</div>
</section>
</template>
<!-- About Section -->
<div>
<h3 class="section-heading">About</h3>
<p class="text-sm">
Good First Issue curates easy pickings from popular open-source projects, and helps you make your first
contribution to open-source.
</p>
</div>

<script setup>
import Tags from '~/data/tags.json'
import { PlusCircleIcon } from '@heroicons/vue/24/outline'
import {HeartIcon} from '@heroicons/vue/24/solid'
</script>
<style>
.section-heading {
@apply text-sm font-bold uppercase tracking-wider mb-2 text-slate;
}
.active-pill {
@apply text-juniper font-semibold border-juniper;
}
<!-- Language Filter Section -->
<div class="pt-6">
<h3 class="section-heading">Browse by language</h3>
...
</div>

.active-pill > span {
@apply text-juniper;
}
</style>
<!-- Add Your Project Button -->
<div class="pt-6">
...
</div>

<!-- Footer -->
<div class="text-sm pt-6">
...
</div>
</section>
41 changes: 34 additions & 7 deletions components/SubscriptionForm.vue
Original file line number Diff line number Diff line change
@@ -1,21 +1,48 @@
<template>
<form method="post" action="https://listmonk.deepsource.io/subscription/form" class="listmonk-form">
<!-- Newsletter Subscription Form -->
<form
method="post"
action="https://listmonk.deepsource.io/subscription/form"
class="listmonk-form"
>
<div class="flex flex-row space-x-2 w-full">
<!-- Email Input Field -->
<input
class="bg-ink-300 text-vanilla-100 flex flex-grow h-10 text-sm py-2 px-3 rounded-sm w-full outline-none"
type="text"
type="email"
name="email"
placeholder="Enter your email"
aria-label="Email address"
placeholder="Enter your email to subscribe"
required
/>

<!-- Hidden checkboxes for list subscriptions -->
<div class="hidden">
<input id="59f61" type="checkbox" name="l" checked value="59f61a48-5867-4861-bde0-59a9027420e3" />
<input
id="59f61"
type="checkbox"
name="l"
checked
value="59f61a48-5867-4861-bde0-59a9027420e3"
/>
<label for="59f61">Good First Issue</label>
<input id="4c2a7" type="checkbox" name="l" checked value="4c2a780e-f85b-4d28-8a60-9e2a43f0e0d4" />

<input
id="4c2a7"
type="checkbox"
name="l"
checked
value="4c2a780e-f85b-4d28-8a60-9e2a43f0e0d4"
/>
<label for="4c2a7">Community newsletter</label>
</div>
<!-- prettier-ignore -->
<input class="bg-ink-300 hover:bg-ink-200 text-vanilla-100 rounded-md font-semibold text-center h-10 px-4 py-2 text-sm space-x-2 leading-8 cursor-pointer" type="submit" value="Subscribe" />

<!-- Submit Button -->
<input
class="bg-ink-300 hover:bg-ink-200 text-vanilla-100 rounded-md font-semibold text-center h-10 px-4 py-2 text-sm space-x-2 leading-8 cursor-pointer"
type="submit"
value="Subscribe"
/>
</div>
</form>
</template>