Skip to content

Commit 10e507c

Browse files
committed
Merge branch 'main' into fix-color-contrast
2 parents dd138c0 + 50ed3fb commit 10e507c

83 files changed

Lines changed: 3664 additions & 1751 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/autofix.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ jobs:
3232
- name: 📦 Install dependencies
3333
run: pnpm install
3434

35-
- name: 🎨 Check for non-RTL CSS classes
36-
run: pnpm rtl:check
35+
- name: 🎨 Check for non-RTL/non-a11y CSS classes
36+
run: pnpm lint:css
3737

3838
- name: 🌐 Compare translations
3939
run: pnpm i18n:check

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,7 @@ test-results/
4040
# generated files
4141
shared/types/lexicons
4242

43+
**/__screenshots__/**
44+
4345
# output
4446
.vercel

.nuxtrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
setups.@nuxt/test-utils="3.23.0"
1+
setups.@nuxt/test-utils="4.0.0"

app/assets/main.css

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
--accent: var(--accent-color, oklch(1 0 0));
2828
--accent-muted: var(--accent-color, oklch(0.922 0 0));
2929

30+
/* accent colors */
31+
--swatch-coral: oklch(0.704 0.177 14.75);
32+
--swatch-amber: oklch(0.828 0.165 84.429);
33+
--swatch-emerald: oklch(0.792 0.153 166.95);
34+
--swatch-sky: oklch(0.787 0.128 230.318);
35+
--swatch-violet: oklch(0.78 0.148 286.067);
36+
--swatch-magenta: oklch(0.78 0.15 330);
37+
3038
/* syntax highlighting colors */
3139
--syntax-fn: oklch(0.727 0.137 299.149);
3240
--syntax-str: oklch(0.829 0.088 252.458);
@@ -89,6 +97,14 @@
8997
--accent: var(--accent-color, oklch(0.145 0 0));
9098
--accent-muted: var(--accent-color, oklch(0.205 0 0));
9199

100+
/* accent colors */
101+
--swatch-coral: oklch(0.7 0.19 14.75);
102+
--swatch-amber: oklch(0.8 0.25 84.429);
103+
--swatch-emerald: oklch(0.7 0.17 166.95);
104+
--swatch-sky: oklch(0.7 0.15 230.318);
105+
--swatch-violet: oklch(0.7 0.17 286.067);
106+
--swatch-magenta: oklch(0.75 0.18 330);
107+
92108
--syntax-fn: oklch(0.502 0.188 294.988);
93109
--syntax-str: oklch(0.425 0.152 252);
94110
--syntax-kw: oklch(0.588 0.193 20.469);
@@ -155,6 +171,26 @@
155171
}
156172
}
157173

