Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
371 changes: 224 additions & 147 deletions app/components/AppFooter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,167 +9,244 @@ const { commandPaletteShortcutLabel } = usePlatformModifierKey()
const modalRef = useTemplateRef('modalRef')
const showModal = () => modalRef.value?.showModal?.()
const closeModal = () => modalRef.value?.close?.()

type FooterLink =
| { name: string; href: string; kbd?: never; type?: never }
| { name: string; kbd: string; href?: never; type?: never }
| { name: string; type: 'button'; href?: never; kbd?: never }

const socialLinks = computed(() => [
{
id: 'github',
href: 'https://repo.npmx.dev',
icon: 'i-simple-icons:github',
},
{
id: 'discord',
href: discord.value.url,
icon: 'i-simple-icons:discord',
},
{
id: 'bluesky',
href: 'https://social.npmx.dev',
icon: 'i-simple-icons:bluesky',
},
])

const footerSections: Array<{ label: string; links: FooterLink[] }> = [
{
label: 'resources',
links: [
{
name: 'footer.blog',
href: 'blog',
},
{
name: 'footer.about',
href: 'about',
},
{
name: 'a11y.footer_title',
href: 'accessibility',
},
{
name: 'privacy_policy.title',
href: 'privacy',
},
],
},
{
label: 'features',
links: [
{
name: 'shortcuts.compare',
href: 'compare',
},
{
name: 'shortcuts.settings',
href: 'settings',
},
{
name: 'footer.keyboard_shortcuts',
type: 'button',
},
],
},
{
label: 'other',
links: [
{
name: 'pds.title',
href: 'pds',
},
{
name: 'footer.docs',
href: NPMX_DOCS_SITE,
Comment thread
alexdln marked this conversation as resolved.
},
],
},
]
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</script>

<template>
<footer class="border-t border-border mt-auto">
<div class="container py-3 sm:py-8 flex flex-col gap-2 sm:gap-4 text-fg-subtle text-sm">
<div class="flex flex-col lg:flex-row lg:items-baseline justify-between gap-2 sm:gap-4">
<div>
<p class="font-mono text-balance m-0 hidden sm:block mb-3">
{{ $t('tagline') }}
</p>
<BuildEnvironment v-if="!isHome" footer />
</div>
<!-- Desktop: Show all links. Mobile: Links are in MobileMenu -->
<div class="hidden sm:flex flex-col lg:items-end gap-3 min-h-11 text-xs">
<div class="flex items-center gap-5">
<LinkBase :to="{ name: 'about' }">
{{ $t('footer.about') }}
</LinkBase>
<LinkBase :to="{ name: 'blog' }">
{{ $t('footer.blog') }}
</LinkBase>
<LinkBase :to="{ name: 'privacy' }">
{{ $t('privacy_policy.title') }}
</LinkBase>
<LinkBase :to="{ name: 'accessibility' }">
{{ $t('a11y.footer_title') }}
</LinkBase>
<LinkBase :to="{ name: 'translation-status' }">
{{ $t('translation_status.title') }}
</LinkBase>
<LinkBase :to="{ name: 'brand' }">
{{ $t('footer.brand') }}
</LinkBase>
<button
type="button"
class="cursor-pointer group inline-flex gap-x-1 items-center justify-center underline-offset-[0.2rem] underline decoration-1 decoration-fg/30 font-mono text-fg hover:(decoration-accent text-accent) focus-visible:(decoration-accent text-accent) transition-colors duration-200"
@click.prevent="showModal"
aria-haspopup="dialog"
>
{{ $t('footer.keyboard_shortcuts') }}
</button>

