Skip to content
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
12 changes: 6 additions & 6 deletions app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const mobileNavigationOpen = ref(false)
const mobileNavigation = useTemplateRef('mobileNavigation')
const mobileNavigationToggle = useTemplateRef('mobileNavigationToggle')
const route = useRoute()
const isAdminLayout = computed(() => route.meta.layout === 'admin')
const hasAppLayout = computed(() => !!route.meta.layout)

const { enabled: kbdEnabled } = useKeyboardShortcuts()
const skillSearch = useSkillSearch()
Expand Down Expand Up @@ -102,7 +102,7 @@ watch(() => route.fullPath, () => {
<!-- Route change announcements for screen readers -->
<NuxtRouteAnnouncer />

<NuxtLayout v-if="isAdminLayout">
<NuxtLayout v-if="hasAppLayout">
<NuxtPage />
</NuxtLayout>

Expand Down Expand Up @@ -294,10 +294,10 @@ watch(() => route.fullPath, () => {
/>
</template>
</UFooter>

<ClientOnly>
<KeyboardShortcutsModal v-model:open="shortcutsModalOpen" />
</ClientOnly>
</template>

<ClientOnly>
<KeyboardShortcutsModal v-model:open="shortcutsModalOpen" />
</ClientOnly>
</UApp>
</template>
4 changes: 2 additions & 2 deletions app/pages/cli/authorize.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
definePageMeta({ middleware: ['session'] })
definePageMeta({ layout: 'auth', middleware: ['session'] })

const route = useRoute()
const { loggedIn } = useUserSession()
Expand Down Expand Up @@ -98,7 +98,7 @@ useSeoMeta({
</script>

<template>
<section class="mx-auto max-w-lg px-4 sm:px-6 pt-16 pb-12 md:pt-24">
<section class="mx-auto w-full max-w-lg">
<div class="rounded-lg border border-default p-6 sm:p-8">
<div class="flex items-start gap-3">
<UIcon name="i-lucide-terminal" class="mt-1 size-6 text-primary" aria-hidden="true" />
Expand Down
4 changes: 2 additions & 2 deletions app/pages/collections/new.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
definePageMeta({ middleware: ['session'] })
definePageMeta({ layout: 'account', middleware: ['session'] })

const route = useRoute()
const { isAuthenticated, user, loginUrl } = useAuth()
Expand Down Expand Up @@ -61,7 +61,7 @@ const githubLoginHref = computed(() => loginUrl({ returnTo: route.fullPath }))

<template>
<section
class="mx-auto max-w-2xl px-4 sm:px-6 pt-12 pb-16"
class="mx-auto max-w-2xl py-6 sm:py-8"
aria-labelledby="new-collection-heading"
>
<h1
Expand Down
4 changes: 2 additions & 2 deletions app/pages/me/cli-tokens/new.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { z } from 'zod'
import { useTokenCreation } from '#layers/identity/app/composables/useTokenCreation'
import SetupSnippet from '#layers/marketing/app/components/_SetupSnippet.vue'

definePageMeta({ middleware: ['auth'] })
definePageMeta({ layout: 'account', middleware: ['auth'] })

const schema = z.object({
label: z.string().trim().min(1, 'Enter a token label.').max(80, 'Use 80 characters or fewer.'),
Expand All @@ -26,7 +26,7 @@ useSeoMeta({ title: 'New token', robots: 'noindex' })
</script>

<template>
<section class="mx-auto max-w-xl px-4 pt-12 pb-16 sm:px-6 md:pt-16">
<section class="mx-auto max-w-xl py-6 sm:py-8">
<UButton to="/me/devices" label="Devices and tokens" icon="i-lucide-arrow-left" color="neutral" variant="link" class="mb-4 min-h-11 px-0" />
<header class="border-b border-default pb-6">
<h1 class="text-2xl font-semibold tracking-tight sm:text-3xl">
Expand Down
4 changes: 2 additions & 2 deletions app/pages/me/devices.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup lang="ts">
definePageMeta({ middleware: ['auth'] })
definePageMeta({ layout: 'account', middleware: ['auth'] })

interface Device {
id: number
Expand Down Expand Up @@ -70,7 +70,7 @@ useSeoMeta({ title: 'Devices and tokens', robots: 'noindex' })
</script>

<template>
<section class="mx-auto max-w-5xl px-4 pt-10 pb-16 sm:px-6 md:pt-14">
<section class="mx-auto max-w-5xl py-6 sm:py-8">
<UButton to="/me" label="Your skills" icon="i-lucide-arrow-left" color="neutral" variant="link" class="mb-4 min-h-11 px-0" />
<header class="flex flex-col gap-5 border-b border-default pb-7 sm:flex-row sm:items-end sm:justify-between">
<div>
Expand Down
109 changes: 109 additions & 0 deletions layers/identity/app/layouts/account.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const route = useRoute()
const { state, logout, isLoading } = useAuth()
const navigationOpen = ref(false)
const navigationToggle = useTemplateRef<{ $el: HTMLButtonElement }>('navigationToggle')

function restoreNavigationFocus(event: Event) {
event.preventDefault()
navigationToggle.value?.$el.focus()
}

const navigation = computed<NavigationMenuItem[]>(() => [
{ label: 'Your skills', icon: 'i-lucide-heart', to: '/me', active: route.path === '/me' && !['email', 'repositories', 'account'].includes(String(route.query.view)) },
{ label: 'Repository coverage', icon: 'i-lucide-git-fork', to: '/me?view=repositories', active: route.path === '/me' && route.query.view === 'repositories' },
{ label: 'Email updates', icon: 'i-lucide-mail', to: '/me?view=email', active: route.path === '/me' && route.query.view === 'email' },
{ label: 'Set up your agent', icon: 'i-lucide-plug', to: '/developers', active: route.path === '/developers' },
{ label: 'Devices and tokens', icon: 'i-lucide-terminal', to: '/me/devices', active: route.path.startsWith('/me/devices') || route.path.startsWith('/me/cli-tokens') },
{ label: 'Account', icon: 'i-lucide-settings', to: '/me?view=account', active: route.path === '/me' && route.query.view === 'account' },
])

const collectionNavigation = computed<NavigationMenuItem[]>(() => [
{ label: 'Publish a collection', icon: 'i-lucide-folder-plus', to: '/collections/new', active: route.path === '/collections/new' },
...(state.value._tag === 'signed-in'
? [{ label: 'View profile', icon: 'i-lucide-user-round', to: `/@${state.value.user.login}` }]
: []),
])
</script>

<template>
<UDashboardGroup unit="rem" :persistent="false" storage-key="skilld-account">
<UDashboardSidebar
v-model:open="navigationOpen"
:default-size="16"
:min-size="16"
:max-size="16"
:toggle="false"
class="bg-muted/40"
:menu="{
title: 'Account',
description: 'Your skills and account tools',
content: { onCloseAutoFocus: restoreNavigationFocus },
}"
:ui="{ header: 'px-4', body: 'gap-6 px-3 py-5', footer: 'border-t border-default p-3', content: 'w-80 max-w-[calc(100vw-3rem)] border-r border-default shadow-none' }"
>
<template #header>
<NuxtLink to="/" aria-label="skilld, home" class="flex min-h-11 items-center rounded-lg">
<AppLogo />
</NuxtLink>
<UButton v-if="navigationOpen" icon="i-lucide-x" aria-label="Close menu" color="neutral" variant="ghost" class="ml-auto min-h-11 min-w-11 lg:hidden" @click="navigationOpen = false" />
</template>

<div class="space-y-6">
<UNavigationMenu
aria-label="Account"
:items="navigation"
orientation="vertical"
:ui="{ link: 'min-h-11 font-mono text-sm', linkLabel: 'whitespace-normal' }"
/>
<USeparator />
<UNavigationMenu
aria-label="Collections"
:items="collectionNavigation"
orientation="vertical"
:ui="{ link: 'min-h-11 font-mono text-sm', linkLabel: 'whitespace-normal' }"
/>
</div>

<UButton to="/skills" label="Find skills" icon="i-lucide-arrow-up-right" color="neutral" variant="ghost" class="mt-auto min-h-11 justify-start" />

<template #footer>
<div :aria-busy="state._tag === 'pending'">
<USkeleton v-if="state._tag === 'pending'" class="h-11 w-full" />
<template v-else-if="state._tag === 'signed-in'">
<NuxtLink :to="`/@${state.user.login}`" class="flex min-h-11 items-center gap-2 rounded-lg px-2 font-mono text-sm hover:bg-elevated">
<UIcon name="i-lucide-user-round" class="size-5 shrink-0 text-muted" aria-hidden="true" />
<span class="truncate">@{{ state.user.login }}</span>
</NuxtLink>
<UButton label="Sign out" icon="i-lucide-log-out" color="neutral" variant="ghost" class="min-h-11 w-full justify-start" :loading="isLoading" @click="logout()" />
</template>
<UButton v-else :to="{ path: '/login', query: { return_to: route.fullPath } }" label="Sign in" icon="i-lucide-github" color="neutral" variant="outline" class="min-h-11 w-full justify-center" />
</div>
</template>
</UDashboardSidebar>

<UDashboardPanel :ui="{ body: 'p-0' }">
<template #header>
<UDashboardNavbar :toggle="false">
<template #left>
<UButton ref="navigationToggle" icon="i-lucide-menu" aria-label="Open menu" aria-haspopup="dialog" color="neutral" variant="ghost" class="min-h-11 min-w-11 lg:hidden" :aria-expanded="navigationOpen" @click="navigationOpen = true" />
<NuxtLink to="/me" class="flex min-h-11 items-center font-mono text-sm text-muted hover:text-default">
skilld
</NuxtLink>
</template>
<template #right>
<SkillSearchTrigger />
<UColorModeButton color="neutral" variant="ghost" class="min-h-11 min-w-11" />
</template>
</UDashboardNavbar>
</template>
<template #body>
<main id="main-content" tabindex="-1" class="min-w-0 px-4 pb-12 sm:px-6 lg:px-8">
<slot />
</main>
</template>
</UDashboardPanel>
</UDashboardGroup>
</template>
19 changes: 19 additions & 0 deletions layers/identity/app/layouts/auth.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<template>
<div class="flex min-h-dvh flex-col bg-muted/40">
<header class="flex items-center justify-between gap-4 px-4 py-3 sm:px-6">
<NuxtLink to="/" class="flex min-h-11 items-center gap-2 rounded-lg font-mono text-sm text-muted hover:text-default">
<UIcon name="i-lucide-arrow-left" class="size-4" aria-hidden="true" />
skilld.dev
</NuxtLink>
<UColorModeButton color="neutral" variant="ghost" class="min-h-11 min-w-11" />
</header>
<main id="main-content" tabindex="-1" class="flex flex-1 flex-col items-center justify-center px-4 pt-6 pb-16 sm:px-6">
<NuxtLink to="/" aria-label="skilld, home" class="mb-8 flex min-h-11 items-center rounded-lg">
<AppLogo />
</NuxtLink>
<div class="w-full max-w-2xl">
<slot />
</div>
</main>
</div>
</template>
8 changes: 4 additions & 4 deletions layers/identity/app/pages/login.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { parseReturnTo } from '#shared/return-to'

definePageMeta({ middleware: ['session'] })
definePageMeta({ layout: 'auth', middleware: ['session'] })

const route = useRoute()
const { loginUrl } = useAuth()
Expand All @@ -26,12 +26,12 @@ useSeoMeta({
</script>

<template>
<section class="mx-auto max-w-md px-4 sm:px-6 pt-10 pb-12 md:pt-16">
<div class="rounded-lg border border-default p-4 sm:p-5">
<section class="mx-auto w-full max-w-md">
<div class="rounded-lg border border-default bg-default p-6 sm:p-8">
<h1 class="text-2xl font-semibold tracking-tight">
Sign in to skilld
</h1>
<p class="mt-2 text-sm text-muted leading-relaxed">
<p class="mt-3 text-base text-muted leading-relaxed">
Like skills, build collections, and get the weekly: changes to your skills, plus what devs are talking about. We ask for your public profile and email address.
</p>
<div class="mt-5">
Expand Down
Loading