Skip to content

Commit c8ed119

Browse files
authored
Merge branch 'main' into refactor/footer-structure
2 parents b6b0b18 + 9c5a6cb commit c8ed119

File tree

12 files changed

+469
-14
lines changed

12 files changed

+469
-14
lines changed

app/components/CopyToClipboardButton.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ function handleClick() {
3737
class="absolute z-20 inset-is-0 top-full inline-flex items-center gap-1 px-2 py-1 rounded border text-xs font-mono whitespace-nowrap transition-all duration-150 opacity-0 -translate-y-1 pointer-events-none group-hover:opacity-100 group-hover:translate-y-0 group-hover:pointer-events-auto focus-visible:opacity-100 focus-visible:translate-y-0 focus-visible:pointer-events-auto"
3838
:class="[
3939
$style.copyButton,
40-
copied ? 'text-accent bg-accent/10' : 'text-fg-muted bg-bg border-border',
40+
copied ? ['text-accent', $style.copiedBg] : 'text-fg-muted bg-bg border-border',
4141
]"
4242
:aria-label="copied ? buttonAriaLabelCopied : buttonAriaLabelCopy"
4343
v-bind="buttonAttrs"
@@ -80,6 +80,10 @@ function handleClick() {
8080
translate 0.15s;
8181
}
8282
83+
.copiedBg {
84+
background-color: color-mix(in srgb, var(--accent) 10%, var(--bg));
85+
}
86+
8387
@media (hover: none) {
8488
.copyButton {
8589
display: none;

app/components/Package/LikeCard.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const { user } = useAtproto()
1717
1818
const authModal = useModal('auth-modal')
1919
20-
const { data: likesData } = useFetch(() => `/api/social/likes/${name.value}`, {
20+
const { data: likesData, status: likesStatus } = useFetch(() => `/api/social/likes/${name.value}`, {
2121
default: () => ({ totalLikes: 0, userHasLiked: false }),
2222
server: false,
2323
})
@@ -76,6 +76,7 @@ const likeAction = async () => {
7676
<div class="flex items-center gap-4 justify-between shrink-0">
7777
<ClientOnly>
7878
<TooltipApp
79+
v-if="likesStatus !== 'pending'"
7980
:text="likesData?.userHasLiked ? $t('package.likes.unlike') : $t('package.likes.like')"
8081
position="bottom"
8182
>

app/components/ReadmeTocDropdown.vue

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,27 @@ function handleKeydown(event: KeyboardEvent) {
139139
break
140140
}
141141
}
142+
143+
const itemScrollIntoView = (index: number) => {
144+
const item = props.toc[index]
145+
if (!item) return
146+
const el = document.getElementById(`${listboxId}-${item.id}`)
147+
if (el) {
148+
el.scrollIntoView({ block: 'center' })
149+
}
150+
}
151+
152+
watch(
153+
isOpen,
154+
open => {
155+
if (open && highlightedIndex.value >= 0) {
156+
itemScrollIntoView(highlightedIndex.value)
157+
}
158+
},
159+
{
160+
flush: 'post',
161+
},
162+
)
142163
</script>
143164

144165
<template>

app/pages/blog/alpha-release.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,12 @@ headline="Read more from the community"
238238
title: 'Finding an accessibility-first culture in npmx',
239239
authorHandle: 'abbeyperini.dev',
240240
description: 'Abbey Perini talks about how accessibility is a deep part of the npmx culture.'
241+
},
242+
{
243+
url: 'https://jonathanyeong.com/writing/npmx-and-the-open-source-mindset/',
244+
title: 'npmx and the open source mindset',
245+
authorHandle: 'jonathanyeong.com',
246+
description: 'How npmx taught me to embrace the open source mindset.'
241247
}
242248
]"
243249
/>

app/pages/package/[[org]]/[name].vue

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,27 @@ const router = useRouter()
3333
3434
const header = useTemplateRef('header')
3535
const isHeaderPinned = shallowRef(false)
36+
const readmeHeader = useTemplateRef('readmeHeader')
37+
const isReadmeHeaderPinned = shallowRef(false)
3638
const navExtraOffset = shallowRef(0)
3739
const isMobile = useMediaQuery('(max-width: 639.9px)')
3840
39-
function checkHeaderPosition() {
40-
const el = header.value
41-
if (!el) return
41+
const headerBounds = useElementBounding(header)
42+
const readmeStickyTop = computed(() => `${56 + headerBounds.height.value}px`)
43+
44+
function isStickyPinned(el: HTMLElement | null): boolean {
45+
if (!el) return false
4246
4347
const style = getComputedStyle(el)
4448
const top = parseFloat(style.top) || 0
4549
const rect = el.getBoundingClientRect()
4650
47-
isHeaderPinned.value = Math.abs(rect.top - top) < 1
51+
return Math.abs(rect.top - top) < 1
52+
}
53+
54+
function checkHeaderPosition() {
55+
isHeaderPinned.value = isStickyPinned(header.value)
56+
isReadmeHeaderPinned.value = isStickyPinned(readmeHeader.value)
4857
}
4958
5059
useEventListener('scroll', checkHeaderPosition, { passive: true })
@@ -1394,7 +1403,12 @@ const showSkeleton = shallowRef(false)
13941403

13951404
<!-- README -->
13961405
<section id="readme" class="min-w-0 scroll-mt-20" :class="$style.areaReadme">
1397-
<div class="flex flex-wrap items-center justify-between mb-3 px-1">
1406+
<div
1407+
ref="readmeHeader"
1408+
class="flex sticky z-10 flex-wrap items-center justify-between mb-3 py-2 -mx-1 px-2 transition-shadow duration-200"
1409+
:class="{ 'bg-bg border-border border-b': isReadmeHeaderPinned }"
1410+
:style="{ top: readmeStickyTop }"
1411+
>
13981412
<h2 id="readme-heading" class="group text-xs text-fg-subtle uppercase tracking-wider">
13991413
<LinkBase to="#readme">
14001414
{{ $t('package.readme.title') }}

app/pages/package/[[org]]/[name]/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// stub page to help with paths
33
definePageMeta({
44
name: 'package',
5-
scrollMargin: 150,
5+
scrollMargin: 200,
66
})
77
</script>
88

app/pages/profile/[identity]/index.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ if (!profile.value || profileError.value?.statusCode === 404) {
2323
})
2424
}
2525
26-
const { user } = useAtproto()
26+
const { user, pending: userPending } = useAtproto()
2727
const isEditing = ref(false)
2828
const displayNameInput = ref()
2929
const descriptionInput = ref()
@@ -84,6 +84,7 @@ const showInviteSection = computed(() => {
8484
profile.value.recordExists === false &&
8585
status.value === 'success' &&
8686
!likes.value?.records?.length &&
87+
!userPending.value &&
8788
user.value?.handle !== profile.value.handle
8889
)
8990
})

