Skip to content

Commit 9bf4501

Browse files
RedStar071Copilot
andauthored
style(profile): improve spatial hierarchy, rhythm, and accessibility (#111)
- [x] Add aria-labels to mobile icon-only UButton instances - [x] Add aria-label to desktop sort UButton (dynamic, reflects sortAscending state) - [x] Fix HTML validation error: restore `<h2 class="sr-only">Servers</h2>` in the Servers tab panel so prerendered `/profile` doesn't skip from h1 to h3 (footer UFooterColumns) --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
1 parent b25f1d9 commit 9bf4501

1 file changed

Lines changed: 139 additions & 148 deletions

File tree

app/pages/profile.vue

Lines changed: 139 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
<UContainer class="mx-auto max-w-7xl space-y-8 px-4 py-8">
44
<h1 class="sr-only">User Profile</h1>
55
<section
6-
class="relative flex flex-col items-center justify-center gap-6 overflow-hidden rounded-xl border-2 border-base-200 bg-base-200/30 p-8 md:flex-row md:border-4 md:p-12"
6+
class="relative flex flex-col items-center justify-center gap-6 overflow-hidden rounded-xl border-2 border-base-200 bg-base-200/30 p-6 shadow-sm md:flex-row md:border-4 md:p-8"
77
>
88
<!-- decorative left accent (sidebar-like) -->
99
<div
10-
class="absolute inset-y-2 left-0 hidden w-1 rounded-r-md bg-primary/40 md:block"
10+
class="absolute inset-y-2 left-0 hidden w-1 rounded-r-md bg-primary/30 md:block"
1111
aria-hidden="true"
1212
></div>
1313
<div v-if="!user" class="flex flex-col items-center justify-center space-y-6">
@@ -89,11 +89,11 @@
8989
</section>
9090

9191
<section
92-
class="relative flex flex-col items-center justify-center divide-y divide-base-200/50 overflow-hidden rounded-xl border-2 border-base-200 bg-base-200/20 shadow-lg md:border-4"
92+
class="relative flex flex-col items-center justify-center divide-y divide-base-200/50 overflow-hidden rounded-xl border-2 border-base-200 bg-base-200/20 md:border-4"
9393
>
9494
<!-- subtle left accent to mirror dashboard sidebar -->
9595
<div
96-
class="absolute inset-y-2 left-0 hidden w-1 rounded-r-md bg-secondary/20 md:block"
96+
class="absolute inset-y-2 left-0 hidden w-1 rounded-r-md bg-secondary/30 md:block"
9797
aria-hidden="true"
9898
></div>
9999
<UTabs
@@ -103,159 +103,150 @@
103103
class="flex w-full flex-col items-center justify-center"
104104
>
105105
<template #content="{ item }">
106-
<div class="p-8">
106+
<div class="p-6 md:p-8">
107107
<div v-if="item.value === 'servers'" class="space-y-6">
108-
<!-- Server Section Header -->
109-
<div class="mb-4">
110-
<h2 class="text-2xl font-bold text-base-content">Servers</h2>
111-
<div class="mt-1 text-base-content/60">
112-
<USkeleton v-if="isLoading" class="inline-block h-5 w-48" />
113-
<span v-else>{{ guilds.length ?? 0 }} servers</span>
114-
</div>
115-
</div>
116-
108+
<h2 class="sr-only">Servers</h2>
117109
<!-- Search and Controls Section -->
118-
<div class="mb-4 flex flex-wrap items-center justify-between gap-4">
119-
<div class="flex items-end gap-2">
120-
<UFieldGroup class="flex items-start gap-2">
121-
<UInput
122-
ref="input"
123-
v-model="searchQuery"
124-
aria-label="Search servers"
125-
name="search"
126-
type="text"
127-
placeholder="Search servers..."
128-
icon="heroicons:magnifying-glass-circle"
129-
:is-loading
130-
is-loading-icon="lucide:loader"
131-
class="flex max-w-xs items-start"
132-
>
133-
<template v-if="searchQuery?.length" #trailing>
134-
<UButton
135-
color="neutral"
136-
variant="link"
137-
size="sm"
138-
icon="lucide:circle-x"
139-
aria-label="Clear input"
140-
@click="undoSearch()"
141-
/>
142-
</template>
143-
</UInput>
144-
</UFieldGroup>
145-
<!-- Mobile Buttons (no view toggle) -->
146-
<UFieldGroup size="sm" class="join flex items-end sm:hidden">
147-
<!-- Manageable Only Toggle Button -->
110+
<div class="mb-4 flex flex-wrap items-center gap-4">
111+
<UInput
112+
ref="input"
113+
v-model="searchQuery"
114+
aria-label="Search servers"
115+
name="search"
116+
type="text"
117+
placeholder="Search servers..."
118+
icon="heroicons:magnifying-glass-circle"
119+
:is-loading
120+
is-loading-icon="lucide:loader"
121+
class="flex max-w-xs items-start"
122+
>
123+
<template v-if="searchQuery?.length" #trailing>
148124
<UButton
149-
class="join-item"
150-
color="primary"
151-
:is-loading
152-
is-loading-icon="lucide:loader"
153-
icon="heroicons:shield-check"
154-
@click="toggleShowManageableOnly()"
125+
color="neutral"
126+
variant="link"
127+
size="sm"
128+
icon="lucide:circle-x"
129+
aria-label="Clear input"
130+
@click="undoSearch()"
155131
/>
156-
157-
<!-- Sort Button -->
158-
<UButton
159-
class="join-item"
160-
color="primary"
161-
:is-loading
162-
@click="toggleSortOrder()"
163-
>
164-
<template #leading>
165-
<UIcon
166-
v-motion
167-
:initial="{ opacity: 0 }"
168-
:enter="{
169-
opacity: 1,
170-
transition: { duration: 150 },
171-
}"
172-
:leave="{
173-
opacity: 0,
174-
transition: { duration: 150 },
175-
}"
176-
:name="
177-
sortAscending
178-
? 'lucide:arrow-up-a-z'
179-
: 'lucide:arrow-down-z-a'
180-
"
181-
/>
182-
</template>
183-
</UButton>
184-
185-
<!-- Refresh Button -->
186-
<UButton
187-
v-if="filteredGuilds.length === 0"
188-
class="join-item"
189-
color="primary"
190-
:is-loading
191-
is-loading-icon="lucide:loader"
192-
icon="heroicons:arrow-path-20-solid"
193-
@click="refresh()"
194-
/>
195-
</UFieldGroup>
196-
197-
<!-- Desktop Buttons (with view toggle) -->
198-
<UFieldGroup size="sm" class="join hidden items-end sm:flex">
199-
<!--
132+
</template>
133+
</UInput>
134+
<!-- Mobile Buttons (no view toggle) -->
135+
<UFieldGroup size="sm" class="join flex items-end sm:hidden">
136+
<!-- Manageable Only Toggle Button -->
137+
<UButton
138+
class="join-item"
139+
color="primary"
140+
:is-loading
141+
is-loading-icon="lucide:loader"
142+
icon="heroicons:shield-check"
143+
aria-label="Toggle manageable only"
144+
@click="toggleShowManageableOnly()"
145+
/>
146+
147+
<!-- Sort Button -->
148+
<UButton
149+
class="join-item"
150+
color="primary"
151+
:is-loading
152+
:aria-label="sortAscending ? 'Sort Z to A' : 'Sort A to Z'"
153+
@click="toggleSortOrder()"
154+
>
155+
<template #leading>
156+
<UIcon
157+
v-motion
158+
:initial="{ opacity: 0 }"
159+
:enter="{
160+
opacity: 1,
161+
transition: { duration: 150 },
162+
}"
163+
:leave="{
164+
opacity: 0,
165+
transition: { duration: 150 },
166+
}"
167+
:name="
168+
sortAscending
169+
? 'lucide:arrow-up-a-z'
170+
: 'lucide:arrow-down-z-a'
171+
"
172+
/>
173+
</template>
174+
</UButton>
175+
176+
<!-- Refresh Button -->
177+
<UButton
178+
v-if="filteredGuilds.length === 0"
179+
class="join-item"
180+
color="primary"
181+
:is-loading
182+
is-loading-icon="lucide:loader"
183+
icon="heroicons:arrow-path-20-solid"
184+
aria-label="Refresh servers"
185+
@click="refresh()"
186+
/>
187+
</UFieldGroup>
188+
189+
<!-- Desktop Buttons (with view toggle) -->
190+
<UFieldGroup size="sm" class="join hidden items-end sm:flex">
191+
<!--
200192
Manageable
201193
Only
202194
Toggle
203195
Button
204196
-->
205-
<UButton
206-
class="join-item"
207-
color="primary"
208-
:is-loading
209-
is-loading-icon="lucide:loader"
210-
icon="heroicons:shield-check"
211-
@click="toggleShowManageableOnly()"
212-
>
213-
<span>Manageable</span>
214-
</UButton>
215-
216-
<!-- Sort Button -->
217-
<UButton
218-
class="join-item"
219-
color="primary"
220-
:is-loading
221-
@click="toggleSortOrder()"
222-
>
223-
<template #leading>
224-
<UIcon
225-
v-motion
226-
:initial="{ opacity: 0 }"
227-
:enter="{
228-
opacity: 1,
229-
transition: { duration: 150 },
230-
}"
231-
:leave="{
232-
opacity: 0,
233-
transition: { duration: 150 },
234-
}"
235-
:name="
236-
sortAscending
237-
? 'lucide:arrow-up-a-z'
238-
: 'lucide:arrow-down-z-a'
239-
"
240-
/>
241-
</template>
242-
</UButton>
243-
244-
<!-- Refresh Button -->
245-
<UButton
246-
v-if="filteredGuilds.length === 0"
247-
class="join-item"
248-
color="primary"
249-
:is-loading
250-
is-loading-icon="lucide:loader"
251-
icon="heroicons:arrow-path-20-solid"
252-
@click="refresh()"
253-
>
254-
<span>Refresh</span>
255-
</UButton>
256-
</UFieldGroup>
257-
</div>
258-
<!-- Search Input for Desktop -->
197+
<UButton
198+
class="join-item"
199+
color="primary"
200+
:is-loading
201+
is-loading-icon="lucide:loader"
202+
icon="heroicons:shield-check"
203+
@click="toggleShowManageableOnly()"
204+
>
205+
<span>Manageable</span>
206+
</UButton>
207+
208+
<!-- Sort Button -->
209+
<UButton
210+
class="join-item"
211+
color="primary"
212+
:is-loading
213+
:aria-label="sortAscending ? 'Sort Z to A' : 'Sort A to Z'"
214+
@click="toggleSortOrder()"
215+
>
216+
<template #leading>
217+
<UIcon
218+
v-motion
219+
:initial="{ opacity: 0 }"
220+
:enter="{
221+
opacity: 1,
222+
transition: { duration: 150 },
223+
}"
224+
:leave="{
225+
opacity: 0,
226+
transition: { duration: 150 },
227+
}"
228+
:name="
229+
sortAscending
230+
? 'lucide:arrow-up-a-z'
231+
: 'lucide:arrow-down-z-a'
232+
"
233+
/>
234+
</template>
235+
</UButton>
236+
237+
<!-- Refresh Button -->
238+
<UButton
239+
v-if="filteredGuilds.length === 0"
240+
class="join-item"
241+
color="primary"
242+
:is-loading
243+
is-loading-icon="lucide:loader"
244+
icon="heroicons:arrow-path-20-solid"
245+
@click="refresh()"
246+
>
247+
<span>Refresh</span>
248+
</UButton>
249+
</UFieldGroup>
259250
</div>
260251
<div class="space-y-4 md:space-y-2">
261252
<GuildCards

0 commit comments

Comments
 (0)