<Modal
id="keyboard-shortcuts-modal"
ref="modalRef"
:modalTitle="$t('footer.keyboard_shortcuts')"
class="w-auto max-w-lg"
<footer class="border-t border-border md:mt-auto md:pt-8 duration-200 transition-all">
<div class="container flex flex-col gap-3">
<!-- Desktop: Show all links. Mobile: Links are in MobileMenu -->
<div
class="hidden md:flex flex-col lg:flex-row gap-6 lg:gap-0 lg:justify-between py-3 duration-200 transition-all"
Comment thread
alexdln marked this conversation as resolved.
Outdated
>
<div class="flex flex-col gap-6">
<div class="flex flex-col items-start gap-3">
<AppLogo class="h-7 w-auto" />
<BuildEnvironment v-if="!isHome" footer />
</div>
<div class="space-x-3">
<NuxtLink
v-for="link in socialLinks"
:key="link.id"
:to="link.href"
:aria-label="link.id"
target="_blank"
class="text-fg-muted hover:text-accent transition-all duration-200"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
>
<p class="mb-4 text-sm leading-relaxed text-fg-muted">
{{
$t('shortcuts.command_palette_description', { ctrlKey: $t('shortcuts.ctrl_key') })
}}
</p>
<p class="mb-2 font-mono text-fg-subtle">
{{ $t('shortcuts.section.global') }}
</p>
<ul class="mb-6 flex flex-col gap-2">
<li class="flex gap-2 items-center">
<kbd class="kbd">{{ commandPaletteShortcutLabel }}</kbd>
<span>{{ $t('shortcuts.command_palette') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">/</kbd>
<span>{{ $t('shortcuts.focus_search') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">?</kbd>
<span>{{ $t('shortcuts.show_kbd_hints') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">,</kbd>
<span>{{ $t('shortcuts.settings') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">c</kbd>
<span>{{ $t('shortcuts.compare') }}</span>
</li>
</ul>
<p class="mb-2 font-mono text-fg-subtle">
{{ $t('shortcuts.section.search') }}
</p>
<ul class="mb-6 flex flex-col gap-2">
<li class="flex gap-2 items-center">
<kbd class="kbd">↑</kbd>/<kbd class="kbd">↓</kbd>
<span>{{ $t('shortcuts.navigate_results') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">Enter</kbd>
<span>{{ $t('shortcuts.go_to_result') }}</span>
</li>
</ul>
<p class="mb-2 font-mono text-fg-subtle">
{{ $t('shortcuts.section.package') }}
</p>
<ul class="mb-8 flex flex-col gap-2">
<li class="flex gap-2 items-center">
<kbd class="kbd">m</kbd>
<span>{{ $t('shortcuts.open_main') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">d</kbd>
<span>{{ $t('shortcuts.open_docs') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">.</kbd>
<span>{{ $t('shortcuts.open_code_view') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">f</kbd>
<span>{{ $t('shortcuts.open_diff') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">t</kbd>
<span>{{ $t('shortcuts.open_timeline') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">c</kbd>
<span>{{ $t('shortcuts.compare_from_package') }}</span>
</li>
</ul>
<p class="text-fg-muted leading-relaxed">
<i18n-t keypath="shortcuts.disable_shortcuts" tag="span" scope="global">
<template #settings>
<NuxtLink
:to="{ name: 'settings' }"
class="hover:text-fg underline decoration-fg-subtle/50 hover:decoration-fg"
@click="closeModal"
>
{{ $t('settings.title') }}
</NuxtLink>
</template>
</i18n-t>
</p>
</Modal>
<span :class="[link.icon, 'size-7']" />
</NuxtLink>
Comment thread
coderabbitai[bot] marked this conversation as resolved.
</div>
<div class="flex items-center gap-5">
<LinkBase :to="NPMX_DOCS_SITE">
{{ $t('footer.docs') }}
</LinkBase>
<LinkBase to="https://repo.npmx.dev">
{{ $t('footer.source') }}
</LinkBase>
<LinkBase to="https://social.npmx.dev">
{{ $t('footer.social') }}
</LinkBase>
<LinkBase :to="discord.url">
{{ discord.label }}
</LinkBase>
</div>

<div class="font-mono flex gap-6">
<div
v-for="section in footerSections"
:key="section.label"
class="flex flex-col gap-3 min-w-40 max-w-50"
>
<p class="uppercase text-fg-muted">
{{ section.label }}
</p>
<template v-for="link in section.links" :key="link.name">
<button
v-if="link.type === 'button'"
class="cursor-pointer text-start font-mono text-fg-subtle text-sm hover:text-accent transition-colors duration-200"
@click="showModal()"
Comment thread
alexdln marked this conversation as resolved.
Outdated
>
{{ $t(link.name) }}
</button>

<LinkBase v-else :key="link.name" :to="link?.href" variant="footer">
{{ $t(link.name) }}
</LinkBase>
</template>
</div>
</div>
</div>
<small class="text-xs text-fg-muted text-center sm:text-start m-0">
<span class="sm:hidden">{{ $t('non_affiliation_disclaimer') }}</span>
<span class="hidden sm:inline">{{ $t('trademark_disclaimer') }}</span>

<small
class="border-border py-7.75 md:border-t md:py-4 duration-200 transition-all text-xs text-fg-muted text-center md:text-start m-0"
>
<span class="lg:hidden">{{ $t('non_affiliation_disclaimer') }}</span>
<span class="hidden lg:block">{{ $t('trademark_disclaimer') }}</span>
</small>
</div>

<Modal
id="keyboard-shortcuts-modal"
ref="modalRef"
:modalTitle="$t('footer.keyboard_shortcuts')"
class="w-auto max-w-lg"
>
<p class="mb-4 text-sm leading-relaxed text-fg-muted">
{{
$t('shortcuts.command_palette_description', {
ctrlKey: $t('shortcuts.ctrl_key'),
})
}}
</p>
<p class="mb-2 font-mono text-fg-subtle">
{{ $t('shortcuts.section.global') }}
</p>
<ul class="mb-6 flex flex-col gap-2">
<li class="flex gap-2 items-center">
<kbd class="kbd">{{ commandPaletteShortcutLabel }}</kbd>
<span>{{ $t('shortcuts.command_palette') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">/</kbd>
<span>{{ $t('shortcuts.focus_search') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">?</kbd>
<span>{{ $t('shortcuts.show_kbd_hints') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">,</kbd>
<span>{{ $t('shortcuts.settings') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">c</kbd>
<span>{{ $t('shortcuts.compare') }}</span>
</li>
</ul>
<p class="mb-2 font-mono text-fg-subtle">
{{ $t('shortcuts.section.search') }}
</p>
<ul class="mb-6 flex flex-col gap-2">
<li class="flex gap-2 items-center">
<kbd class="kbd">↑</kbd>/<kbd class="kbd">↓</kbd>
<span>{{ $t('shortcuts.navigate_results') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">Enter</kbd>
<span>{{ $t('shortcuts.go_to_result') }}</span>
</li>
</ul>
<p class="mb-2 font-mono text-fg-subtle">
{{ $t('shortcuts.section.package') }}
</p>
<ul class="mb-8 flex flex-col gap-2">
<li class="flex gap-2 items-center">
<kbd class="kbd">m</kbd>
<span>{{ $t('shortcuts.open_main') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">d</kbd>
<span>{{ $t('shortcuts.open_docs') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">.</kbd>
<span>{{ $t('shortcuts.open_code_view') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">f</kbd>
<span>{{ $t('shortcuts.open_diff') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">t</kbd>
<span>{{ $t('shortcuts.open_timeline') }}</span>
</li>
<li class="flex gap-2 items-center">
<kbd class="kbd">c</kbd>
<span>{{ $t('shortcuts.compare_from_package') }}</span>
</li>
</ul>
<p class="text-fg-muted leading-relaxed">
<i18n-t keypath="shortcuts.disable_shortcuts" tag="span" scope="global">
<template #settings>
<NuxtLink
:to="{ name: 'settings' }"
class="hover:text-fg underline decoration-fg-subtle/50 hover:decoration-fg"
@click="closeModal"
>
{{ $t('settings.title') }}
</NuxtLink>
</template>
</i18n-t>
</p>
</Modal>
</footer>
</template>

<style scoped>
.kbd {
@apply items-center justify-center text-sm text-fg bg-bg-muted border border-border rounded px-2;
@apply items-center justify-center text-xs text-fg bg-bg-muted border border-border rounded px-2;
}
</style>
Loading
Loading