i18n/locales/fr-FR.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"social": "réseaux sociaux",
1919
"chat": "espace de discussion",
2020
"blog": "blog",
21+
"builders_chat": "builders",
2122
"keyboard_shortcuts": "raccourcis clavier"
2223
},
2324
"shortcuts": {
@@ -64,7 +65,13 @@
6465
"org": "organisation",
6566
"view_user_packages": "Voir les paquets de cet utilisateur",
6667
"view_org_packages": "Voir les paquets de cette organisation"
67-
}
68+
},
69+
"instant_search": "Recherche instantanée",
70+
"instant_search_on": "activée",
71+
"instant_search_off": "désactivée",
72+
"instant_search_turn_on": "activer",
73+
"instant_search_turn_off": "désactiver",
74+
"instant_search_advisory": "{label} {state} — {action}"
6875
},
6976
"nav": {
7077
"main_navigation": "Barre de navigation",
@@ -958,6 +965,11 @@
958965
"description": "Discutez, posez des questions et partagez des idées.",
959966
"cta": "Joindre le Discord"
960967
},
968+
"builders": {
969+
"title": "Aidez à construire npmx",
970+
"description": "Rejoignez les builders qui façonnent l'avenir de npmx.",
971+
"cta": "Rejoindre le Discord Builders"
972+
},
961973
"follow": {
962974
"title": "Rester à jour",
963975
"description": "Découvrez les dernières nouveautés de npmx.",

i18n/locales/zh-CN.json

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"source": "源码",
1919
"social": "社交媒体",
2020
"chat": "聊天",
21+
"builders_chat": "构建者",
2122
"keyboard_shortcuts": "键盘快捷键"
2223
},
2324
"shortcuts": {
@@ -64,7 +65,13 @@
6465
"org": "组织",
6566
"view_user_packages": "查看该用户的包",
6667
"view_org_packages": "查看该组织的包"
67-
}
68+
},
69+
"instant_search": "即时搜索",
70+
"instant_search_on": "已开启",
71+
"instant_search_off": "已关闭",
72+
"instant_search_turn_on": "开启",
73+
"instant_search_turn_off": "关闭",
74+
"instant_search_advisory": "{label} {state} — {action}"
6875
},
6976
"nav": {
7077
"main_navigation": "主页",
@@ -85,6 +92,8 @@
8592
"author": {
8693
"view_profile": "在 Bluesky 上查看 {name} 的资料"
8794
},
95+
"draft_badge": "草稿",
96+
"draft_banner": "这是一篇未发布的草稿。内容可能不完整或包含不准确的信息。",
8897
"atproto": {
8998
"view_on_bluesky": "在 Bluesky 上查看",
9099
"reply_on_bluesky": "在 Bluesky 上回复",
@@ -120,6 +129,8 @@
120129
"algolia": "Algolia",
121130
"algolia_description": "使用 Algolia 来实现更快的搜索,适用于组织页和用户页。"
122131
},
132+
"instant_search": "即时搜索",
133+
"instant_search_description": "导航到搜索页面并在输入时更新结果。",
123134
"relative_dates": "相对时间",
124135
"include_types": "在安装时包含 {'@'}types",
125136
"include_types_description": "为未提供类型定义的包自动添加 {'@'}types 包到安装命令",
@@ -954,6 +965,11 @@
954965
"description": "聊天、提出问题并分享想法。",
955966
"cta": "加入 Discord"
956967
},
968+
"builders": {
969+
"title": "参与构建 npmx",
970+
"description": "加入构建者团队,共同塑造 npmx 的未来。",
971+
"cta": "加入构建者 Discord"
972+
},
957973
"follow": {
958974
"title": "保持更新",
959975
"description": "了解 npmx 的最新动态。",
@@ -1163,6 +1179,34 @@
11631179
"close_files_panel": "关闭文件面板",
11641180
"filter_files_label": "按更改类型筛选文件"
11651181
},
1182+
"pds": {
1183+
"title": "npmx.social",
1184+
"meta_description": "npmx 社区的官方 AT Protocol 个人数据服务器 (PDS)。",
1185+
"join": {
1186+
"title": "加入社区",
1187+
"description": "无论你是第一次在 Atmosphere 上创建账户,还是迁移现有账户,这里都是你的归属。你可以迁移当前账户,而不会丢失你的账户、帖子或关注者。",
1188+
"migrate": "使用 PDS MOOver 迁移"
1189+
},
1190+
"server": {
1191+
"title": "服务器详情",
1192+
"location_label": "位置:",
1193+
"location_value": "德国,纽伦堡",
1194+
"infrastructure_label": "基础设施:",
1195+
"infrastructure_value": "托管于 Hetzner",
1196+
"privacy_label": "隐私:",
1197+
"privacy_value": "受欧盟严格的数据保护法律约束",
1198+
"learn_more": "了解 npmx 如何使用 Atmosphere"
1199+
},
1200+
"community": {
1201+
"title": "谁在这里",
1202+
"description": "在 {count} 个已将 npmx.social 视为家的账户中,这里有一些:",
1203+
"loading": "正在加载 PDS 社区...",
1204+
"error": "加载 PDS 社区失败。",
1205+
"empty": "没有社区成员可显示。",
1206+
"view_profile": "查看 {handle} 的资料",
1207+
"new_accounts": "...以及 {count} 个新加入 Atmosphere 的账户"
1208+
}
1209+
},
11661210
"privacy_policy": {
11671211
"title": "隐私政策",
11681212
"last_updated": "上次更新:{date}",

test/nuxt/components/PackageLikeCard.spec.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,11 @@ describe('PackageLikeCard', () => {
4444

4545
expect(wrapper.find('span.truncate').text()).toBe('@scope/pkg')
4646
})
47+
48+
it('hides the like button entirely while like data is pending', async () => {
49+
wrapper = await mountLikeCard('https://npmx.dev/package/vue')
50+
51+
const button = wrapper.find('button')
52+
expect(button.exists()).toBe(false)
53+
})
4754
})

0 commit comments

Comments
 (0)