Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions app/components/AppHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,12 @@ onKeyStroke(

<!-- Center: Search bar + nav items -->
<div
class="flex-1 flex items-center justify-center md:gap-6"
:class="{ 'hidden sm:flex': !isSearchExpanded }"
class="flex-1 flex items-center md:gap-6"
:class="{
'hidden sm:flex': !isSearchExpanded,
'justify-end': isOnHomePage,
'justify-center': !isOnHomePage,
}"
>
<!-- Search bar (hidden on mobile unless expanded) -->
<HeaderSearchBox
Expand Down
13 changes: 7 additions & 6 deletions app/components/Compare/PackageSelector.vue
Original file line number Diff line number Diff line change
Expand Up @@ -139,17 +139,16 @@ function handleBlur() {

<!-- Add package input -->
<div v-if="packages.length < maxPackages" class="relative">
<div class="relative group">
<div class="relative group flex items-center">
<label for="package-search" class="sr-only">
{{ $t('compare.selector.search_label') }}
</label>
<span
class="absolute inset-y-0 start-3 flex items-center text-fg-subtle pointer-events-none group-focus-within:text-accent"
aria-hidden="true"
class="absolute inset-is-3 text-fg-subtle font-mono text-md pointer-events-none transition-colors duration-200 motion-reduce:transition-none [.group:hover:not(:focus-within)_&]:text-fg/80 group-focus-within:text-accent z-1"
>
<span class="i-carbon:search w-4 h-4" />
/
</span>
<input
<InputBase
id="package-search"
v-model="inputValue"
type="text"
Expand All @@ -158,7 +157,9 @@ function handleBlur() {
? $t('compare.selector.search_first')
: $t('compare.selector.search_add')
"
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)"
no-correct
size="medium"
class="w-full min-w-25 ps-7"
aria-autocomplete="list"
@focus="isInputFocused = true"
@blur="handleBlur"
Expand Down
6 changes: 4 additions & 2 deletions app/components/Filter/Panel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,15 @@ const hasActiveFilters = computed(() => !!filterSummary.value)
</button>
</div>
</div>
<input
<InputBase
id="filter-search"
type="text"
:value="filters.text"
:placeholder="searchPlaceholder"
autocomplete="off"
class="w-full bg-bg-subtle border border-border rounded-md px-4 py-3 font-mono text-sm text-fg placeholder:text-fg-subtle transition-[border-color,outline-color] duration-300 hover:border-fg-subtle outline-2 outline-transparent focus:border-accent focus-visible:(outline-2 outline-accent/70)"
class="w-full min-w-25"
size="medium"
no-correct
@input="handleTextInput"
/>
</div>
Expand Down
7 changes: 4 additions & 3 deletions app/components/Header/AuthModal.client.vue
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,15 @@ watch(handleInput, newHandleInput => {
>
{{ $t('auth.modal.handle_label') }}
</label>
<input
<InputBase
id="handle-input"
v-model="handleInput"
type="text"
name="handle"
:placeholder="$t('auth.modal.handle_placeholder')"
v-bind="noCorrect"
class="w-full px-3 py-2 font-mono text-sm bg-bg-subtle border border-border rounded-md text-fg placeholder:text-fg-subtle transition-colors duration-200 hover:border-fg-subtle focus:border-accent focus-visible:(outline-2 outline-accent/70)"
no-correct
class="w-full"
size="medium"
/>
<p v-if="errorMessage" class="text-red-500 text-xs mt-1" role="alert">
{{ errorMessage }}
Expand Down
12 changes: 7 additions & 5 deletions app/components/Header/ConnectorModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -161,14 +161,15 @@ function handleDisconnect() {
>
{{ $t('connector.modal.token_label') }}
</label>
<input
<InputBase
id="connector-token"
v-model="tokenInput"
type="password"
name="connector-token"
:placeholder="$t('connector.modal.token_placeholder')"
v-bind="noCorrect"
class="w-full px-3 py-2 font-mono text-sm bg-bg-subtle border border-border rounded-md text-fg placeholder:text-fg-subtle transition-colors duration-200 hover:border-fg-subtle focus-visible:outline-none focus-visible:ring-2 focus-visible:outline-accent/70"
no-correct
class="w-full"
size="medium"
/>
</div>

Expand All @@ -183,14 +184,15 @@ function handleDisconnect() {
>
{{ $t('connector.modal.port_label') }}
</label>
<input
<InputBase
id="connector-port"
v-model="portInput"
type="text"
name="connector-port"
inputmode="numeric"
autocomplete="off"
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 hover:border-fg-subtle focus:border-border-hover focus-visible:outline-none focus-visible:ring-2 focus-visible:outline-accent/70"
class="w-full"
size="medium"
/>
</div>
</details>
Expand Down
20 changes: 6 additions & 14 deletions app/components/Header/SearchBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,6 @@ watch(
},
)

function handleSearchBlur() {
isSearchFocused.value = false
emit('blur')
}
function handleSearchFocus() {
isSearchFocused.value = true
emit('focus')
}

function handleSubmit() {
if (pagesWithLocalFilter.has(route.name as string)) {
router.push({
Expand Down Expand Up @@ -114,17 +105,18 @@ defineExpose({ focus })
/
</span>

<input
<InputBase
id="header-search"
ref="inputRef"
v-model="searchQuery"
type="search"
name="q"
:placeholder="$t('search.placeholder')"
v-bind="noCorrect"
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,outline-color] duration-300 hover:border-fg-subtle outline-2 outline-transparent focus:border-accent focus-visible:(outline-2 outline-accent/70)"
@focus="handleSearchFocus"
@blur="handleSearchBlur"
no-correct
class="w-full min-w-25 ps-7"
@focus="isSearchFocused = true"
@blur="isSearchFocused = false"
size="small"
/>
<button type="submit" class="sr-only">{{ $t('search.button') }}</button>
</div>
Expand Down
49 changes: 49 additions & 0 deletions app/components/Input/Base.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script setup lang="ts">
import { noCorrect } from '~/utils/input'

const model = defineModel<string>({ default: '' })

const props = withDefaults(
defineProps<{
disabled?: boolean
size?: 'small' | 'medium' | 'large'
noCorrect?: boolean
}>(),
{
size: 'medium',
noCorrect: true,
},
)

const emit = defineEmits<{
focus: [event: FocusEvent]
blur: [event: FocusEvent]
}>()

const el = useTemplateRef('el')

defineExpose({
focus: () => el.value?.focus(),
blur: () => el.value?.blur(),
})
</script>

<template>
<input
ref="el"
v-model="model"
v-bind="props.noCorrect ? noCorrect : undefined"
@focus="emit('focus', $event)"
@blur="emit('blur', $event)"
class="bg-bg-subtle border border-border font-mono text-fg placeholder:text-fg-subtle transition-[border-color,outline-color] duration-300 hover:border-fg-subtle outline-2 outline-transparent outline-offset-2 focus:border-accent focus-visible:outline-accent/70 disabled:(opacity-50 cursor-not-allowed)"
:class="{
'text-xs leading-[1.2] px-2 py-2 rounded-md': size === 'small',
'text-sm leading-none px-3 py-2.5 rounded-lg': size === 'medium',
'text-base leading-none px-6 py-3.5 h-14 rounded-xl': size === 'large',
}"
:disabled="
/** Catching Vue render-bug of invalid `disabled=false` attribute in the final HTML */
disabled ? true : undefined
"
/>
</template>
16 changes: 9 additions & 7 deletions app/components/Org/MembersPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -331,14 +331,15 @@ watch(lastExecutionTime, () => {
aria-hidden="true"
/>
<label for="members-search" class="sr-only">{{ $t('org.members.filter_label') }}</label>
<input
<InputBase
id="members-search"
v-model="searchQuery"
type="search"
name="members-search"
:placeholder="$t('org.members.filter_placeholder')"
v-bind="noCorrect"
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)"
no-correct
class="w-full min-w-25 ps-7"
size="small"
/>
</div>
<div
Expand Down Expand Up @@ -516,14 +517,15 @@ watch(lastExecutionTime, () => {
<label for="new-member-username" class="sr-only">{{
$t('org.members.username_label')
}}</label>
<input
<InputBase
id="new-member-username"
v-model="newUsername"
type="text"
name="new-member-username"
:placeholder="$t('org.members.username_placeholder')"
v-bind="noCorrect"
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"
no-correct
class="w-full min-w-25"
size="small"
/>
<div class="flex items-center gap-2">
<label for="new-member-role" class="sr-only">{{ $t('org.members.role_label') }}</label>
Expand Down Expand Up @@ -553,7 +555,7 @@ watch(lastExecutionTime, () => {
<button
type="submit"
:disabled="!newUsername.trim() || isAddingMember"
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"
class="px-3 py-2 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"
>
{{ isAddingMember ? '…' : $t('org.members.add_button') }}
</button>
Expand Down
7 changes: 4 additions & 3 deletions app/components/Org/OperationsQueue.vue
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ watch(isExecuting, executing => {
</div>
<form class="flex items-center gap-2" @submit.prevent="handleRetryWithOtp">
<label for="otp-input" class="sr-only">{{ $t('operations.queue.otp_label') }}</label>
<input
<InputBase
id="otp-input"
v-model="otpInput"
type="text"
Expand All @@ -252,12 +252,13 @@ watch(isExecuting, executing => {
:placeholder="$t('operations.queue.otp_placeholder')"
autocomplete="one-time-code"
spellcheck="false"
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"
class="flex-1 min-w-25"
size="small"
/>
<button
type="submit"
:disabled="!otpInput.trim() || isExecuting"
class="px-3 py-1.5 font-mono text-xs text-bg bg-amber-500 rounded transition-all duration-200 hover:bg-amber-400 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-500/50"
class="px-3 py-2 font-mono text-xs text-bg bg-amber-500 rounded transition-all duration-200 hover:bg-amber-400 disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-amber-500/50"
>
{{ isExecuting ? $t('operations.queue.retrying') : $t('operations.queue.retry_otp') }}
</button>
Expand Down
27 changes: 15 additions & 12 deletions app/components/Org/TeamsPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -287,14 +287,15 @@ watch(lastExecutionTime, () => {
aria-hidden="true"
/>
<label for="teams-search" class="sr-only">{{ $t('org.teams.filter_label') }}</label>
<input
<InputBase
id="teams-search"
v-model="searchQuery"
type="search"
name="teams-search"
:placeholder="$t('org.teams.filter_placeholder')"
v-bind="noCorrect"
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)"
no-correct
class="w-full min-w-25 ps-7"
size="medium"
/>
</div>
<div
Expand Down Expand Up @@ -425,7 +426,7 @@ watch(lastExecutionTime, () => {
>
~{{ user }}
</NuxtLink>
<span class="font-mono text-sm text-fg">{{ teamName }}</span>
<span class="font-mono text-sm text-fg mx-2">{{ teamName }}</span>
<button
type="button"
class="p-1 text-fg-subtle hover:text-red-400 transition-colors duration-200 rounded focus-visible:outline-accent/70"
Expand All @@ -446,14 +447,15 @@ watch(lastExecutionTime, () => {
<label :for="`add-user-${teamName}`" class="sr-only">{{
$t('org.teams.username_to_add', { team: teamName })
}}</label>
<input
<InputBase
:id="`add-user-${teamName}`"
v-model="newUserUsername"
type="text"
:name="`add-user-${teamName}`"
:placeholder="$t('org.teams.username_placeholder')"
v-bind="noCorrect"
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"
no-correct
class="flex-1 min-w-25"
size="medium"
/>
<button
type="submit"
Expand Down Expand Up @@ -497,25 +499,26 @@ watch(lastExecutionTime, () => {
<form class="flex items-center gap-2" @submit.prevent="handleCreateTeam">
<div class="flex-1 flex items-center">
<span
class="px-2 py-1.5 font-mono text-sm text-fg-subtle bg-bg border border-ie-0 border-border rounded-is"
class="px-2 py-3 leading-none font-mono text-sm text-fg-subtle bg-bg border border-ie-0 border-border rounded-is"
>
{{ orgName }}:
</span>
<label for="new-team-name" class="sr-only">{{ $t('org.teams.team_name_label') }}</label>
<input
<InputBase
id="new-team-name"
v-model="newTeamName"
type="text"
name="new-team-name"
:placeholder="$t('org.teams.team_name_placeholder')"
v-bind="noCorrect"
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"
no-correct
class="flex-1 min-w-25 rounded-is-none"
size="medium"
/>
</div>
<button
type="submit"
:disabled="!newTeamName.trim() || isCreatingTeam"
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"
class="px-3 py-2 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"
>
{{ isCreatingTeam ? '…' : $t('org.teams.create_button') }}
</button>
Expand Down
2 changes: 1 addition & 1 deletion app/components/Package/AccessControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ watch(
<button
type="submit"
:disabled="!selectedTeam || isGranting"
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"
class="px-3 py-2 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"
>
{{ isGranting ? '…' : $t('package.access.grant_button') }}
</button>
Expand Down
Loading
Loading