-
Notifications
You must be signed in to change notification settings - Fork 2
feat: implement pinboard for repositories #68
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
Changes from all commits
e93adb9
0a1e19a
f8973ac
31f5d58
f9cccd3
c38350d
f6d176e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,17 @@ const isDark = computed({ | |
| // Later use a store e.g. | ||
| const notificationCount = ref(3) | ||
|
|
||
| const { pinnedRepos, unpin } = usePinnedRepos() | ||
|
|
||
| const { update: updateSettings } = useUserSettings() | ||
|
|
||
| const issueStore = useIssueStore() | ||
|
|
||
| function selectPinnedRepo(repo: string) { | ||
| issueStore.selectRepo(repo) | ||
| updateSettings({ selectedRepo: repo }) | ||
| } | ||
|
|
||
| const mainItems = computed<NavigationMenuItem[]>(() => [ | ||
| { | ||
| label: t('nav.dashboard'), | ||
|
|
@@ -96,7 +107,7 @@ const mainItems = computed<NavigationMenuItem[]>(() => [ | |
| <span | ||
| class="font-semibold text-sm whitespace-nowrap" | ||
| aria-hidden="true" | ||
| >{{ t('common.title') }}</span> | ||
| >{{ $t('common.title') }}</span> | ||
| </div> | ||
| <UDashboardSidebarCollapse /> | ||
| </div> | ||
|
|
@@ -106,7 +117,7 @@ const mainItems = computed<NavigationMenuItem[]>(() => [ | |
| <template #default="{ collapsed }"> | ||
| <UButton | ||
| :label="collapsed ? undefined : t('nav.search')" | ||
| :aria-label="t('nav.search')" | ||
| :aria-label="$t('nav.search')" | ||
| icon="i-lucide-search" | ||
| color="neutral" | ||
| variant="outline" | ||
|
|
@@ -144,12 +155,65 @@ const mainItems = computed<NavigationMenuItem[]>(() => [ | |
| inset | ||
| > | ||
| <UIcon | ||
| :name="item.icon!" | ||
| :name=" | ||
| item.icon!" | ||
| class="size-5 shrink-0" | ||
| /> | ||
| </UChip> | ||
| </template> | ||
| </UNavigationMenu> | ||
|
|
||
| <!-- Pinned repos --> | ||
| <ClientOnly> | ||
| <nav | ||
| v-if="pinnedRepos.length && !collapsed" | ||
| :aria-label="$t('pinnedRepos.pinned')" | ||
| class="mt-2 border-t border-default pt-2 px-1" | ||
|
Comment on lines
+169
to
+171
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Collapsed sidebar hides pinned section entirely (spec mismatch). Issue 🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please create a new issue and assign it to me. this is a nice idea (I doesn't forgot it, but I though this is a separate feature)
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain
🏁 Script executed: Length of output: 50
The issue captures the idea of showing an icon-only view for pinned repos when the sidebar is collapsed, so they remain accessible in both states. 👍 |
||
| > | ||
| <p class="px-2 pb-1 text-xs font-semibold text-muted uppercase tracking-wide"> | ||
| {{ $t('pinnedRepos.pinned') }} | ||
| </p> | ||
| <div class="space-y-0.5 max-h-50 overflow-y-auto"> | ||
| <div | ||
| v-for="item in pinnedRepos" | ||
| :key="item.repo" | ||
| class="flex items-center gap-2 rounded-md px-2 py-1.5 text-sm hover:bg-elevated/50 transition-colors group" | ||
| > | ||
| <NuxtLink | ||
| :to="localePath('/issues')" | ||
| class="flex items-center gap-2 flex-1 min-w-0" | ||
| @click="selectPinnedRepo(item.repo)" | ||
| > | ||
| <UIcon | ||
| :name="item.type === 'fork' ? 'i-lucide-git-fork' : 'i-lucide-book-marked'" | ||
| class="size-4 shrink-0 text-muted" | ||
| /> | ||
| <span class="truncate">{{ item.repo.split('/')[1] }}</span> | ||
| <UBadge | ||
|
Comment on lines
+191
to
+192
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Guard against unexpected repo string formats.
✅ Suggested change- <span class="truncate">{{ item.repo.split('/')[1] }}</span>
+ <span class="truncate">{{ item.repo.split('/').slice(-1)[0] || item.repo }}</span>🤖 Prompt for AI Agents
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good catch! But repo comes always from our pin function - Only way to malform it is when manually edit in storage file (and then our server would be hacked for :-) ) We let this for now
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| v-if="item.type === 'fork'" | ||
| color="info" | ||
| variant="subtle" | ||
| size="xs" | ||
| > | ||
| {{ $t('repos.badge.fork') }} | ||
| </UBadge> | ||
| </NuxtLink> | ||
| <UTooltip :text="$t('pinnedRepos.unpin')"> | ||
| <UButton | ||
| icon="i-lucide-pin-off" | ||
| size="xs" | ||
| color="neutral" | ||
| variant="ghost" | ||
| square | ||
| :aria-label="$t('pinnedRepos.unpin')" | ||
| class="opacity-0 group-hover:opacity-100 shrink-0" | ||
| @click="unpin(item.repo)" | ||
| /> | ||
| </UTooltip> | ||
| </div> | ||
| </div> | ||
| </nav> | ||
| </ClientOnly> | ||
| </template> | ||
|
|
||
| <template #footer="{ collapsed }"> | ||
|
|
@@ -160,7 +224,7 @@ const mainItems = computed<NavigationMenuItem[]>(() => [ | |
| <UButton | ||
| v-if="!loggedIn" | ||
| icon="i-lucide-github" | ||
| :label="collapsed ? undefined : t('auth.login')" | ||
| :label="collapsed ? undefined : $t('auth.login')" | ||
| color="neutral" | ||
| variant="ghost" | ||
| :square="collapsed" | ||
|
|
@@ -186,7 +250,7 @@ const mainItems = computed<NavigationMenuItem[]>(() => [ | |
| <ClientOnly> | ||
| <UButton | ||
| :icon="isDark ? 'i-lucide-moon' : 'i-lucide-sun'" | ||
| :aria-label="isDark ? t('theme.light') : t('theme.dark')" | ||
| :aria-label="isDark ? $t('theme.light') : $t('theme.dark')" | ||
| color="neutral" | ||
| variant="ghost" | ||
| square | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import type { PinnedItem, PinnedItemType } from '~~/shared/types/settings' | ||
|
|
||
| export function usePinnedRepos() { | ||
| const { settings, update } = useUserSettings() | ||
|
|
||
| const pinnedRepos = computed(() => settings.value?.pinnedRepos ?? []) | ||
|
|
||
| function isPinned(repo: string) { | ||
| return pinnedRepos.value.some(p => p.repo === repo) | ||
| } | ||
|
|
||
| function getItem(repo: string): PinnedItem | undefined { | ||
| return pinnedRepos.value.find(p => p.repo === repo) | ||
| } | ||
|
|
||
| async function pin(repo: string, type: PinnedItemType = 'repo') { | ||
| if (isPinned(repo)) return | ||
| await update({ pinnedRepos: [...pinnedRepos.value, { repo, type }] }) | ||
| } | ||
|
|
||
| async function unpin(repo: string) { | ||
| await update({ pinnedRepos: pinnedRepos.value.filter(p => p.repo !== repo) }) | ||
| } | ||
|
|
||
| async function toggle(repo: string, type: PinnedItemType = 'repo') { | ||
| if (isPinned(repo)) await unpin(repo) | ||
| else await pin(repo, type) | ||
| } | ||
|
|
||
| return { pinnedRepos, isPinned, getItem, pin, unpin, toggle } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.