174+
/*
175+
* Forced Colors Mode (WHCM) Override for Icons
176+
*
177+
* By default, `forced-color-adjust: preserve-parent-color` (from UnoConfig) works fine
178+
* for most icons as they inherit the correct text color.
179+
*
180+
* However, if icons disappear in specific contexts (e.g., inside buttons with
181+
* complex backgrounds or transparent states), uncomment the following block
182+
* to enforce visibility using `CanvasText`.
183+
*/
184+
/*
185+
@media (forced-colors: active) {
186+
[class^='i-'],
187+
[class*=' i-'] {
188+
forced-color-adjust: none !important;
189+
color: CanvasText !important;
190+
}
191+
}
192+
*/
193+
158194
html {
159195
-webkit-font-smoothing: antialiased;
160196
-moz-osx-font-smoothing: grayscale;

app/components/Compare/FacetSelector.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ function isCategoryNoneSelected(category: string): boolean {
2929
<div v-for="category in categoryOrder" :key="category">
3030
<!-- Category header with all/none buttons -->
3131
<div class="flex items-center gap-2 mb-2">
32-
<span class="text-[10px] text-fg-subtle uppercase tracking-wider">
32+
<span class="text-3xs text-fg-subtle uppercase tracking-wider">
3333
{{ getCategoryLabel(category) }}
3434
</span>
3535
<button
3636
type="button"
37-
class="text-[10px] transition-colors focus-visible:outline-none focus-visible:underline focus-visible:underline-accent"
37+
class="text-3xs transition-colors focus-visible:outline-none focus-visible:underline focus-visible:underline-accent"
3838
:class="
3939
isCategoryAllSelected(category)
4040
? 'text-fg-muted'
@@ -48,10 +48,10 @@ function isCategoryNoneSelected(category: string): boolean {
4848
>
4949
{{ $t('compare.facets.all') }}
5050
</button>
51-
<span class="text-[10px] text-fg-muted/40">/</span>
51+
<span class="text-2xs text-fg-muted/40">/</span>
5252
<button
5353
type="button"
54-
class="text-[10px] transition-colors focus-visible:outline-none focus-visible:underline focus-visible:underline-accent"
54+
class="text-3xs transition-colors focus-visible:outline-none focus-visible:underline focus-visible:underline-accent"
5555
:class="
5656
isCategoryNoneSelected(category)
5757
? 'text-fg-muted'
@@ -94,7 +94,7 @@ function isCategoryNoneSelected(category: string): boolean {
9494
aria-hidden="true"
9595
/>
9696
{{ facet.label }}
97-
<span v-if="facet.comingSoon" class="text-[9px]"
97+
<span v-if="facet.comingSoon" class="text-4xs"
9898
>({{ $t('compare.facets.coming_soon') }})</span
9999
>
100100
</button>

app/components/Compare/PackageSelector.vue

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,18 @@ function removePackage(name: string) {
7777
}
7878
7979
function handleKeydown(e: KeyboardEvent) {
80-
if (e.key === 'Enter' && inputValue.value.trim()) {
80+
const inputValueTrim = inputValue.value.trim()
81+
const hasMatchInPackages = filteredResults.value.find(result => {
82+
return result.name === inputValueTrim
83+
})
84+
85+
if (e.key === 'Enter' && inputValueTrim) {
8186
e.preventDefault()
82-
addPackage(inputValue.value.trim())
87+
if (showNoDependencyOption.value) {
88+
addPackage(NO_DEPENDENCY_ID)
89+
} else if (hasMatchInPackages) {
90+
addPackage(inputValueTrim)
91+
}
8392
}
8493
}
8594

app/components/DependencyPathPopup.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ function parsePackageString(pkg: string): { name: string; version: string } {
6868
<!-- Path badge button -->
6969
<button
7070
type="button"
71-
class="path-badge font-mono text-[10px] px-1.5 py-0.5 rounded bg-amber-500/10 border border-amber-500/30 text-amber-700 dark:text-amber-400 cursor-pointer transition-all duration-200 ease-out whitespace-nowrap flex items-center gap-1 hover:bg-amber-500/20 hover:border-amber-500/50"
71+
class="path-badge font-mono text-3xs px-1.5 py-0.5 rounded bg-amber-500/10 border border-amber-500/30 text-amber-700 dark:text-amber-400 cursor-pointer transition-all duration-200 ease-out whitespace-nowrap flex items-center gap-1 hover:bg-amber-500/20 hover:border-amber-500/50"
7272
:aria-expanded="isOpen"
7373
@click.stop="togglePopup"
7474
>

app/components/Header/AccountMenu.client.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ function openAuthModal() {
120120
<!-- Operation count badge (when npm connected with pending ops) -->
121121
<span
122122
v-if="isNpmConnected && operationCount > 0"
123-
class="absolute -top-1 -inset-ie-1 min-w-[1rem] h-4 px-1 flex items-center justify-center font-mono text-[10px] rounded-full"
123+
class="absolute -top-1 -inset-ie-1 min-w-[1rem] h-4 px-1 flex items-center justify-center font-mono text-3xs rounded-full"
124124
:class="hasPendingOperations ? 'bg-yellow-500 text-black' : 'bg-blue-500 text-white'"
125125
aria-hidden="true"
126126
>
Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<template>
2-
<div class="flex items-center justify-end gap-2 px-2 py-1.5 min-w-24">
3-
<span class="font-mono text-sm text-fg-muted">{{ $t('account_menu.connect') }}</span>
4-
<span class="i-carbon-chevron-down w-3 h-3 text-fg-muted" aria-hidden="true" />
2+
<div class="relative flex min-w-24 justify-end">
3+
<div
4+
class="inline-flex gap-x-1 items-center justify-center font-mono border border-border rounded-md text-sm px-4 py-2 bg-transparent text-fg border-none"
5+
>
6+
<span class="font-mono text-sm text-fg-muted">{{ $t('account_menu.connect') }}</span>
7+
<span class="i-carbon-chevron-down w-3 h-3 text-fg-muted" aria-hidden="true" />
8+
</div>
59
</div>
610
</template>

app/components/Header/AuthModal.client.vue

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
<script setup lang="ts">
22
import { useAtproto } from '~/composables/atproto/useAtproto'
33
import { authRedirect } from '~/utils/atproto/helpers'
4+
import { ensureValidAtIdentifier } from '@atproto/syntax'
45
56
const handleInput = shallowRef('')
7+
const errorMessage = shallowRef('')
68
const route = useRoute()
79
const { user, logout } = useAtproto()
810
@@ -13,26 +15,41 @@ const localeSubPath = ['ko', 'pt', 'ja'].includes(currentLang) ? currentLang : '
1315
const atprotoLink = `https://atproto.com/${localeSubPath}`
1416
1517
async function handleBlueskySignIn() {
16-
await authRedirect('https://bsky.social', { redirectTo: route.fullPath })
18+
await authRedirect('https://bsky.social', { redirectTo: route.fullPath, locale: locale.value })
1719
}
1820
1921
async function handleCreateAccount() {
20-
await authRedirect('https://npmx.social', { create: true, redirectTo: route.fullPath })
22+
await authRedirect('https://npmx.social', {
23+
create: true,
24+
redirectTo: route.fullPath,
25+
locale: locale.value,
26+
})
2127
}
2228
2329
async function handleLogin() {
2430
if (handleInput.value) {
25-
await authRedirect(handleInput.value)
31+
// URLS to PDSs are valid for oauth redirects
32+
if (!handleInput.value.startsWith('https://')) {
33+
try {
34+
ensureValidAtIdentifier(handleInput.value)
35+
} catch (error) {
36+
errorMessage.value =
37+
error instanceof Error ? error.message : $t('auth.modal.default_input_error')
38+
return
39+
}
40+
}
41+
await authRedirect(handleInput.value, {
42+
redirectTo: route.fullPath,
43+
locale: locale.value,
44+
})
2645
}
2746
}
2847
2948
watch(handleInput, newHandleInput => {
49+
errorMessage.value = ''
3050
if (!newHandleInput) return
3151
32-
const normalized = newHandleInput
33-
.trim()
34-
.toLowerCase()
35-
.replace(/[^a-z0-9.-]/g, '')
52+
const normalized = newHandleInput.trim().toLowerCase().replace(/@/g, '')
3653
3754
if (normalized !== newHandleInput) {
3855
handleInput.value = normalized
@@ -81,6 +98,9 @@ watch(handleInput, newHandleInput => {
8198
v-bind="noCorrect"
8299
class="w-full px-3 py-2 font-mono text-sm bg-bg-subtle border border-border rounded-md text-fg placeholder:text-fg-subtle transition-colors duration-200 hover:border-fg-subtle focus:border-accent focus-visible:(outline-2 outline-accent/70)"
83100
/>
101+
<p v-if="errorMessage" class="text-red-500 text-xs mt-1" role="alert">
102+
{{ errorMessage }}
103+
</p>
84104
</div>
85105

86106
<details class="text-sm">

0 commit comments

Comments
 (0)