[READ-ONLY] a fast, modern browser for the npm registry
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(ui): app footer layout and build environment on narrow screens (#1032)

Co-authored-by: Daniel Roe <daniel@roe.dev>

authored by

Joaquín Sánchez
Daniel Roe
and committed by
GitHub
ac7e6385 77fd97e3

+134 -20
+1 -1
app/components/AppFooter.vue
··· 14 14 > 15 15 <div> 16 16 <p class="font-mono text-balance m-0 hidden sm:block">{{ $t('tagline') }}</p> 17 - <BuildEnvironment v-if="!isHome" footer /> 18 17 </div> 19 18 <!-- Desktop: Show all links. Mobile: Links are in MobileMenu --> 20 19 <div class="hidden sm:flex items-center gap-6 min-h-11 text-xs"> ··· 105 104 </Modal> 106 105 </div> 107 106 </div> 107 + <BuildEnvironment v-if="!isHome" footer /> 108 108 <p class="text-xs text-fg-muted text-center sm:text-start m-0"> 109 109 <span class="sm:hidden">{{ $t('non_affiliation_disclaimer') }}</span> 110 110 <span class="hidden sm:inline">{{ $t('trademark_disclaimer') }}</span>
+7 -3
app/components/BuildEnvironment.vue
··· 1 1 <script setup lang="ts"> 2 - defineProps<{ 2 + import type { BuildInfo } from '#shared/types' 3 + 4 + const { footer = false, buildInfo: buildInfoProp } = defineProps<{ 3 5 footer?: boolean 6 + buildInfo?: BuildInfo 4 7 }>() 5 8 6 9 const { locale } = useI18n() 7 - const buildInfo = useAppConfig().buildInfo 10 + const appConfig = useAppConfig() 11 + const buildInfo = computed(() => buildInfoProp || appConfig.buildInfo) 8 12 </script> 9 13 10 14 <template> 11 15 <div 12 16 class="font-mono text-xs text-fg-muted flex items-center gap-2 motion-safe:animate-fade-in motion-safe:animate-fill-both" 13 - :class="footer ? 'mt-4 justify-start' : 'mb-8 justify-center'" 17 + :class="footer ? 'my-1 justify-center sm:justify-start' : 'mb-8 justify-center'" 14 18 style="animation-delay: 0.05s" 15 19 > 16 20 <i18n-t keypath="built_at" scope="global">
+30 -15
modules/build-env.ts
··· 1 - import type { BuildInfo } from '../shared/types' 1 + import type { BuildInfo, EnvType } from '../shared/types' 2 2 import { createResolver, defineNuxtModule } from 'nuxt/kit' 3 3 import { isCI } from 'std-env' 4 4 import { getEnv, getFileLastUpdated, version } from '../config/env' ··· 10 10 name: 'npmx:build-env', 11 11 }, 12 12 async setup(_options, nuxt) { 13 - const [{ env, commit, shortCommit, branch }, privacyPolicyDate] = await Promise.all([ 14 - getEnv(nuxt.options.dev), 15 - getFileLastUpdated('app/pages/privacy.vue'), 16 - ]) 17 - 13 + let env: EnvType = 'dev' 18 14 nuxt.options.appConfig = nuxt.options.appConfig || {} 19 15 nuxt.options.appConfig.env = env 20 - nuxt.options.appConfig.buildInfo = { 21 - version, 22 - time: +Date.now(), 23 - commit, 24 - shortCommit, 25 - branch, 26 - env, 27 - privacyPolicyDate, 28 - } satisfies BuildInfo 16 + if (process.env.TEST) { 17 + const time = new Date() 18 + nuxt.options.appConfig.buildInfo = { 19 + env, 20 + version: '0.0.0', 21 + commit: '704987bba88909f3782d792c224bde989569acb9', 22 + shortCommit: '704987b', 23 + branch: 'xxx', 24 + time: time.getTime(), 25 + privacyPolicyDate: time.toISOString(), 26 + } satisfies BuildInfo 27 + } else { 28 + const [{ env: useEnv, commit, shortCommit, branch }, privacyPolicyDate] = await Promise.all([ 29 + getEnv(nuxt.options.dev), 30 + getFileLastUpdated('app/pages/privacy.vue'), 31 + ]) 32 + env = useEnv 33 + nuxt.options.appConfig.env = useEnv 34 + nuxt.options.appConfig.buildInfo = { 35 + version, 36 + time: +Date.now(), 37 + commit, 38 + shortCommit, 39 + branch, 40 + env, 41 + privacyPolicyDate, 42 + } satisfies BuildInfo 43 + } 29 44 30 45 nuxt.options.nitro.publicAssets = nuxt.options.nitro.publicAssets || [] 31 46 if (env === 'dev') nuxt.options.nitro.publicAssets.unshift({ dir: resolve('../public-dev') })
+3 -1
shared/types/env.ts
··· 1 + export type EnvType = 'dev' | 'preview' | 'canary' | 'release' 2 + 1 3 export interface BuildInfo { 2 4 version: string 3 5 commit: string 4 6 shortCommit: string 5 7 time: number 6 8 branch: string 7 - env: 'preview' | 'canary' | 'dev' | 'release' 9 + env: EnvType 8 10 privacyPolicyDate: string 9 11 }
+35
test/nuxt/components/AppFooter.spec.ts
··· 1 + import { describe, expect, it } from 'vitest' 2 + import { mountSuspended } from '@nuxt/test-utils/runtime' 3 + import AppFooter from '~/components/AppFooter.vue' 4 + 5 + /* check nuxt module at modules/build-env.ts */ 6 + describe('AppFooter', () => { 7 + it('BuildEnvironment is properly displayed at settings', async () => { 8 + const buildInfo = useAppConfig().buildInfo 9 + const component = await mountSuspended(AppFooter, { 10 + route: '/settings', 11 + }) 12 + 13 + const envSpan = component.find('span.tracking-wider') 14 + expect(envSpan.exists()).toBe(true) 15 + expect(envSpan.text()).toBe(buildInfo.env) 16 + const commitLink = component.find(`a[href$="/commit/${buildInfo.commit}"]`) 17 + expect(commitLink.exists()).toBe(true) 18 + const tagLink = component.find(`a[href$="/tag/v${buildInfo.version}"]`) 19 + expect(tagLink.exists()).toBe(false) 20 + }) 21 + 22 + it('BuildEnvironment is hidden at home', async () => { 23 + const buildInfo = useAppConfig().buildInfo 24 + const component = await mountSuspended(AppFooter, { 25 + route: '/', 26 + }) 27 + 28 + const envSpan = component.find('span.tracking-wider') 29 + expect(envSpan.exists()).toBe(false) 30 + const commitLink = component.find(`a[href$="/commit/${buildInfo.commit}"]`) 31 + expect(commitLink.exists()).toBe(false) 32 + const tagLink = component.find(`a[href$="/tag/v${buildInfo.version}"]`) 33 + expect(tagLink.exists()).toBe(false) 34 + }) 35 + })
+58
test/nuxt/components/BuildEnvironment.spec.ts
··· 1 + import type { BuildInfo } from '#shared/types' 2 + import { describe, expect, it } from 'vitest' 3 + import { mountSuspended } from '@nuxt/test-utils/runtime' 4 + import BuildEnvironment from '~/components/BuildEnvironment.vue' 5 + 6 + describe('BuildEnvironment', () => { 7 + it('renders dev environment correctly', async () => { 8 + const buildInfo: BuildInfo = { 9 + env: 'dev', 10 + version: '1.2.3', 11 + time: 1234567890, 12 + commit: 'abcdef', 13 + shortCommit: 'abc', 14 + branch: 'main', 15 + privacyPolicyDate: new Date().toISOString(), 16 + } 17 + const component = await mountSuspended(BuildEnvironment, { 18 + props: { 19 + buildInfo, 20 + }, 21 + }) 22 + 23 + // In dev mode, it shows env name, not version link 24 + const envSpan = component.find('span.tracking-wider') 25 + expect(envSpan.exists()).toBe(true) 26 + expect(envSpan.text()).toBe(buildInfo.env) 27 + const commitLink = component.find(`a[href$="/commit/${buildInfo.commit}"]`) 28 + expect(commitLink.exists()).toBe(true) 29 + const tagLink = component.find(`a[href$="/tag/v${buildInfo.version}"]`) 30 + expect(tagLink.exists()).toBe(false) 31 + }) 32 + 33 + it('renders release environment correctly', async () => { 34 + const buildInfo: BuildInfo = { 35 + env: 'release', 36 + version: '1.2.3', 37 + time: 1234567890, 38 + commit: 'abcdef', 39 + shortCommit: 'abc', 40 + branch: 'release', 41 + privacyPolicyDate: new Date().toISOString(), 42 + } 43 + 44 + const component = await mountSuspended(BuildEnvironment, { 45 + props: { 46 + buildInfo, 47 + }, 48 + }) 49 + 50 + // In release mode, it shows tag version link, not env name 51 + const envSpan = component.find('span.tracking-wider') 52 + expect(envSpan.exists()).toBe(false) 53 + const commitLink = component.find(`a[href$="/commit/${buildInfo.commit}"]`) 54 + expect(commitLink.exists()).toBe(false) 55 + const tagLink = component.find(`a[href$="/tag/v${buildInfo.version}"]`) 56 + expect(tagLink.exists()).toBe(true) 57 + }) 58 + })