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

feat: accessible rings, accent colors & visual changes (#904)

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

authored by

Jaydip Sanghani
Daniel Roe
and committed by
GitHub
ac1171a8 3b7c0277

+356 -271
+9 -2
app/assets/main.css
··· 196 196 } 197 197 198 198 a:focus-visible { 199 - outline: 2px solid var(--border); 199 + outline: 2px solid var(--accent); 200 200 outline-offset: 2px; 201 - border-radius: 2px; 201 + border-radius: 4px; 202 202 } 203 203 204 204 /* Reset dd margin (browser default is margin-left: 40px) */ ··· 213 213 cursor: pointer; 214 214 font: inherit; 215 215 padding: 0; 216 + } 217 + 218 + button:focus-visible, 219 + select:focus-visible { 220 + outline: 2px solid var(--accent); 221 + outline-offset: 2px; 222 + border-radius: 4px; 216 223 } 217 224 218 225 /* Selection */
+5 -5
app/components/AppFooter.vue
··· 15 15 </div> 16 16 <!-- Desktop: Show all links. Mobile: Links are in MobileMenu --> 17 17 <div class="hidden sm:flex items-center gap-6"> 18 - <NuxtLink to="/about" class="link-subtle font-mono text-xs min-h-11 flex items-center"> 18 + <NuxtLink to="/about" class="link-subtle font-mono text-xs flex items-center"> 19 19 {{ $t('footer.about') }} 20 20 </NuxtLink> 21 21 <a 22 22 href="https://docs.npmx.dev" 23 23 target="_blank" 24 24 rel="noopener noreferrer" 25 - class="link-subtle font-mono text-xs min-h-11 flex items-center gap-1" 25 + class="link-subtle font-mono text-xs flex items-center gap-1" 26 26 > 27 27 {{ $t('footer.docs') }} 28 28 <span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" /> ··· 31 31 href="https://repo.npmx.dev" 32 32 target="_blank" 33 33 rel="noopener noreferrer" 34 - class="link-subtle font-mono text-xs min-h-11 flex items-center gap-1" 34 + class="link-subtle font-mono text-xs flex items-center gap-1" 35 35 > 36 36 {{ $t('footer.source') }} 37 37 <span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" /> ··· 40 40 href="https://social.npmx.dev" 41 41 target="_blank" 42 42 rel="noopener noreferrer" 43 - class="link-subtle font-mono text-xs min-h-11 flex items-center gap-1" 43 + class="link-subtle font-mono text-xs flex items-center gap-1" 44 44 > 45 45 {{ $t('footer.social') }} 46 46 <span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" /> ··· 49 49 href="https://chat.npmx.dev" 50 50 target="_blank" 51 51 rel="noopener noreferrer" 52 - class="link-subtle font-mono text-xs min-h-11 flex items-center gap-1" 52 + class="link-subtle font-mono text-xs flex items-center gap-1" 53 53 > 54 54 {{ $t('footer.chat') }} 55 55 <span class="i-carbon:launch rtl-flip w-3 h-3" aria-hidden="true" />
+8 -22
app/components/AppHeader.vue
··· 95 95 <button 96 96 v-if="!isSearchExpanded && !isOnHomePage" 97 97 type="button" 98 - class="sm:hidden flex-shrink-0 inline-flex items-center gap-2 font-mono text-lg font-medium text-fg hover:text-fg transition-colors duration-200 focus-ring rounded" 98 + class="sm:hidden flex-shrink-0 inline-flex items-center gap-2 font-mono text-lg font-medium text-fg hover:text-fg transition-colors duration-200 rounded" 99 99 :aria-label="$t('nav.tap_to_search')" 100 100 @click="expandMobileSearch" 101 101 > 102 - <img 103 - aria-hidden="true" 104 - :alt="$t('alt_logo')" 105 - src="/logo.svg" 106 - width="96" 107 - height="96" 108 - class="w-8 h-8 rounded-lg" 109 - /> 102 + <AppLogo class="w-8 h-8 rounded-lg" /> 110 103 <span class="i-carbon:search w-4 h-4 text-fg-subtle" aria-hidden="true" /> 111 104 </button> 112 105 ··· 116 109 to="/" 117 110 :aria-label="$t('header.home')" 118 111 dir="ltr" 119 - class="inline-flex items-center gap-2 header-logo font-mono text-lg font-medium text-fg hover:text-fg transition-colors duration-200 focus-ring rounded" 112 + class="inline-flex items-center gap-2 header-logo font-mono text-lg font-medium text-fg hover:text-fg transition-colors duration-200 rounded" 120 113 > 121 - <img 122 - aria-hidden="true" 123 - :alt="$t('alt_logo')" 124 - src="/logo.svg" 125 - width="96" 126 - height="96" 127 - class="w-8 h-8 rounded-lg" 128 - /> 114 + <AppLogo class="w-8 h-8 rounded-lg" /> 129 115 <span>npmx</span> 130 116 </NuxtLink> 131 117 </div> ··· 163 149 </div> 164 150 165 151 <!-- End: Desktop nav items + Mobile menu button --> 166 - <div class="flex-shrink-0 flex items-center gap-4 sm:gap-6"> 152 + <div class="flex-shrink-0 flex items-center gap-0.5 sm:gap-2"> 167 153 <!-- Desktop: Compare link --> 168 154 <NuxtLink 169 155 to="/compare" 170 - class="hidden sm:inline-flex link-subtle font-mono text-sm items-center gap-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50 rounded" 156 + class="hidden sm:inline-flex link-subtle font-mono text-sm items-center gap-2 px-2 py-1.5 hover:bg-bg-subtle focus-visible:outline-accent/70 rounded" 171 157 aria-keyshortcuts="c" 172 158 > 173 159 {{ $t('nav.compare') }} ··· 182 168 <!-- Desktop: Settings link --> 183 169 <NuxtLink 184 170 to="/settings" 185 - class="hidden sm:inline-flex link-subtle font-mono text-sm items-center gap-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50 rounded" 171 + class="hidden sm:inline-flex link-subtle font-mono text-sm items-center gap-2 px-2 py-1.5 hover:bg-bg-subtle focus-visible:outline-accent/70 rounded" 186 172 aria-keyshortcuts="," 187 173 > 188 174 {{ $t('nav.settings') }} ··· 202 188 <!-- Mobile: Menu button (always visible, toggles menu) --> 203 189 <button 204 190 type="button" 205 - class="sm:hidden flex items-center p-2 -m-2 text-fg-subtle hover:text-fg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50 rounded" 191 + class="sm:hidden flex items-center p-2 -m-2 text-fg-subtle hover:text-fg transition-colors duration-200 focus-visible:outline-accent/70 rounded" 206 192 :aria-label="showMobileMenu ? $t('common.close') : $t('nav.open_menu')" 207 193 :aria-expanded="showMobileMenu" 208 194 @click="showMobileMenu = !showMobileMenu"
+31
app/components/AppLogo.vue
··· 1 + <script setup lang="ts"> 2 + defineProps<{ 3 + class?: string 4 + }>() 5 + </script> 6 + 7 + <template> 8 + <svg 9 + aria-hidden="true" 10 + xmlns="http://www.w3.org/2000/svg" 11 + viewBox="0 0 512 512" 12 + width="96" 13 + height="96" 14 + :class="class" 15 + > 16 + <title>{{ $t('alt_logo') }}</title> 17 + <rect fill="var(--bg)" width="512" height="512" rx="64" /> 18 + <rect fill="var(--fg)" x="110" y="310" width="60" height="60" /> 19 + <text 20 + fill="var(--accent)" 21 + x="320" 22 + y="370" 23 + font-family="'Geist Mono',ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 24 + font-size="420" 25 + font-weight="500" 26 + text-anchor="middle" 27 + > 28 + <tspan>/</tspan> 29 + </text> 30 + </svg> 31 + </template>
+7 -4
app/components/CollapsibleSection.vue
··· 76 76 77 77 <template> 78 78 <section class="scroll-mt-20" :data-anchor-id="id"> 79 - <div class="flex items-center justify-between mb-3"> 79 + <div class="flex items-center justify-between mb-3 px-1"> 80 80 <component 81 81 :is="headingLevel" 82 82 :id="headingId" ··· 85 85 <button 86 86 :id="buttonId" 87 87 type="button" 88 - class="w-4 h-4 flex items-center justify-center text-fg-subtle hover:text-fg-muted transition-colors duration-200 shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 88 + class="w-4 h-4 flex items-center justify-center text-fg-subtle hover:text-fg-muted transition-colors duration-200 shrink-0 focus-visible:outline-accent/70 rounded" 89 89 :aria-expanded="isOpen" 90 90 :aria-controls="contentId" 91 91 :aria-label="ariaLabel" ··· 118 118 </component> 119 119 120 120 <!-- Actions slot for buttons or other elements --> 121 - <slot name="actions" /> 121 + <div class="pe-1"> 122 + <slot name="actions" /> 123 + </div> 122 124 </div> 123 125 124 126 <div 125 127 :id="contentId" 126 128 class="grid ms-6 transition-[grid-template-rows] duration-200 ease-in-out collapsible-content overflow-hidden" 129 + :inert="!isOpen" 127 130 > 128 - <div class="min-h-0 min-w-0"> 131 + <div class="min-h-0 min-w-0 p-1"> 129 132 <slot /> 130 133 </div> 131 134 </div>
+3 -3
app/components/Compare/FacetSelector.vue
··· 34 34 </span> 35 35 <button 36 36 type="button" 37 - class="text-[10px] transition-colors focus-visible:outline-none focus-visible:underline" 37 + class="text-[10px] transition-colors focus-visible:outline-none focus-visible:underline focus-visible:underline-accent" 38 38 :class=" 39 39 isCategoryAllSelected(category) 40 40 ? 'text-fg-muted' ··· 51 51 <span class="text-[10px] text-fg-muted/40">/</span> 52 52 <button 53 53 type="button" 54 - class="text-[10px] transition-colors focus-visible:outline-none focus-visible:underline" 54 + class="text-[10px] transition-colors focus-visible:outline-none focus-visible:underline focus-visible:underline-accent" 55 55 :class=" 56 56 isCategoryNoneSelected(category) 57 57 ? 'text-fg-muted' ··· 77 77 :disabled="facet.comingSoon" 78 78 :aria-pressed="isFacetSelected(facet.id)" 79 79 :aria-label="facet.label" 80 - class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded border transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 80 + class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded border transition-colors duration-200 focus-visible:outline-accent/70" 81 81 :class=" 82 82 facet.comingSoon 83 83 ? 'text-fg-subtle/50 bg-bg-subtle border-border-subtle cursor-not-allowed'
+4 -4
app/components/Compare/PackageSelector.vue
··· 71 71 </NuxtLink> 72 72 <button 73 73 type="button" 74 - class="text-fg-subtle hover:text-fg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50 rounded" 74 + class="text-fg-subtle hover:text-fg transition-colors focus-visible:outline-accent/70 rounded" 75 75 :aria-label="$t('compare.selector.remove_package', { package: pkg })" 76 76 @click="removePackage(pkg)" 77 77 > ··· 82 82 83 83 <!-- Add package input --> 84 84 <div v-if="packages.length < maxPackages" class="relative"> 85 - <div class="relative"> 85 + <div class="relative group"> 86 86 <label for="package-search" class="sr-only"> 87 87 {{ $t('compare.selector.search_label') }} 88 88 </label> 89 89 <span 90 - class="absolute inset-is-3 top-1/2 -translate-y-1/2 text-fg-subtle flex" 90 + class="absolute inset-y-0 start-3 flex items-center text-fg-subtle pointer-events-none group-focus-within:text-accent" 91 91 aria-hidden="true" 92 92 > 93 93 <span class="i-carbon:search w-4 h-4" /> ··· 101 101 ? $t('compare.selector.search_first') 102 102 : $t('compare.selector.search_add') 103 103 " 104 - class="w-full bg-bg-subtle border border-border rounded-lg ps-10 pe-4 py-2.5 font-mono text-sm text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-accent focus-visible:outline-none" 104 + class="w-full bg-bg-subtle border border-border rounded-lg ps-10 pe-4 py-2.5 font-mono text-sm text-fg placeholder:text-fg-subtle motion-reduce:transition-none duration-200 focus:border-accent focus-visible:(outline-2 outline-accent/70)" 105 105 aria-autocomplete="list" 106 106 @focus="isInputFocused = true" 107 107 @blur="handleBlur"
+1 -1
app/components/Header/AccountMenu.client.vue
··· 59 59 <div ref="accountMenuRef" class="relative flex min-w-24 justify-end"> 60 60 <button 61 61 type="button" 62 - class="relative flex items-center gap-2 px-2 py-1.5 rounded-md transition-colors duration-200 hover:bg-bg-subtle focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 62 + class="relative flex items-center gap-2 px-2 py-1.5 rounded-md transition-colors duration-200 hover:bg-bg-subtle hover:text-accent focus-visible:outline-accent/70" 63 63 :aria-expanded="isOpen" 64 64 aria-haspopup="true" 65 65 @click="isOpen = !isOpen"
+7 -7
app/components/Header/AuthModal.client.vue
··· 34 34 </div> 35 35 </div> 36 36 <button 37 - class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 37 + class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70" 38 38 @click="logout" 39 39 > 40 40 {{ $t('auth.modal.disconnect') }} ··· 61 61 :placeholder="$t('auth.modal.handle_placeholder')" 62 62 autocomplete="off" 63 63 spellcheck="false" 64 - 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 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 64 + 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 focus:border-accent focus-visible:(outline-2 outline-accent/70)" 65 65 /> 66 66 </div> 67 67 68 68 <details class="text-sm"> 69 69 <summary 70 - class="text-fg-subtle cursor-pointer hover:text-fg-muted transition-colors duration-200" 70 + class="text-fg-subtle cursor-pointer hover:text-fg-muted transition-colors duration-200 focus-visible:(outline-2 outline-accent/70)" 71 71 > 72 72 {{ $t('auth.modal.what_is_atmosphere') }} 73 73 </summary> ··· 99 99 <button 100 100 type="submit" 101 101 :disabled="!handleInput.trim()" 102 - class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 focus-visible:ring-offset-2 focus-visible:ring-offset-bg" 102 + class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70 focus-visible:ring-offset-2 focus-visible:ring-offset-bg" 103 103 > 104 104 {{ $t('auth.modal.connect') }} 105 105 </button> 106 106 <button 107 107 type="button" 108 - class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 focus-visible:ring-offset-2 focus-visible:ring-offset-bg" 108 + class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70 focus-visible:ring-offset-2 focus-visible:ring-offset-bg" 109 109 @click="handleCreateAccount" 110 110 > 111 111 {{ $t('auth.modal.create_account') }} 112 112 </button> 113 - <hr /> 113 + <hr class="color-border" /> 114 114 <button 115 115 type="button" 116 - class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 focus-visible:ring-offset-2 focus-visible:ring-offset-bg flex items-center justify-center gap-2" 116 + class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70 focus-visible:ring-offset-2 focus-visible:ring-offset-bg flex items-center justify-center gap-2" 117 117 @click="handleBlueskySignIn" 118 118 > 119 119 {{ $t('auth.modal.connect_bluesky') }}
+6 -6
app/components/Header/ConnectorModal.vue
··· 70 70 71 71 <button 72 72 type="button" 73 - class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 73 + class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70" 74 74 @click="handleDisconnect" 75 75 > 76 76 {{ $t('connector.modal.disconnect') }} ··· 114 114 <button 115 115 type="button" 116 116 :aria-label="copied ? $t('connector.modal.copied') : $t('connector.modal.copy_command')" 117 - class="ms-auto text-fg-subtle hover:text-fg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 117 + class="ms-auto text-fg-subtle hover:text-fg transition-colors duration-200 focus-visible:outline-accent/70 rounded" 118 118 @click="copy('pnpm npmx-connector')" 119 119 > 120 120 <span v-if="!copied" class="i-carbon:copy w-5 h-5" aria-hidden="true" /> ··· 136 136 :aria-label=" 137 137 copied ? $t('connector.modal.copied') : $t('connector.modal.copy_command') 138 138 " 139 - class="ms-auto text-fg-subtle hover:text-fg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 139 + class="ms-auto text-fg-subtle hover:text-fg transition-colors duration-200 focus-visible:outline-accent/70 rounded" 140 140 @click="copyCommand" 141 141 > 142 142 <span v-if="!copied" class="i-carbon:copy w-5 h-5" aria-hidden="true" /> ··· 167 167 name="connector-token" 168 168 :placeholder="$t('connector.modal.token_placeholder')" 169 169 v-bind="noCorrect" 170 - 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 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50" 170 + 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 focus-visible:outline-none focus-visible:ring-2 focus-visible:outline-accent/70" 171 171 /> 172 172 </div> 173 173 ··· 191 191 name="connector-port" 192 192 inputmode="numeric" 193 193 autocomplete="off" 194 - class="w-full px-3 py-2 font-mono text-sm bg-bg-subtle border border-border rounded-md text-fg transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50" 194 + class="w-full px-3 py-2 font-mono text-sm bg-bg-subtle border border-border rounded-md text-fg transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:outline-accent/70" 195 195 /> 196 196 </div> 197 197 </details> ··· 222 222 <button 223 223 type="submit" 224 224 :disabled="!tokenInput.trim() || isConnecting" 225 - class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 focus-visible:ring-offset-2 focus-visible:ring-offset-bg" 225 + class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70 focus-visible:ring-offset-2 focus-visible:ring-offset-bg" 226 226 > 227 227 {{ isConnecting ? $t('connector.modal.connecting') : $t('connector.modal.connect') }} 228 228 </button>
+1 -1
app/components/Header/MobileMenu.client.vue
··· 91 91 <span class="font-mono text-sm text-fg-muted">{{ $t('nav.menu') }}</span> 92 92 <button 93 93 type="button" 94 - class="p-2 -m-2 text-fg-subtle hover:text-fg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50 rounded" 94 + class="p-2 -m-2 text-fg-subtle hover:text-fg transition-colors duration-200 focus-visible:outline-accent/70 rounded" 95 95 :aria-label="$t('common.close')" 96 96 @click="closeMenu" 97 97 >
+1 -1
app/components/Header/SearchBox.vue
··· 122 122 name="q" 123 123 :placeholder="$t('search.placeholder')" 124 124 v-bind="noCorrect" 125 - class="w-full min-w-25 bg-bg-subtle border border-border rounded-md ps-7 pe-3 py-1.5 font-mono text-sm text-fg placeholder:text-fg-subtle transition-border-color duration-300 motion-reduce:transition-none focus:border-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50" 125 + class="w-full min-w-25 bg-bg-subtle border border-border rounded-md ps-7 pe-3 py-1.5 font-mono text-sm text-fg placeholder:text-fg-subtle transition-border-color duration-300 motion-reduce:transition-none focus:border-accent focus-visible:(outline-2 outline-accent/70)" 126 126 @focus="handleSearchFocus" 127 127 @blur="handleSearchBlur" 128 128 />
+2 -2
app/components/Modal.client.vue
··· 25 25 <dialog 26 26 ref="dialogRef" 27 27 closedby="any" 28 - class="w-full bg-bg border border-border rounded-lg shadow-xl max-h-[90vh] overflow-y-auto overscroll-contain m-0 m-auto p-6 text-fg" 28 + class="w-full bg-bg border border-border rounded-lg shadow-xl max-h-[90vh] overflow-y-auto overscroll-contain m-0 m-auto p-6 text-fg focus-visible:outline focus-visible:outline-accent/70" 29 29 :aria-labelledby="modalTitleId" 30 30 v-bind="$attrs" 31 31 > ··· 36 36 </h2> 37 37 <button 38 38 type="button" 39 - class="text-fg-subtle hover:text-fg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 39 + class="text-fg-subtle w-5 h-5 hover:text-fg transition-colors duration-200 focus-visible:outline-accent/70 rounded" 40 40 :aria-label="$t('common.close')" 41 41 @click="handleModalClose" 42 42 >
+16 -16
app/components/Org/MembersPanel.vue
··· 296 296 </h2> 297 297 <button 298 298 type="button" 299 - class="p-1.5 text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 299 + class="p-1.5 text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 300 300 :aria-label="$t('org.members.refresh')" 301 301 :disabled="isLoading" 302 302 @click="refreshData" ··· 324 324 name="members-search" 325 325 :placeholder="$t('org.members.filter_placeholder')" 326 326 v-bind="noCorrect" 327 - class="w-full ps-7 pe-2 py-1.5 font-mono text-sm bg-bg-subtle border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 327 + class="w-full ps-7 pe-2 py-1.5 font-mono text-sm bg-bg-subtle border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-accent focus-visible:(outline-2 outline-accent/70)" 328 328 /> 329 329 </div> 330 330 <div ··· 336 336 v-for="role in ['all', 'owner', 'admin', 'developer'] as const" 337 337 :key="role" 338 338 type="button" 339 - class="px-2 py-1 font-mono text-xs rounded transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 339 + class="px-2 py-1 font-mono text-xs rounded transition-colors duration-200 focus-visible:outline-accent/70" 340 340 :class="filterRole === role ? 'bg-bg-muted text-fg' : 'text-fg-muted hover:text-fg'" 341 341 :aria-pressed="filterRole === role" 342 342 @click="filterRole = role" ··· 352 352 id="team-filter" 353 353 v-model="filterTeam" 354 354 name="team-filter" 355 - class="px-2 py-1 font-mono text-xs bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 355 + class="px-2 py-1 font-mono text-xs bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover" 356 356 > 357 357 <option :value="null">{{ $t('org.members.all_teams') }}</option> 358 358 <option v-for="team in teamNames" :key="team" :value="team"> ··· 367 367 > 368 368 <button 369 369 type="button" 370 - class="px-2 py-1 font-mono rounded transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 370 + class="px-2 py-1 font-mono rounded transition-colors duration-200 focus-visible:outline-accent/70" 371 371 :class="sortBy === 'name' ? 'bg-bg-muted text-fg' : 'text-fg-muted hover:text-fg'" 372 372 :aria-pressed="sortBy === 'name'" 373 373 @click="toggleSort('name')" ··· 377 377 </button> 378 378 <button 379 379 type="button" 380 - class="px-2 py-1 font-mono rounded transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 380 + class="px-2 py-1 font-mono rounded transition-colors duration-200 focus-visible:outline-accent/70" 381 381 :class="sortBy === 'role' ? 'bg-bg-muted text-fg' : 'text-fg-muted hover:text-fg'" 382 382 :aria-pressed="sortBy === 'role'" 383 383 @click="toggleSort('role')" ··· 404 404 </p> 405 405 <button 406 406 type="button" 407 - class="mt-2 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 407 + class="mt-2 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 408 408 @click="loadMembers" 409 409 > 410 410 {{ $t('common.try_again') }} ··· 451 451 :id="`role-${member.name}`" 452 452 :value="member.role" 453 453 :name="`role-${member.name}`" 454 - class="px-1.5 py-0.5 font-mono text-xs bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 cursor-pointer" 454 + class="px-1.5 py-0.5 font-mono text-xs bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover" 455 455 @change=" 456 456 handleChangeRole( 457 457 member.name, ··· 466 466 <!-- Remove button --> 467 467 <button 468 468 type="button" 469 - class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 469 + class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 rounded focus-visible:outline-accent/70" 470 470 :aria-label="$t('org.members.remove_from_org', { name: member.name })" 471 471 @click="handleRemoveMember(member.name)" 472 472 > ··· 480 480 v-for="team in member.teams" 481 481 :key="team" 482 482 type="button" 483 - class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs text-fg-muted border border-border rounded hover:text-fg hover:border-border-hover transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 483 + class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs text-fg-muted border border-border rounded hover:text-fg hover:border-border-hover transition-colors duration-200 focus-visible:outline-accent/70" 484 484 :aria-label="$t('org.members.view_team', { team })" 485 485 @click="handleTeamClick(team)" 486 486 > ··· 509 509 name="new-member-username" 510 510 :placeholder="$t('org.members.username_placeholder')" 511 511 v-bind="noCorrect" 512 - class="w-full px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 512 + class="w-full px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-accent/70" 513 513 /> 514 514 <div class="flex items-center gap-2"> 515 515 <label for="new-member-role" class="sr-only">{{ $t('org.members.role_label') }}</label> ··· 517 517 id="new-member-role" 518 518 v-model="newRole" 519 519 name="new-member-role" 520 - class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 520 + class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover" 521 521 > 522 522 <option value="developer">{{ $t('org.members.role.developer') }}</option> 523 523 <option value="admin">{{ $t('org.members.role.admin') }}</option> ··· 529 529 id="new-member-team" 530 530 v-model="newTeam" 531 531 name="new-member-team" 532 - class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 532 + class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover" 533 533 > 534 534 <option value="">{{ $t('org.members.no_team') }}</option> 535 535 <option v-for="team in teamNames" :key="team" :value="team"> ··· 539 539 <button 540 540 type="submit" 541 541 :disabled="!newUsername.trim() || isAddingMember" 542 - class="px-3 py-1.5 font-mono text-xs text-bg bg-fg rounded transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 542 + class="px-3 py-1.5 font-mono text-xs text-bg bg-fg rounded transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70" 543 543 > 544 544 {{ isAddingMember ? '…' : $t('org.members.add_button') }} 545 545 </button> 546 546 <button 547 547 type="button" 548 - class="p-1.5 text-fg-subtle hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 548 + class="p-1.5 text-fg-subtle hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 549 549 :aria-label="$t('org.members.cancel_add')" 550 550 @click="showAddMember = false" 551 551 > ··· 557 557 <button 558 558 v-else 559 559 type="button" 560 - class="w-full px-3 py-2 font-mono text-sm text-fg-muted bg-bg border border-border rounded transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 560 + class="w-full px-3 py-2 font-mono text-sm text-fg-muted bg-bg border border-border rounded transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70" 561 561 @click="showAddMember = true" 562 562 > 563 563 {{ $t('org.members.add_member') }}
+8 -8
app/components/Org/OperationsQueue.vue
··· 129 129 <button 130 130 v-if="hasOperations" 131 131 type="button" 132 - class="px-2 py-1 font-mono text-xs text-fg-muted hover:text-fg bg-bg-subtle border border-border rounded transition-colors duration-200 hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 132 + class="px-2 py-1 font-mono text-xs text-fg-muted hover:text-fg bg-bg-subtle border border-border rounded transition-colors duration-200 hover:border-border-hover focus-visible:outline-accent/70" 133 133 :aria-label="$t('operations.queue.clear_all')" 134 134 @click="handleClearAll" 135 135 > ··· 137 137 </button> 138 138 <button 139 139 type="button" 140 - class="p-1 text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 140 + class="p-1 text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 141 141 :aria-label="$t('operations.queue.refresh')" 142 142 @click="refreshState" 143 143 > ··· 209 209 <button 210 210 v-if="op.status === 'pending'" 211 211 type="button" 212 - class="p-1 text-fg-muted hover:text-green-400 transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 212 + class="p-1 text-fg-muted hover:text-green-400 transition-colors duration-200 rounded focus-visible:outline-accent/70" 213 213 :aria-label="$t('operations.queue.approve_operation')" 214 214 @click="approveOperation(op.id)" 215 215 > ··· 218 218 <button 219 219 v-if="op.status !== 'running'" 220 220 type="button" 221 - class="p-1 text-fg-muted hover:text-red-400 transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 221 + class="p-1 text-fg-muted hover:text-red-400 transition-colors duration-200 rounded focus-visible:outline-accent/70" 222 222 :aria-label="$t('operations.queue.remove_operation')" 223 223 @click="removeOperation(op.id)" 224 224 > ··· 252 252 :placeholder="$t('operations.queue.otp_placeholder')" 253 253 autocomplete="one-time-code" 254 254 spellcheck="false" 255 - class="flex-1 px-3 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 255 + class="flex-1 px-3 py-1.5 font-mono text-sm bg-bg border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-accent/70" 256 256 /> 257 257 <button 258 258 type="submit" ··· 269 269 <button 270 270 v-if="hasPendingOperations" 271 271 type="button" 272 - class="flex-1 px-4 py-2 font-mono text-sm text-fg bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 272 + class="flex-1 px-4 py-2 font-mono text-sm text-fg bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:border-border-hover focus-visible:outline-accent/70" 273 273 @click="handleApproveAll" 274 274 > 275 275 {{ $t('operations.queue.approve_all') }} ({{ pendingOperations.length }}) ··· 278 278 v-if="hasApprovedOperations && !hasOtpFailures" 279 279 type="button" 280 280 :disabled="isExecuting" 281 - class="flex-1 px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 focus-visible:ring-offset-2 focus-visible:ring-offset-bg" 281 + class="flex-1 px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70 focus-visible:ring-offset-2 focus-visible:ring-offset-bg" 282 282 @click="handleExecute()" 283 283 > 284 284 {{ ··· 327 327 </div> 328 328 <button 329 329 type="button" 330 - class="p-0.5 text-fg-subtle hover:text-fg-muted transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 330 + class="p-0.5 text-fg-subtle hover:text-fg-muted transition-colors duration-200 rounded focus-visible:outline-accent/70" 331 331 :aria-label="$t('operations.queue.remove_from_log')" 332 332 @click="removeOperation(op.id)" 333 333 >
+16 -16
app/components/Org/TeamsPanel.vue
··· 266 266 <span aria-hidden="true" class="flex-shrink-1 flex-grow-1" /> 267 267 <button 268 268 type="button" 269 - class="p-1.5 text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 269 + class="p-1.5 text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 270 270 :aria-label="$t('org.teams.refresh')" 271 271 :disabled="isLoadingTeams" 272 272 @click="loadTeams" ··· 294 294 name="teams-search" 295 295 :placeholder="$t('org.teams.filter_placeholder')" 296 296 v-bind="noCorrect" 297 - class="w-full ps-7 pe-2 py-1.5 font-mono text-sm bg-bg-subtle border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 297 + class="w-full ps-7 pe-2 py-1.5 font-mono text-sm bg-bg-subtle border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-accent focus-visible:(outline-2 outline-accent/70)" 298 298 /> 299 299 </div> 300 300 <div ··· 304 304 > 305 305 <button 306 306 type="button" 307 - class="px-2 py-1 font-mono rounded transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 307 + class="px-2 py-1 font-mono rounded transition-colors duration-200 focus-visible:outline-accent/70" 308 308 :class="sortBy === 'name' ? 'bg-bg-muted text-fg' : 'text-fg-muted hover:text-fg'" 309 309 :aria-pressed="sortBy === 'name'" 310 310 @click="toggleSort('name')" ··· 314 314 </button> 315 315 <button 316 316 type="button" 317 - class="px-2 py-1 font-mono rounded transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 317 + class="px-2 py-1 font-mono rounded transition-colors duration-200 focus-visible:outline-accent/70" 318 318 :class="sortBy === 'members' ? 'bg-bg-muted text-fg' : 'text-fg-muted hover:text-fg'" 319 319 :aria-pressed="sortBy === 'members'" 320 320 @click="toggleSort('members')" ··· 341 341 </p> 342 342 <button 343 343 type="button" 344 - class="mt-2 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 344 + class="mt-2 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 345 345 @click="loadTeams" 346 346 > 347 347 {{ $t('common.try_again') }} ··· 362 362 > 363 363 <button 364 364 type="button" 365 - class="flex-1 flex items-center gap-2 text-start rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 365 + class="flex-1 flex items-center gap-2 text-start rounded focus-visible:outline-accent/70" 366 366 :aria-expanded="expandedTeams.has(teamName)" 367 367 :aria-controls="`team-${teamName}-members`" 368 368 @click="toggleTeam(teamName)" ··· 394 394 <span aria-hidden="true" class="flex-shrink-1 flex-grow-1" /> 395 395 <button 396 396 type="button" 397 - class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 397 + class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 rounded focus-visible:outline-accent/70" 398 398 :aria-label="$t('org.teams.delete_team', { name: teamName })" 399 399 @click.stop="handleDestroyTeam(teamName)" 400 400 > ··· 428 428 <span class="font-mono text-sm text-fg">{{ teamName }}</span> 429 429 <button 430 430 type="button" 431 - class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 431 + class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 rounded focus-visible:outline-accent/70" 432 432 :aria-label="$t('org.teams.remove_user', { user })" 433 433 @click="handleRemoveUser(teamName, user)" 434 434 > ··· 453 453 :name="`add-user-${teamName}`" 454 454 :placeholder="$t('org.teams.username_placeholder')" 455 455 v-bind="noCorrect" 456 - class="flex-1 px-2 py-1 font-mono text-sm bg-bg-subtle border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 456 + class="flex-1 px-2 py-1 font-mono text-sm bg-bg-subtle border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-accent/70" 457 457 /> 458 458 <button 459 459 type="submit" 460 460 :disabled="!newUserUsername.trim() || isAddingUser" 461 - class="px-2 py-1 font-mono text-xs text-bg bg-fg rounded transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 461 + class="px-2 py-1 font-mono text-xs text-bg bg-fg rounded transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70" 462 462 > 463 463 {{ isAddingUser ? '…' : $t('org.teams.add_button') }} 464 464 </button> 465 465 <button 466 466 type="button" 467 - class="p-1 text-fg-subtle hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 467 + class="p-1 text-fg-subtle hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 468 468 :aria-label="$t('org.teams.cancel_add_user')" 469 469 @click="showAddUserFor = null" 470 470 > ··· 475 475 <button 476 476 v-else 477 477 type="button" 478 - class="mt-2 px-2 py-1 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 478 + class="mt-2 px-2 py-1 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 479 479 @click="showAddUserFor = teamName" 480 480 > 481 481 {{ $t('org.teams.add_member') }} ··· 509 509 name="new-team-name" 510 510 :placeholder="$t('org.teams.team_name_placeholder')" 511 511 v-bind="noCorrect" 512 - class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded-ie text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 512 + class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg border border-border rounded-ie text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-accent/70" 513 513 /> 514 514 </div> 515 515 <button 516 516 type="submit" 517 517 :disabled="!newTeamName.trim() || isCreatingTeam" 518 - class="px-3 py-1.5 font-mono text-xs text-bg bg-fg rounded transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 518 + class="px-3 py-1.5 font-mono text-xs text-bg bg-fg rounded transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70" 519 519 > 520 520 {{ isCreatingTeam ? '…' : $t('org.teams.create_button') }} 521 521 </button> 522 522 <button 523 523 type="button" 524 - class="p-1.5 text-fg-subtle hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 524 + class="p-1.5 text-fg-subtle hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 525 525 :aria-label="$t('org.teams.cancel_create')" 526 526 @click="showCreateTeam = false" 527 527 > ··· 532 532 <button 533 533 v-else 534 534 type="button" 535 - class="w-full px-3 py-2 font-mono text-sm text-fg-muted bg-bg border border-border rounded transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 535 + class="w-full px-3 py-2 font-mono text-sm text-fg-muted bg-bg border border-border rounded transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70" 536 536 @click="showCreateTeam = true" 537 537 > 538 538 {{ $t('org.teams.create_team') }}
+7 -7
app/components/Package/AccessControls.vue
··· 157 157 </h2> 158 158 <button 159 159 type="button" 160 - class="p-1 text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 160 + class="p-1 text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 161 161 :aria-label="$t('package.access.refresh')" 162 162 :disabled="isLoadingCollaborators" 163 163 @click="loadCollaborators" ··· 225 225 <button 226 226 v-if="collab.isTeam" 227 227 type="button" 228 - class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 shrink-0 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 228 + class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 shrink-0 rounded focus-visible:outline-accent/70" 229 229 :aria-label="$t('package.access.revoke_access', { name: collab.displayName })" 230 230 @click="handleRevokeAccess(collab.name)" 231 231 > ··· 250 250 id="grant-team-select" 251 251 v-model="selectedTeam" 252 252 name="grant-team" 253 - class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 253 + class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover" 254 254 :disabled="isLoadingTeams" 255 255 > 256 256 <option value="" disabled> ··· 273 273 id="grant-permission-select" 274 274 v-model="permission" 275 275 name="grant-permission" 276 - class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 276 + class="flex-1 px-2 py-1.5 font-mono text-sm bg-bg-subtle border border-border rounded text-fg transition-colors duration-200 focus:border-border-hover" 277 277 > 278 278 <option value="read-only">{{ $t('package.access.permission.read_only') }}</option> 279 279 <option value="read-write">{{ $t('package.access.permission.read_write') }}</option> ··· 281 281 <button 282 282 type="submit" 283 283 :disabled="!selectedTeam || isGranting" 284 - class="px-3 py-1.5 font-mono text-xs text-bg bg-fg rounded transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 284 + class="px-3 py-1.5 font-mono text-xs text-bg bg-fg rounded transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70" 285 285 > 286 286 {{ isGranting ? '…' : $t('package.access.grant_button') }} 287 287 </button> 288 288 <button 289 289 type="button" 290 - class="p-1.5 text-fg-subtle hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 290 + class="p-1.5 text-fg-subtle hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 291 291 :aria-label="$t('package.access.cancel_grant')" 292 292 @click="showGrantAccess = false" 293 293 > ··· 299 299 <button 300 300 v-else 301 301 type="button" 302 - class="w-full px-3 py-1.5 font-mono text-xs text-fg-muted bg-bg-subtle border border-border rounded transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 302 + class="w-full px-3 py-1.5 font-mono text-xs text-fg-muted bg-bg-subtle border border-border rounded transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70" 303 303 @click="showGrantAccess = true" 304 304 > 305 305 {{ $t('package.access.grant_access') }}
+7 -7
app/components/Package/ClaimPackageModal.vue
··· 174 174 <div class="flex gap-3"> 175 175 <NuxtLink 176 176 :to="`/package/${packageName}`" 177 - class="flex-1 px-4 py-2 font-mono text-sm text-center text-bg bg-fg rounded-md transition-colors duration-200 hover:bg-fg/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 177 + class="flex-1 px-4 py-2 font-mono text-sm text-center text-bg bg-fg rounded-md transition-colors duration-200 hover:bg-fg/90 focus-visible:outline-accent/70" 178 178 @click="close" 179 179 > 180 180 {{ $t('claim.modal.view_package') }} 181 181 </NuxtLink> 182 182 <button 183 183 type="button" 184 - class="flex-1 px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 184 + class="flex-1 px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70" 185 185 @click="close" 186 186 > 187 187 {{ $t('common.close') }} ··· 278 278 <div class="min-w-0"> 279 279 <NuxtLink 280 280 :to="`/package/${pkg.name}`" 281 - class="font-mono text-sm text-fg hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 281 + class="font-mono text-sm text-fg hover:underline focus-visible:outline-accent/70 rounded" 282 282 target="_blank" 283 283 > 284 284 {{ pkg.name }} ··· 328 328 </div> 329 329 <button 330 330 type="button" 331 - class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-colors duration-200 hover:bg-fg/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 331 + class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-colors duration-200 hover:bg-fg/90 focus-visible:outline-accent/70" 332 332 @click="connectorModal.open" 333 333 > 334 334 {{ $t('claim.modal.connect_button') }} ··· 356 356 <button 357 357 type="button" 358 358 :disabled="isPublishing" 359 - class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-colors duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 359 + class="w-full px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-colors duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70" 360 360 @click="handleClaim" 361 361 > 362 362 {{ isPublishing ? $t('claim.modal.publishing') : $t('claim.modal.claim_button') }} ··· 368 368 <button 369 369 v-if="!checkResult.available || !checkResult.valid" 370 370 type="button" 371 - class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 371 + class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70" 372 372 @click="close" 373 373 > 374 374 {{ $t('common.close') }} ··· 385 385 </div> 386 386 <button 387 387 type="button" 388 - class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 388 + class="w-full px-4 py-2 font-mono text-sm text-fg-muted bg-bg-subtle border border-border rounded-md transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70" 389 389 @click="() => checkAvailability()" 390 390 > 391 391 {{ $t('common.retry') }}
+6 -9
app/components/Package/Dependencies.vue
··· 75 75 id="dependencies" 76 76 :title="$t('package.dependencies.title', { count: sortedDependencies.length })" 77 77 > 78 - <ul class="space-y-1 list-none m-0 p-0" :aria-label="$t('package.dependencies.list_label')"> 78 + <ul class="space-y-1 list-none m-0" :aria-label="$t('package.dependencies.list_label')"> 79 79 <li 80 80 v-for="[dep, version] in sortedDependencies.slice(0, depsExpanded ? undefined : 10)" 81 81 :key="dep" ··· 145 145 <button 146 146 v-if="sortedDependencies.length > 10 && !depsExpanded" 147 147 type="button" 148 - class="mt-2 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 148 + class="my-2 ms-1 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 149 149 @click="depsExpanded = true" 150 150 > 151 151 {{ ··· 166 166 }) 167 167 " 168 168 > 169 - <ul 170 - class="space-y-1 list-none m-0 p-0" 171 - :aria-label="$t('package.peer_dependencies.list_label')" 172 - > 169 + <ul class="space-y-1 list-none m-0" :aria-label="$t('package.peer_dependencies.list_label')"> 173 170 <li 174 171 v-for="peer in sortedPeerDependencies.slice(0, peerDepsExpanded ? undefined : 10)" 175 172 :key="peer.name" ··· 208 205 <button 209 206 v-if="sortedPeerDependencies.length > 10 && !peerDepsExpanded" 210 207 type="button" 211 - class="mt-2 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 208 + class="mt-2 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 212 209 @click="peerDepsExpanded = true" 213 210 > 214 211 {{ ··· 230 227 " 231 228 > 232 229 <ul 233 - class="space-y-1 list-none m-0 p-0" 230 + class="space-y-1 list-none m-0" 234 231 :aria-label="$t('package.optional_dependencies.list_label')" 235 232 > 236 233 <li ··· 262 259 <button 263 260 v-if="sortedOptionalDependencies.length > 10 && !optionalDepsExpanded" 264 261 type="button" 265 - class="mt-2 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 262 + class="mt-2 font-mono text-xs text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 266 263 @click="optionalDepsExpanded = true" 267 264 > 268 265 {{
+1 -1
app/components/Package/DeprecatedTree.vue
··· 48 48 <!-- Header --> 49 49 <button 50 50 type="button" 51 - class="w-full flex items-center justify-between gap-3 px-4 py-3 text-start transition-colors duration-200 hover:bg-white/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-fg/50" 51 + class="w-full flex items-center justify-between gap-3 px-4 py-3 text-start transition-colors duration-200 hover:bg-white/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-accent/70" 52 52 :aria-expanded="isExpanded" 53 53 aria-controls="deprecated-tree-details" 54 54 @click="isExpanded = !isExpanded"
+6 -8
app/components/Package/DownloadAnalytics.vue
··· 46 46 47 47 const accentColorValueById = computed<Record<string, string>>(() => { 48 48 const map: Record<string, string> = {} 49 - for (const item of accentColors) { 49 + for (const item of accentColors.value) { 50 50 map[item.id] = item.value 51 51 } 52 52 return map ··· 620 620 {{ $t('package.downloads.granularity') }} 621 621 </label> 622 622 623 - <div 624 - class="flex items-center px-2.5 py-1.75 bg-bg-subtle border border-border rounded-md focus-within:(border-border-hover ring-2 ring-accent/30)" 625 - > 623 + <div class="flex items-center bg-bg-subtle border border-border rounded-md"> 626 624 <select 627 625 id="granularity" 628 626 v-model="selectedGranularity" 629 - class="w-full bg-bg-subtle font-mono text-sm text-fg outline-none appearance-none" 627 + class="w-full px-2.5 py-1.75 bg-bg-subtle font-mono text-sm text-fg outline-none appearance-none focus-visible:outline-accent/70" 630 628 > 631 629 <option value="daily">{{ $t('package.downloads.granularity_daily') }}</option> 632 630 <option value="weekly">{{ $t('package.downloads.granularity_weekly') }}</option> ··· 646 644 {{ $t('package.downloads.start_date') }} 647 645 </label> 648 646 <div 649 - class="flex items-center gap-2 px-2.5 py-1.75 bg-bg-subtle border border-border rounded-md focus-within:(border-border-hover ring-2 ring-accent/30)" 647 + class="flex items-center gap-2 px-2.5 py-1.75 bg-bg-subtle border border-border rounded-md focus-within:(border-border-hover ring-2 ring-accent/70)" 650 648 > 651 649 <span class="i-carbon:calendar w-4 h-4 text-fg-subtle shrink-0" aria-hidden="true" /> 652 650 <input ··· 666 664 {{ $t('package.downloads.end_date') }} 667 665 </label> 668 666 <div 669 - class="flex items-center gap-2 px-2.5 py-1.75 bg-bg-subtle border border-border rounded-md focus-within:(border-border-hover ring-2 ring-accent/30)" 667 + class="flex items-center gap-2 px-2.5 py-1.75 bg-bg-subtle border border-border rounded-md focus-within:(border-border-hover ring-2 ring-accent/70)" 670 668 > 671 669 <span class="i-carbon:calendar w-4 h-4 text-fg-subtle shrink-0" aria-hidden="true" /> 672 670 <input ··· 684 682 v-if="showResetButton" 685 683 type="button" 686 684 aria-label="Reset date range" 687 - class="self-end flex items-center justify-center px-2.5 py-1.75 border border-transparent rounded-md text-fg-subtle hover:text-fg transition-colors hover:border-border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 sm:mb-0" 685 + class="self-end flex items-center justify-center px-2.5 py-1.75 border border-transparent rounded-md text-fg-subtle hover:text-fg transition-colors hover:border-border focus-visible:outline-accent/70 sm:mb-0" 688 686 @click=" 689 687 () => { 690 688 hasUserEditedDates = false
+2 -2
app/components/Package/InstallScripts.vue
··· 31 31 <dt class="font-mono text-xs text-fg-muted">{{ scriptName }}</dt> 32 32 <dd 33 33 tabindex="0" 34 - class="font-mono text-sm text-fg-subtle m-0 truncate focus:whitespace-normal focus:overflow-visible cursor-help rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 34 + class="font-mono text-sm text-fg-subtle m-0 truncate focus:whitespace-normal focus:overflow-visible cursor-help rounded focus-visible:(outline-2 outline-accent outline-offset-2)" 35 35 :title="installScripts.content?.[scriptName]" 36 36 > 37 37 {{ installScripts.content?.[scriptName] || $t('package.install_scripts.script_label') }} ··· 43 43 <div v-if="hasNpxDeps" class="mt-3"> 44 44 <button 45 45 type="button" 46 - class="flex items-center gap-1.5 text-xs text-fg-muted hover:text-fg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 46 + class="flex items-center gap-1.5 text-xs text-fg-muted hover:text-fg transition-colors duration-200 focus-visible:outline-accent/70 rounded" 47 47 :aria-expanded="isExpanded" 48 48 aria-controls="npx-packages-details" 49 49 @click="isExpanded = !isExpanded"
+1 -1
app/components/Package/Keywords.vue
··· 5 5 </script> 6 6 <template> 7 7 <CollapsibleSection v-if="keywords?.length" :title="$t('package.keywords_title')" id="keywords"> 8 - <ul class="flex flex-wrap gap-1.5 list-none m-0 p-0"> 8 + <ul class="flex flex-wrap gap-1.5 list-none m-0 p-1"> 9 9 <li v-for="keyword in keywords.slice(0, 15)" :key="keyword"> 10 10 <TagLink :to="{ name: 'search', query: { q: `keywords:${keyword}` } }"> 11 11 {{ keyword }}
+1 -1
app/components/Package/ListControls.vue
··· 67 67 type="search" 68 68 :placeholder="placeholder ?? $t('package.list.filter_placeholder')" 69 69 v-bind="noCorrect" 70 - class="w-full bg-bg-subtle border border-border rounded-lg ps-10 pe-4 py-2 font-mono text-sm text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:(border-border-hover outline-none)" 70 + class="w-full bg-bg-subtle border border-border rounded-lg ps-10 pe-4 py-2 font-mono text-sm text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-accent focus-visible:(outline-2 outline-accent/70)" 71 71 /> 72 72 </div> 73 73
+1 -1
app/components/Package/ListToolbar.vue
··· 160 160 <select 161 161 id="sort-select" 162 162 :value="currentSort.key" 163 - class="appearance-none bg-bg-subtle border border-border rounded-md ps-3 pe-8 py-1.5 font-mono text-sm text-fg cursor-pointer transition-colors duration-200 hover:border-border-hover focus-visible:ring-2 focus-visible:ring-fg focus-visible:ring-offset-2 focus-visible:ring-offset-bg focus-visible:outline-none" 163 + class="appearance-none bg-bg-subtle border border-border rounded-md ps-3 pe-8 py-1.5 font-mono text-sm text-fg cursor-pointer transition-colors duration-200 hover:border-border-hover" 164 164 @change="handleSortKeyChange" 165 165 > 166 166 <option
+10 -7
app/components/Package/Maintainers.vue
··· 173 173 id="maintainers" 174 174 :title="$t('package.maintainers.title')" 175 175 > 176 - <ul class="space-y-2 list-none m-0 p-0" :aria-label="$t('package.maintainers.list_label')"> 176 + <ul 177 + class="space-y-2 list-none m-0 p-0 my-1 px-1" 178 + :aria-label="$t('package.maintainers.list_label')" 179 + > 177 180 <li 178 181 v-for="maintainer in visibleMaintainers" 179 182 :key="maintainer.name ?? maintainer.email" ··· 214 217 <button 215 218 v-if="canManageOwners && maintainer.name && maintainer.name !== npmUser" 216 219 type="button" 217 - class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 shrink-0 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 220 + class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 shrink-0 rounded focus-visible:outline-accent/70" 218 221 :aria-label=" 219 222 $t('package.maintainers.remove_owner', { 220 223 name: maintainer.name, ··· 231 234 <button 232 235 v-if="!canManageOwners && hiddenMaintainersCount > 0" 233 236 type="button" 234 - class="mt-2 text-xs text-fg-muted hover:text-fg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 237 + class="mt-2 text-xs text-fg-muted hover:text-fg transition-colors duration-200 focus-visible:outline-accent/70 rounded" 235 238 @click="showAllMaintainers = !showAllMaintainers" 236 239 > 237 240 {{ ··· 257 260 name="add-owner-username" 258 261 :placeholder="$t('package.maintainers.username_placeholder')" 259 262 v-bind="noCorrect" 260 - class="flex-1 px-2 py-1 font-mono text-sm bg-bg-subtle border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 263 + class="flex-1 px-2 py-1 font-mono text-sm bg-bg-subtle border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-accent/70" 261 264 /> 262 265 <button 263 266 type="submit" 264 267 :disabled="!newOwnerUsername.trim() || isAdding" 265 - class="px-2 py-1 font-mono text-xs text-bg bg-fg rounded transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 268 + class="px-2 py-1 font-mono text-xs text-bg bg-fg rounded transition-all duration-200 hover:bg-fg/90 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-accent/70" 266 269 > 267 270 {{ isAdding ? '…' : $t('package.maintainers.add_button') }} 268 271 </button> 269 272 <button 270 273 type="button" 271 - class="p-1 text-fg-subtle hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 274 + class="p-1 text-fg-subtle hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70" 272 275 :aria-label="$t('package.maintainers.cancel_add')" 273 276 @click="showAddOwner = false" 274 277 > ··· 279 282 <button 280 283 v-else 281 284 type="button" 282 - class="w-full px-3 py-1.5 font-mono text-xs text-fg-muted bg-bg-subtle border border-border rounded transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 285 + class="w-full px-3 py-1.5 font-mono text-xs text-fg-muted bg-bg-subtle border border-border rounded transition-colors duration-200 hover:text-fg hover:border-border-hover focus-visible:outline-accent/70" 283 286 @click="showAddOwner = true" 284 287 > 285 288 {{ $t('package.maintainers.add_owner') }}
+1 -1
app/components/Package/ManagerSelect.vue
··· 88 88 <button 89 89 ref="triggerRef" 90 90 type="button" 91 - class="flex items-center gap-1.5 px-2 py-2 font-mono text-xs text-fg-muted bg-bg-subtle border border-border-subtle border-solid rounded-md transition-colors duration-150 hover:(text-fg border-border-hover) active:scale-95 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 hover:text-fg" 91 + class="flex items-center gap-1.5 px-2 py-2 font-mono text-xs text-fg-muted bg-bg-subtle border border-border-subtle border-solid rounded-md transition-colors duration-150 hover:(text-fg border-border-hover) active:scale-95 focus:border-border-hover focus-visible:outline-accent/70 hover:text-fg" 92 92 :aria-expanded="isOpen" 93 93 aria-haspopup="listbox" 94 94 :aria-label="$t('package.get_started.pm_label')"
+4 -4
app/components/Package/MetricsBadges.vue
··· 60 60 :is="typesHref ? NuxtLink : 'span'" 61 61 :to="typesHref" 62 62 :tabindex="!typesHref ? 0 : undefined" 63 - class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded transition-colors duration-200" 63 + class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded transition-colors duration-200 focus-visible:(outline-2 outline-accent)" 64 64 :class="[ 65 65 hasTypes 66 66 ? 'text-fg-muted bg-bg-muted border border-border' 67 67 : 'text-fg-subtle bg-bg-subtle border border-border-subtle', 68 68 typesHref 69 - ? 'hover:text-fg hover:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50' 69 + ? 'hover:text-fg hover:border-border-hover focus-visible:outline-accent/70' 70 70 : '', 71 71 ]" 72 72 > ··· 85 85 <TooltipApp :text="hasEsm ? $t('package.metrics.esm') : $t('package.metrics.no_esm')"> 86 86 <span 87 87 tabindex="0" 88 - class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded transition-colors duration-200" 88 + class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs rounded transition-colors duration-200 focus-visible:(outline-2 outline-accent)" 89 89 :class=" 90 90 hasEsm 91 91 ? 'text-fg-muted bg-bg-muted border border-border' ··· 107 107 <TooltipApp :text="$t('package.metrics.cjs')"> 108 108 <span 109 109 tabindex="0" 110 - class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs text-fg-muted bg-bg-muted border border-border rounded transition-colors duration-200" 110 + class="inline-flex items-center gap-1 px-1.5 py-0.5 font-mono text-xs text-fg-muted bg-bg-muted border border-border rounded transition-colors duration-200 focus-visible:(outline-2 outline-accent)" 111 111 > 112 112 <span class="i-carbon-checkmark w-3 h-3" aria-hidden="true" /> 113 113 CJS
+4 -4
app/components/Package/Playgrounds.vue
··· 109 109 </script> 110 110 111 111 <template> 112 - <section v-if="links.length > 0"> 112 + <section v-if="links.length > 0" class="px-1"> 113 113 <h2 id="playgrounds-heading" class="text-xs text-fg-subtle uppercase tracking-wider mb-3"> 114 114 {{ $t('package.playgrounds.title') }} 115 115 </h2> ··· 121 121 :href="firstLink.url" 122 122 target="_blank" 123 123 rel="noopener noreferrer" 124 - class="w-full flex items-center gap-2 px-3 py-2 text-sm font-mono bg-bg-muted border border-border rounded-md hover:border-border-hover hover:bg-bg-elevated focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-hover transition-colors duration-200" 124 + class="w-full flex items-center gap-2 px-3 py-2 text-sm font-mono bg-bg-muted border border-border rounded-md hover:border-border-hover hover:bg-bg-elevated focus-visible:outline-accent/70 transition-colors duration-200" 125 125 > 126 126 <span 127 127 :class="[getIcon(firstLink.provider), getColor(firstLink.provider), 'w-4 h-4 shrink-0']" ··· 137 137 type="button" 138 138 aria-haspopup="true" 139 139 :aria-expanded="isOpen" 140 - class="w-full flex items-center justify-between gap-2 px-3 py-2 text-sm font-mono bg-bg-muted border border-border rounded-md hover:border-border-hover hover:bg-bg-elevated focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-hover transition-colors duration-200" 140 + class="w-full flex items-center justify-between gap-2 px-3 py-2 text-sm font-mono bg-bg-muted border border-border rounded-md hover:border-border-hover hover:bg-bg-elevated focus-visible:outline-accent/70 transition-colors duration-200" 141 141 @click="isOpen = !isOpen" 142 142 @keydown="handleKeydown" 143 143 > ··· 176 176 target="_blank" 177 177 rel="noopener noreferrer" 178 178 role="menuitem" 179 - class="flex items-center gap-2 px-3 py-2 text-sm font-mono text-fg-muted hover:text-fg hover:bg-bg-muted focus-visible:outline-none focus-visible:text-fg focus-visible:bg-bg-muted transition-colors duration-150" 179 + class="flex items-center gap-2 px-3 py-2 text-sm font-mono text-fg-muted hover:text-fg hover:bg-bg-muted focus-visible:outline-accent/70 focus-visible:text-fg focus-visible:bg-bg-muted transition-colors duration-150" 180 180 @click="closeDropdown" 181 181 > 182 182 <span
+1 -1
app/components/Package/SkillsCard.vue
··· 14 14 <CollapsibleSection v-if="skills.length" :title="$t('package.skills.title')" id="skills"> 15 15 <button 16 16 type="button" 17 - class="w-full flex items-center gap-2 px-3 py-2 text-sm font-mono bg-bg-muted border border-border rounded-md hover:border-border-hover hover:bg-bg-elevated focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-hover transition-colors duration-200" 17 + class="w-full flex items-center gap-2 px-3 py-2 text-sm font-mono bg-bg-muted border border-border rounded-md hover:border-border-hover hover:bg-bg-elevated focus-visible:outline-accent/70 transition-colors duration-200" 18 18 @click="skillsModal.open()" 19 19 > 20 20 <span class="i-custom:agent-skills w-4 h-4 shrink-0 text-fg-muted" aria-hidden="true" />
+4 -4
app/components/Package/SkillsModal.vue
··· 62 62 :aria-selected="selectedMethod === 'skills-npm'" 63 63 :tabindex="selectedMethod === 'skills-npm' ? 0 : -1" 64 64 type="button" 65 - class="px-2 py-1 font-mono text-xs rounded transition-colors duration-150 border border-solid focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 65 + class="px-2 py-1 font-mono text-xs rounded transition-colors duration-150 border border-solid focus-visible:outline-accent/70" 66 66 :class=" 67 67 selectedMethod === 'skills-npm' 68 68 ? 'bg-bg border-border shadow-sm text-fg' ··· 77 77 :aria-selected="selectedMethod === 'skills-cli'" 78 78 :tabindex="selectedMethod === 'skills-cli' ? 0 : -1" 79 79 type="button" 80 - class="px-2 py-1 font-mono text-xs rounded transition-colors duration-150 border border-solid focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 80 + class="px-2 py-1 font-mono text-xs rounded transition-colors duration-150 border border-solid focus-visible:outline-accent/70" 81 81 :class=" 82 82 selectedMethod === 'skills-cli' 83 83 ? 'bg-bg border-border shadow-sm text-fg' ··· 133 133 </code> 134 134 <button 135 135 type="button" 136 - class="absolute top-0 inset-ie-0 px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/cmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 136 + class="absolute top-0 inset-ie-0 px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/cmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-accent/70" 137 137 :aria-label="$t('package.get_started.copy_command')" 138 138 @click.stop="copyCommand" 139 139 > ··· 154 154 <li v-for="skill in skills" :key="skill.dirName"> 155 155 <button 156 156 type="button" 157 - class="w-full flex items-center gap-2 py-1.5 text-start rounded transition-colors hover:bg-bg-subtle focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 157 + class="w-full flex items-center gap-2 py-1.5 text-start rounded transition-colors hover:bg-bg-subtle focus-visible:outline-accent/70" 158 158 :aria-expanded="expandedSkills.has(skill.dirName)" 159 159 @click="toggleSkill(skill.dirName)" 160 160 >
+7 -7
app/components/Package/Versions.vue
··· 311 311 :href="`https://majors.nullvoxpopuli.com/q?packages=${packageName}`" 312 312 target="_blank" 313 313 rel="noopener noreferrer" 314 - class="text-fg-subtle hover:text-fg transition-colors duration-200 inline-flex items-center justify-center min-w-6 min-h-6 -m-1 p-1" 314 + class="text-fg-subtle hover:text-fg transition-colors duration-200 inline-flex items-center justify-center min-w-6 min-h-6 -m-1 p-1 focus-visible:outline-accent/70 rounded" 315 315 :title="$t('package.downloads.community_distribution')" 316 316 > 317 317 <span class="i-carbon:load-balancer-network w-3.5 h-3.5" aria-hidden="true" /> ··· 322 322 <!-- Dist-tag rows (limited to MAX_VISIBLE_TAGS) --> 323 323 <div v-for="row in visibleTagRows" :key="row.id"> 324 324 <div 325 - class="flex items-center gap-2 pe-2" 325 + class="flex items-center gap-2 pe-2 px-1" 326 326 :class="row.tag === 'latest' ? 'bg-bg-subtle rounded-lg' : ''" 327 327 > 328 328 <!-- Expand button (only if there are more versions to show) --> 329 329 <button 330 330 v-if="getTagVersions(row.tag).length > 1 || !hasLoadedAll" 331 331 type="button" 332 - class="w-4 h-4 flex items-center justify-center text-fg-subtle hover:text-fg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg-muted focus-visible:ring-offset-1 focus-visible:ring-offset-bg rounded-sm" 332 + class="w-4 h-4 flex items-center justify-center text-fg-subtle hover:text-fg transition-colors rounded-sm" 333 333 :aria-expanded="expandedTags.has(row.tag)" 334 334 :aria-label=" 335 335 expandedTags.has(row.tag) ··· 362 362 <div> 363 363 <NuxtLink 364 364 :to="versionRoute(row.primaryVersion.version)" 365 - class="block font-mono text-sm transition-colors duration-200 truncate inline-flex items-center gap-1" 365 + class="block font-mono text-sm transition-colors duration-200 truncate inline-flex items-center gap-1 focus-visible:outline-none focus-visible:text-accent" 366 366 :class=" 367 367 row.primaryVersion.deprecated 368 368 ? 'text-red-400 hover:text-red-300' ··· 477 477 </div> 478 478 479 479 <!-- Other versions section --> 480 - <div class="pt-1"> 480 + <div class="p-1"> 481 481 <button 482 482 type="button" 483 - class="flex items-center gap-2 text-start focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg-muted focus-visible:ring-offset-1 focus-visible:ring-offset-bg rounded-sm" 483 + class="flex items-center gap-2 text-start rounded-sm" 484 484 :aria-expanded="otherVersionsExpanded" 485 485 :aria-label=" 486 486 otherVersionsExpanded ··· 579 579 <div class="flex items-center gap-2 min-w-0"> 580 580 <button 581 581 type="button" 582 - class="w-4 h-4 flex items-center justify-center text-fg-subtle hover:text-fg transition-colors shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg-muted focus-visible:ring-offset-1 focus-visible:ring-offset-bg rounded-sm" 582 + class="w-4 h-4 flex items-center justify-center text-fg-subtle hover:text-fg transition-colors shrink-0 focus-visible:outline-accent/70 rounded-sm" 583 583 :aria-expanded="expandedMajorGroups.has(group.groupKey)" 584 584 :aria-label=" 585 585 expandedMajorGroups.has(group.groupKey)
+1 -1
app/components/Package/VulnerabilityTree.vue
··· 67 67 <!-- Header --> 68 68 <button 69 69 type="button" 70 - class="w-full flex items-center justify-between gap-3 px-4 py-3 text-start transition-colors duration-200 hover:bg-white/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-fg/50" 70 + class="w-full flex items-center justify-between gap-3 px-4 py-3 text-start transition-colors duration-200 hover:bg-white/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-accent/70" 71 71 :aria-expanded="isExpanded" 72 72 aria-controls="vuln-tree-details" 73 73 @click="isExpanded = !isExpanded"
+2 -2
app/components/Package/WeeklyDownloadStats.vue
··· 64 64 65 65 const accentColorValueById = computed<Record<string, string>>(() => { 66 66 const map: Record<string, string> = {} 67 - for (const item of accentColors) { 67 + for (const item of accentColors.value) { 68 68 map[item.id] = item.value 69 69 } 70 70 return map ··· 202 202 <button 203 203 type="button" 204 204 @click="openChartModal" 205 - class="link-subtle font-mono text-sm inline-flex items-center gap-1.5 ms-auto shrink-0 self-center focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 205 + class="text-fg-subtle hover:text-fg transition-colors duration-200 inline-flex items-center justify-center min-w-6 min-h-6 -m-1 p-1 focus-visible:outline-accent/70 rounded" 206 206 :title="$t('package.downloads.analyze')" 207 207 > 208 208 <span class="i-carbon:data-analytics w-4 h-4" aria-hidden="true" />
+1 -1
app/components/PaginationControls.vue
··· 153 153 <select 154 154 id="page-size" 155 155 :value="pageSize" 156 - class="appearance-none bg-bg-subtle border border-border rounded-md ps-3 pe-8 py-1 font-mono text-sm text-fg cursor-pointer transition-colors duration-200 hover:border-border-hover focus-visible:ring-2 focus-visible:ring-fg focus-visible:ring-offset-2 focus-visible:ring-offset-bg focus-visible:outline-none" 156 + class="appearance-none bg-bg-subtle border border-border rounded-md ps-3 pe-8 py-1 font-mono text-sm text-fg cursor-pointer transition-colors duration-200 hover:border-border-hover" 157 157 @change="handlePageSizeChange" 158 158 > 159 159 <option v-for="size in PAGE_SIZE_OPTIONS" :key="size" :value="size">
+1 -1
app/components/Readme.vue
··· 60 60 61 61 <template> 62 62 <article 63 - class="readme prose prose-invert max-w-[70ch] lg:max-w-none" 63 + class="readme prose prose-invert max-w-[70ch] lg:max-w-none px-1" 64 64 v-html="html" 65 65 @click="handleClick" 66 66 />
+1 -1
app/components/ReadmeTocDropdown.vue
··· 148 148 <button 149 149 ref="triggerRef" 150 150 type="button" 151 - class="flex items-center gap-1.5 px-2 py-2 font-mono text-xs text-fg-muted bg-bg-subtle border border-border-subtle border-solid rounded-md transition-colors duration-150 hover:(text-fg border-border-hover) active:scale-95 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 hover:text-fg" 151 + class="flex items-center gap-1.5 px-2 py-2 font-mono text-xs text-fg-muted bg-bg-subtle border border-border-subtle border-solid rounded-md transition-colors duration-150 hover:(text-fg border-border-hover) active:scale-95 focus:border-border-hover focus-visible:outline-accent/70 hover:text-fg" 152 152 :aria-expanded="isOpen" 153 153 aria-haspopup="listbox" 154 154 :aria-label="$t('package.readme.toc_title')"
+1 -1
app/components/Settings/Toggle.client.vue
··· 22 22 </span> 23 23 <span 24 24 class="relative inline-flex h-6 w-11 shrink-0 items-center rounded-full border-2 transition-colors duration-200 ease-in-out motion-reduce:transition-none cursor-pointer" 25 - :class="checked ? 'bg-accent border-transparent shadow-sm' : 'bg-bg border border-border'" 25 + :class="checked ? 'bg-accent border-transparent shadow-sm' : 'bg-bg border border-border/50'" 26 26 aria-hidden="true" 27 27 > 28 28 <span
+4 -4
app/components/Settings/TranslationHelper.vue
··· 68 68 </h4> 69 69 <button 70 70 type="button" 71 - class="text-xs text-accent hover:underline rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50" 71 + class="text-xs text-accent hover:underline rounded focus-visible:outline-accent/70" 72 72 @click="copyMissingKeysTemplate" 73 73 > 74 74 {{ copied ? $t('common.copied') : $t('i18n.copy_keys') }} ··· 84 84 <button 85 85 v-if="hasMoreKeys" 86 86 type="button" 87 - class="text-xs text-fg-muted hover:text-fg rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 87 + class="text-xs text-fg-muted hover:text-fg rounded focus-visible:outline-accent/70" 88 88 @click="showAll = true" 89 89 > 90 90 {{ $t('i18n.show_more_keys', { count: remainingCount }) }} ··· 102 102 :href="status.githubEditUrl" 103 103 target="_blank" 104 104 rel="noopener noreferrer" 105 - class="inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs bg-bg hover:bg-bg-subtle border border-border rounded-md transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 105 + class="inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs bg-bg hover:bg-bg-subtle border border-border rounded-md transition-colors focus-visible:outline-accent/70" 106 106 > 107 107 <span class="i-carbon-edit w-3.5 h-3.5" aria-hidden="true" /> 108 108 {{ $t('i18n.edit_on_github') }} ··· 112 112 :href="contributionGuideUrl" 113 113 target="_blank" 114 114 rel="noopener noreferrer" 115 - class="inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs text-fg-muted hover:text-fg rounded transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 115 + class="inline-flex items-center gap-1.5 px-2.5 py-1.5 text-xs text-fg-muted hover:text-fg rounded transition-colors focus-visible:outline-accent/70" 116 116 > 117 117 <span class="i-carbon-document w-3.5 h-3.5" aria-hidden="true" /> 118 118 {{ $t('i18n.view_guide') }}
+1 -1
app/components/Terminal/Execute.vue
··· 70 70 > 71 71 <button 72 72 type="button" 73 - class="px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/executecmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 73 + class="px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/executecmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-accent/70" 74 74 :aria-label="$t('package.get_started.copy_command')" 75 75 @click.stop="copyExecuteCommand" 76 76 >
+6 -5
app/components/Terminal/Install.vue
··· 123 123 > 124 124 <button 125 125 type="button" 126 - class="px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/installcmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 126 + class="px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/installcmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-accent/70" 127 127 :aria-label="$t('package.get_started.copy_command')" 128 128 @click.stop="copyInstallCommand" 129 129 > ··· 150 150 > 151 151 <NuxtLink 152 152 :to="`/package/${typesPackageName}`" 153 - class="text-fg-subtle hover:text-fg-muted text-xs transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 153 + class="text-fg-subtle hover:text-fg-muted text-xs transition-colors focus-visible:outline-accent/70 rounded" 154 154 :title="$t('package.get_started.view_types', { package: typesPackageName })" 155 155 > 156 156 <span class="i-carbon:arrow-right rtl-flip w-3 h-3 align-middle" aria-hidden="true" /> ··· 185 185 > 186 186 <button 187 187 type="button" 188 - class="px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/runcmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 188 + class="px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/runcmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-accent/70" 189 189 @click.stop="copyRunCommand(executableInfo?.primaryCommand)" 190 190 > 191 191 {{ runCopied ? $t('common.copied') : $t('common.copy') }} ··· 202 202 > 203 203 <NuxtLink 204 204 :to="`/package/${createPackageInfo.packageName}`" 205 - class="text-fg-muted hover:text-fg text-xs transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 205 + class="text-fg-muted hover:text-fg text-xs transition-colors focus-visible:outline-accent/70 rounded" 206 + :title="$t('package.create.view', { packageName: createPackageInfo.packageName })" 206 207 > 207 208 <TooltipApp 208 209 :text="$t('package.create.view', { packageName: createPackageInfo.packageName })" ··· 232 233 > 233 234 <button 234 235 type="button" 235 - class="px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/createcmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 236 + class="px-2 py-0.5 font-mono text-xs text-fg-muted bg-bg-subtle/80 border border-border rounded transition-colors duration-200 opacity-0 group-hover/createcmd:opacity-100 hover:(text-fg border-border-hover) active:scale-95 focus-visible:opacity-100 focus-visible:outline-accent/70" 236 237 :aria-label="$t('package.create.copy_command')" 237 238 @click.stop="copyCreateCommand" 238 239 >
+1 -1
app/components/UserCombobox.vue
··· 154 154 :aria-activedescendant=" 155 155 highlightedIndex >= 0 ? `${listboxId}-option-${highlightedIndex}` : undefined 156 156 " 157 - class="w-full px-2 py-1 font-mono text-sm bg-bg-subtle border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 disabled:opacity-50 disabled:cursor-not-allowed" 157 + class="w-full px-2 py-1 font-mono text-sm bg-bg-subtle border border-border rounded text-fg placeholder:text-fg-subtle transition-colors duration-200 focus:border-border-hover focus-visible:outline-accent/70 disabled:opacity-50 disabled:cursor-not-allowed" 158 158 @input="handleInput" 159 159 @focus="handleFocus" 160 160 @blur="handleBlur"
+25 -8
app/composables/useSettings.ts
··· 6 6 7 7 type BackgroundThemeId = keyof typeof BACKGROUND_THEMES 8 8 9 - type AccentColorId = keyof typeof ACCENT_COLORS 9 + type AccentColorId = keyof typeof ACCENT_COLORS.light 10 10 11 11 /** 12 12 * Application settings stored in localStorage ··· 76 76 */ 77 77 export function useAccentColor() { 78 78 const { settings } = useSettings() 79 + const colorMode = useColorMode() 79 80 80 - const accentColors = Object.entries(ACCENT_COLORS).map(([id, value]) => ({ 81 - id: id as AccentColorId, 82 - name: id, 83 - value, 84 - })) 81 + const accentColors = computed(() => { 82 + const isDark = colorMode.value === 'dark' 83 + const colors = isDark ? ACCENT_COLORS.dark : ACCENT_COLORS.light 84 + 85 + return Object.entries(colors).map(([id, value]) => ({ 86 + id: id as AccentColorId, 87 + name: id, 88 + value, 89 + })) 90 + }) 85 91 86 92 function setAccentColor(id: AccentColorId | null) { 87 - const color = id ? ACCENT_COLORS[id] : null 88 - if (color) { 93 + if (id) { 94 + const isDark = colorMode.value === 'dark' 95 + const color = isDark ? ACCENT_COLORS.dark[id] : ACCENT_COLORS.light[id] 89 96 document.documentElement.style.setProperty('--accent-color', color) 90 97 } else { 91 98 document.documentElement.style.removeProperty('--accent-color') 92 99 } 93 100 settings.value.accentColorId = id 94 101 } 102 + 103 + // Update accent color when color mode changes 104 + watch( 105 + () => colorMode.value, 106 + () => { 107 + if (settings.value.accentColorId) { 108 + setAccentColor(settings.value.accentColorId) 109 + } 110 + }, 111 + ) 95 112 96 113 return { 97 114 accentColors,
+1 -1
app/pages/about.vue
··· 216 216 <footer class="mt-16 pt-8 border-t border-border"> 217 217 <NuxtLink 218 218 to="/" 219 - class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-[color] duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 219 + class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-[color] duration-200 rounded focus-visible:outline-accent/70" 220 220 > 221 221 <span class="i-carbon:arrow-left rtl-flip w-4 h-4" aria-hidden="true" /> 222 222 {{ $t('about.back_home') }}
+2 -2
app/pages/compare.vue
··· 85 85 </h2> 86 86 <button 87 87 type="button" 88 - class="text-[10px] transition-colors focus-visible:outline-none focus-visible:underline" 88 + class="text-[10px] transition-colors focus-visible:outline-none focus-visible:underline focus-visible:underline-accent" 89 89 :class="isAllSelected ? 'text-fg-muted' : 'text-fg-muted/60 hover:text-fg-muted'" 90 90 :disabled="isAllSelected" 91 91 :aria-label="$t('compare.facets.select_all')" ··· 96 96 <span class="text-[10px] text-fg-muted/40" aria-hidden="true">/</span> 97 97 <button 98 98 type="button" 99 - class="text-[10px] transition-colors focus-visible:outline-none focus-visible:underline" 99 + class="text-[10px] transition-colors focus-visible:outline-none focus-visible:underline focus-visible:underline-accent" 100 100 :class="isNoneSelected ? 'text-fg-muted' : 'text-fg-muted/60 hover:text-fg-muted'" 101 101 :disabled="isNoneSelected" 102 102 :aria-label="$t('compare.facets.deselect_all')"
+3 -10
app/pages/index.vue
··· 59 59 dir="ltr" 60 60 class="flex items-center justify-center gap-2 header-logo font-mono text-5xl sm:text-7xl md:text-8xl font-medium tracking-tight mb-4 motion-safe:animate-fade-in motion-safe:animate-fill-both" 61 61 > 62 - <img 63 - aria-hidden="true" 64 - :alt="$t('alt_logo')" 65 - src="/logo.svg" 66 - width="48" 67 - height="48" 68 - class="w-12 h-12 sm:w-20 sm:h-20 md:w-24 md:h-24 rounded-2xl sm:rounded-3xl" 69 - /> 62 + <AppLogo class="w-12 h-12 sm:w-20 sm:h-20 md:w-24 md:h-24 rounded-2xl sm:rounded-3xl" /> 70 63 <span class="pb-4">npmx</span> 71 64 </h1> 72 65 ··· 107 100 autofocus 108 101 :placeholder="$t('search.placeholder')" 109 102 v-bind="noCorrect" 110 - class="w-full bg-bg-subtle border border-border rounded-lg ps-8 pe-24 py-4 font-mono text-base text-fg placeholder:text-fg-subtle transition-border-color duration-300 focus:border-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/50" 103 + class="w-full bg-bg-subtle border border-border rounded-lg ps-8 pe-24 py-4 font-mono text-base text-fg placeholder:text-fg-subtle transition-border-color duration-300 focus:border-accent focus-visible:(outline-2 outline-accent/70)" 111 104 @input="handleInput" 112 105 /> 113 106 114 107 <button 115 108 type="submit" 116 - class="absolute inset-ie-2 px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-[background-color,transform] duration-200 hover:bg-fg/90 active:scale-95 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 109 + class="absolute inset-ie-2 px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-[background-color,transform] duration-200 hover:bg-fg/90 active:scale-95 focus-visible:outline-accent/70" 117 110 > 118 111 <span class="i-carbon:search align-middle w-4 h-4" aria-hidden="true"></span> 119 112 {{ $t('search.button') }}
+1 -1
app/pages/package-code/[...path].vue
··· 407 407 v-for="mode in markdownViewModes" 408 408 :key="mode.key" 409 409 role="tab" 410 - class="px-2 py-1.5 font-mono text-xs rounded transition-colors duration-150 border border-solid focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 inline-flex items-center gap-1.5" 410 + class="px-2 py-1.5 font-mono text-xs rounded transition-colors duration-150 border border-solid focus-visible:outline-accent/70 inline-flex items-center gap-1.5" 411 411 :class=" 412 412 markdownViewMode === mode.key 413 413 ? 'bg-bg shadow text-fg border-border'
+24 -19
app/pages/package/[...package].vue
··· 488 488 </h1> 489 489 490 490 <!-- Floating copy button --> 491 - <TooltipAnnounce :text="$t('common.copied')" :isVisible="copiedPkgName"> 492 - <button 493 - type="button" 494 - @click="copyPkgName()" 495 - class="copy-button absolute z-20 left-0 top-full inline-flex items-center gap-1 px-2 py-1 rounded border text-xs font-mono whitespace-nowrap text-fg-muted bg-bg border-border 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 hover:text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/40" 496 - :aria-label="$t('package.copy_name')" 497 - > 498 - <span class="i-carbon:copy w-3.5 h-3.5" aria-hidden="true" /> 499 - {{ $t('package.copy_name') }} 500 - </button> 501 - </TooltipAnnounce> 491 + <button 492 + type="button" 493 + @click="copyPkgName()" 494 + class="copy-button absolute z-20 left-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" 495 + :class=" 496 + copiedPkgName ? 'text-accent bg-accent/10' : 'text-fg-muted bg-bg border-border' 497 + " 498 + :aria-label="copiedPkgName ? $t('common.copied') : $t('package.copy_name')" 499 + > 500 + <span 501 + :class="copiedPkgName ? 'i-carbon:checkmark' : 'i-carbon:copy'" 502 + class="w-3.5 h-3.5" 503 + aria-hidden="true" 504 + /> 505 + {{ copiedPkgName ? $t('common.copied') : $t('package.copy_name') }} 506 + </button> 502 507 </div> 503 508 <span 504 509 v-if="resolvedVersion" ··· 582 587 <NuxtLink 583 588 v-if="docsLink" 584 589 :to="docsLink" 585 - class="px-2 py-1.5 font-mono text-xs rounded transition-colors duration-150 border border-transparent text-fg-subtle hover:text-fg hover:bg-bg hover:shadow hover:border-border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 inline-flex items-center gap-1.5" 590 + class="px-2 py-1.5 font-mono text-xs rounded transition-colors duration-150 border border-transparent text-fg-subtle hover:text-fg hover:bg-bg hover:shadow hover:border-border inline-flex items-center gap-1.5" 586 591 aria-keyshortcuts="d" 587 592 > 588 593 <span class="i-carbon:document w-3 h-3" aria-hidden="true" /> ··· 596 601 </NuxtLink> 597 602 <NuxtLink 598 603 :to="`/package-code/${pkg.name}/v/${resolvedVersion}`" 599 - class="px-2 py-1.5 font-mono text-xs rounded transition-colors duration-150 border border-transparent text-fg-subtle hover:text-fg hover:bg-bg hover:shadow hover:border-border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 inline-flex items-center gap-1.5" 604 + class="px-2 py-1.5 font-mono text-xs rounded transition-colors duration-150 border border-transparent text-fg-subtle hover:text-fg hover:bg-bg hover:shadow hover:border-border inline-flex items-center gap-1.5" 600 605 aria-keyshortcuts="." 601 606 > 602 607 <span class="i-carbon:code w-3 h-3" aria-hidden="true" /> ··· 610 615 </NuxtLink> 611 616 <NuxtLink 612 617 :to="{ path: '/compare', query: { packages: pkg.name } }" 613 - class="px-2 py-1.5 font-mono text-xs rounded transition-colors duration-150 border border-transparent text-fg-subtle hover:text-fg hover:bg-bg hover:shadow hover:border-border focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 inline-flex items-center gap-1.5" 618 + class="px-2 py-1.5 font-mono text-xs rounded transition-colors duration-150 border border-transparent text-fg-subtle hover:text-fg hover:bg-bg hover:shadow hover:border-border inline-flex items-center gap-1.5" 614 619 aria-keyshortcuts="c" 615 620 > 616 621 <span class="i-carbon:compare w-3 h-3" aria-hidden="true" /> ··· 833 838 :href="`https://npmgraph.js.org/?q=${pkg.name}`" 834 839 target="_blank" 835 840 rel="noopener noreferrer" 836 - class="text-fg-subtle hover:text-fg transition-colors duration-200 inline-flex items-center justify-center min-w-6 min-h-6 -m-1 p-1" 841 + class="text-fg-subtle hover:text-fg transition-colors duration-200 inline-flex items-center justify-center min-w-6 min-h-6 -m-1 p-1 focus-visible:outline-accent/70 rounded" 837 842 :title="$t('package.stats.view_dependency_graph')" 838 843 > 839 844 <span class="i-carbon:network-3 w-3.5 h-3.5" aria-hidden="true" /> ··· 845 850 :href="`https://node-modules.dev/grid/depth#install=${pkg.name}${resolvedVersion ? `@${resolvedVersion}` : ''}`" 846 851 target="_blank" 847 852 rel="noopener noreferrer" 848 - class="text-fg-subtle hover:text-fg transition-colors duration-200 inline-flex items-center justify-center min-w-6 min-h-6 -m-1 p-1" 853 + class="text-fg-subtle hover:text-fg transition-colors duration-200 inline-flex items-center justify-center min-w-6 min-h-6 -m-1 p-1 focus-visible:outline-accent/70 rounded" 849 854 :title="$t('package.stats.inspect_dependency_tree')" 850 855 > 851 856 <span class="i-lucide-view w-3.5 h-3.5" aria-hidden="true" /> ··· 1036 1041 1037 1042 <!-- README --> 1038 1043 <section id="readme" class="area-readme min-w-0 scroll-mt-20"> 1039 - <div class="flex flex-wrap items-center justify-between mb-3"> 1044 + <div class="flex flex-wrap items-center justify-between mb-4 px-1"> 1040 1045 <h2 id="readme-heading" class="group text-xs text-fg-subtle uppercase tracking-wider"> 1041 1046 <a 1042 1047 href="#readme" 1043 - class="inline-flex items-center gap-1.5 text-fg-subtle hover:text-fg-muted transition-colors duration-200 no-underline" 1048 + class="inline-flex py-4 px-2 items-center gap-1.5 text-fg-subtle hover:text-fg-muted transition-colors duration-200 no-underline mt-1" 1044 1049 > 1045 1050 {{ $t('package.readme.title') }} 1046 1051 <span ··· 1076 1081 1077 1082 <div class="area-sidebar"> 1078 1083 <!-- Sidebar --> 1079 - <div class="sticky top-34 space-y-6 sm:space-y-8 min-w-0 overflow-hidden xl:(top-22 pt-2)"> 1084 + <div class="sticky top-34 space-y-6 sm:space-y-8 min-w-0 overflow-hidden xl:(top-22) pt-1"> 1080 1085 <!-- Maintainers (with admin actions when connected) --> 1081 1086 <PackageMaintainers :package-name="pkg.name" :maintainers="pkg.maintainers" /> 1082 1087
+2 -2
app/pages/search.vue
··· 640 640 </div> 641 641 <button 642 642 type="button" 643 - class="shrink-0 px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md motion-safe:transition-colors motion-safe:duration-200 hover:bg-fg/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 643 + class="shrink-0 px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md motion-safe:transition-colors motion-safe:duration-200 hover:bg-fg/90 focus-visible:outline-accent/70" 644 644 @click="claimPackageModalRef?.open()" 645 645 > 646 646 {{ $t('search.claim_button', { name: query }) }} ··· 736 736 <p class="text-sm text-fg-muted mb-3">{{ $t('search.want_to_claim') }}</p> 737 737 <button 738 738 type="button" 739 - class="px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-colors duration-200 hover:bg-fg/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50" 739 + class="px-4 py-2 font-mono text-sm text-bg bg-fg rounded-md transition-colors duration-200 hover:bg-fg/90 focus-visible:outline-accent/70" 740 740 @click="claimPackageModalRef?.open()" 741 741 > 742 742 {{ $t('search.claim_button', { name: query }) }}
+4 -4
app/pages/settings.vue
··· 46 46 </h1> 47 47 <button 48 48 type="button" 49 - class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 shrink-0" 49 + class="inline-flex items-center gap-2 font-mono text-sm text-fg-muted hover:text-fg transition-colors duration-200 rounded focus-visible:outline-accent/70 shrink-0" 50 50 @click="router.back()" 51 51 > 52 52 <span class="i-carbon:arrow-left rtl-flip w-4 h-4" aria-hidden="true" /> ··· 74 74 <select 75 75 id="theme-select" 76 76 :value="colorMode.preference" 77 - class="w-full sm:w-auto min-w-48 bg-bg border border-border rounded-md px-3 py-2 text-sm text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 cursor-pointer" 77 + class="w-full sm:w-auto min-w-48 bg-bg border border-border rounded-md px-3 py-2 text-sm text-fg cursor-pointer" 78 78 @change=" 79 79 colorMode.preference = ($event.target as HTMLSelectElement).value as 80 80 | 'light' ··· 161 161 <select 162 162 id="language-select" 163 163 :value="locale" 164 - class="w-full sm:w-auto min-w-48 bg-bg border border-border rounded-md px-3 py-2 text-sm text-fg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 cursor-pointer" 164 + class="w-full sm:w-auto min-w-48 bg-bg border border-border rounded-md px-3 py-2 text-sm text-fg focus-visible:outline-accent/70 cursor-pointer" 165 165 @change="setLocale(($event.target as HTMLSelectElement).value as typeof locale)" 166 166 > 167 167 <option v-for="loc in locales" :key="loc.code" :value="loc.code" :lang="loc.code"> ··· 193 193 href="https://github.com/npmx-dev/npmx.dev/tree/main/i18n/locales" 194 194 target="_blank" 195 195 rel="noopener noreferrer" 196 - class="inline-flex items-center gap-2 text-sm text-fg-muted hover:text-fg transition-colors duration-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fg/50 rounded" 196 + class="inline-flex items-center gap-2 text-sm text-fg-muted hover:text-fg transition-colors duration-200 focus-visible:outline-accent/70 rounded" 197 197 > 198 198 <span class="i-carbon:logo-github w-4 h-4" aria-hidden="true" /> 199 199 {{ $t('settings.help_translate') }}
+26 -12
app/utils/prehydrate.ts
··· 1 1 import type { ACCENT_COLORS } from '#shared/utils/constants' 2 2 3 - type AccentColorId = keyof typeof ACCENT_COLORS 3 + type AccentColorId = keyof typeof ACCENT_COLORS.light // for both themes color names are same 4 4 5 5 /** 6 6 * Initialize user preferences before hydration to prevent flash/layout shift. ··· 14 14 // All constants must be hardcoded inside the callback. 15 15 onPrehydrate(() => { 16 16 // Accent colors - hardcoded since ACCENT_COLORS can't be referenced 17 - const colors: Record<AccentColorId, string> = { 18 - rose: 'oklch(0.797 0.084 11.056)', 19 - amber: 'oklch(0.828 0.165 84.429)', 20 - emerald: 'oklch(0.792 0.153 166.95)', 21 - sky: 'oklch(0.787 0.128 230.318)', 22 - violet: 'oklch(0.714 0.148 286.067)', 23 - coral: 'oklch(0.704 0.177 14.75)', 17 + 18 + const colors = { 19 + light: { 20 + coral: 'oklch(0.70 0.19 14.75)', 21 + amber: 'oklch(0.8 0.25 84.429)', 22 + emerald: 'oklch(0.70 0.17 166.95)', 23 + sky: 'oklch(0.70 0.15 230.318)', 24 + violet: 'oklch(0.70 0.17 286.067)', 25 + magenta: 'oklch(0.75 0.18 330)', 26 + }, 27 + dark: { 28 + coral: 'oklch(0.704 0.177 14.75)', 29 + amber: 'oklch(0.828 0.165 84.429)', 30 + emerald: 'oklch(0.792 0.153 166.95)', 31 + sky: 'oklch(0.787 0.128 230.318)', 32 + violet: 'oklch(0.78 0.148 286.067)', 33 + magenta: 'oklch(0.78 0.15 330)', 34 + }, 24 35 } 25 36 26 37 // Valid package manager IDs ··· 29 40 // Read settings from localStorage 30 41 const settings = JSON.parse(localStorage.getItem('npmx-settings') || '{}') 31 42 32 - // Apply accent color 33 - const color = settings.accentColorId ? colors[settings.accentColorId as AccentColorId] : null 34 - if (color) { 35 - document.documentElement.style.setProperty('--accent-color', color) 43 + // Determine theme (default to 'dark') 44 + const theme = document.documentElement.dataset.theme === 'light' ? 'light' : 'dark' 45 + 46 + // Apply accent color based on theme 47 + const accentColorId = settings.accentColorId as AccentColorId | undefined 48 + if (accentColorId && colors[theme][accentColorId]) { 49 + document.documentElement.style.setProperty('--accent-color', colors[theme][accentColorId]) 36 50 } 37 51 38 52 // Apply background accent
+7 -6
public-dev/favicon.svg
··· 1 1 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> 2 2 <rect width="512" height="512" rx="64" fill="#0a0a0a"/> 3 + <rect x="110" y="310" width="60" height="60" fill="#525252"/> 3 4 <text 4 - x="256" 5 - y="320" 6 - font-family="ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 7 - font-size="280" 5 + x="320" 6 + y="370" 7 + font-family="'Geist Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 8 + font-size="420" 8 9 font-weight="500" 9 10 text-anchor="middle" 10 - fill="#91BA4D" 11 - ><tspan fill="#20461A">.</tspan>/</text> 11 + fill="#fafafa" 12 + ><tspan>/</tspan></text> 12 13 </svg>
+3 -3
public-dev/logo.svg
··· 1 1 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> 2 2 <rect width="512" height="512" rx="64" fill="#0a0a0a"/> 3 - <rect x="110" y="310" width="60" height="60" fill="#20461A"/> 3 + <rect x="110" y="310" width="60" height="60" fill="#525252"/> 4 4 <text 5 5 x="320" 6 6 y="370" 7 - font-family="ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 7 + font-family="'Geist Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 8 8 font-size="420" 9 9 font-weight="500" 10 10 text-anchor="middle" 11 - fill="#91BA4D" 11 + fill="#fafafa" 12 12 ><tspan>/</tspan></text> 13 13 </svg>
+7 -6
public-staging/favicon.svg
··· 1 1 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> 2 2 <rect width="512" height="512" rx="64" fill="#0a0a0a"/> 3 + <rect x="110" y="310" width="60" height="60" fill="#525252"/> 3 4 <text 4 - x="256" 5 - y="320" 6 - font-family="ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 7 - font-size="280" 5 + x="320" 6 + y="370" 7 + font-family="'Geist Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 8 + font-size="420" 8 9 font-weight="500" 9 10 text-anchor="middle" 10 - fill="#5AB1CC" 11 - ><tspan fill="#1E4E5E">.</tspan>/</text> 11 + fill="#fafafa" 12 + ><tspan>/</tspan></text> 12 13 </svg>
+3 -3
public-staging/logo.svg
··· 1 1 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> 2 2 <rect width="512" height="512" rx="64" fill="#0a0a0a"/> 3 - <rect x="110" y="310" width="60" height="60" fill="#1E4E5E"/> 3 + <rect x="110" y="310" width="60" height="60" fill="#525252"/> 4 4 <text 5 5 x="320" 6 6 y="370" 7 - font-family="ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 7 + font-family="'Geist Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 8 8 font-size="420" 9 9 font-weight="500" 10 10 text-anchor="middle" 11 - fill="#5AB1CC" 11 + fill="#fafafa" 12 12 ><tspan>/</tspan></text> 13 13 </svg>
+6 -5
public/favicon.svg
··· 1 1 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"> 2 2 <rect width="512" height="512" rx="64" fill="#0a0a0a"/> 3 + <rect x="110" y="310" width="60" height="60" fill="#525252"/> 3 4 <text 4 - x="256" 5 - y="320" 6 - font-family="ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 7 - font-size="280" 5 + x="320" 6 + y="370" 7 + font-family="'Geist Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 8 + font-size="420" 8 9 font-weight="500" 9 10 text-anchor="middle" 10 11 fill="#fafafa" 11 - ><tspan fill="#525252">.</tspan>/</text> 12 + ><tspan>/</tspan></text> 12 13 </svg>
+1 -1
public/logo.svg
··· 4 4 <text 5 5 x="320" 6 6 y="370" 7 - font-family="ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 7 + font-family="'Geist Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace" 8 8 font-size="420" 9 9 font-weight="500" 10 10 text-anchor="middle"
+16 -6
shared/utils/constants.ts
··· 45 45 46 46 // Theming 47 47 export const ACCENT_COLORS = { 48 - rose: 'oklch(0.797 0.084 11.056)', 49 - amber: 'oklch(0.828 0.165 84.429)', 50 - emerald: 'oklch(0.792 0.153 166.95)', 51 - sky: 'oklch(0.787 0.128 230.318)', 52 - violet: 'oklch(0.714 0.148 286.067)', 53 - coral: 'oklch(0.704 0.177 14.75)', 48 + light: { 49 + coral: 'oklch(0.70 0.19 14.75)', 50 + amber: 'oklch(0.8 0.25 84.429)', 51 + emerald: 'oklch(0.70 0.17 166.95)', 52 + sky: 'oklch(0.70 0.15 230.318)', 53 + violet: 'oklch(0.70 0.17 286.067)', 54 + magenta: 'oklch(0.75 0.18 330)', 55 + }, 56 + dark: { 57 + coral: 'oklch(0.704 0.177 14.75)', 58 + amber: 'oklch(0.828 0.165 84.429)', 59 + emerald: 'oklch(0.792 0.153 166.95)', 60 + sky: 'oklch(0.787 0.128 230.318)', 61 + violet: 'oklch(0.78 0.148 286.067)', 62 + magenta: 'oklch(0.78 0.15 330)', 63 + }, 54 64 } as const 55 65 56 66 export const BACKGROUND_THEMES = {
+17
test/nuxt/a11y.spec.ts
··· 61 61 import { 62 62 AppFooter, 63 63 AppHeader, 64 + AppLogo, 64 65 BaseCard, 65 66 BuildEnvironment, 66 67 CallToAction, ··· 219 220 describe('AppFooter', () => { 220 221 it('should have no accessibility violations', async () => { 221 222 const component = await mountSuspended(AppFooter) 223 + const results = await runAxe(component) 224 + expect(results.violations).toEqual([]) 225 + }) 226 + }) 227 + 228 + describe('AppLogo', () => { 229 + it('should have no accessibility violations', async () => { 230 + const component = await mountSuspended(AppLogo) 231 + const results = await runAxe(component) 232 + expect(results.violations).toEqual([]) 233 + }) 234 + 235 + it('should have no accessibility violations with custom class', async () => { 236 + const component = await mountSuspended(AppLogo, { 237 + props: { class: 'h-6 w-6 text-accent' }, 238 + }) 222 239 const results = await runAxe(component) 223 240 expect(results.violations).toEqual([]) 224 241 })
+1 -1
uno.config.ts
··· 123 123 ['container-sm', 'max-w-5xl mx-auto px-4 sm:px-6'], 124 124 125 125 // Focus states - subtle but accessible 126 - ['focus-ring', 'outline-none focus-visible:(ring-2 ring-fg/10 ring-offset-2)'], 126 + ['focus-ring', 'outline-none focus-visible:(ring-2 ring-fg/50 ring-offset-2)'], 127 127 128 128 // Buttons 129 129 [