Skip to content
Closed
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
6 changes: 6 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@
## 2026-06-25 - Explicit Loading Feedback for Intent Generation
**Learning:** In deeply nested data-action layouts (like DataLayout's document and thread intent generation), missing explicit loading spinners and text changes (e.g., from "์‹คํ–‰" to "์ฒ˜๋ฆฌ ์ค‘") leaves users guessing if the button click registered. `disabled` alone is insufficient feedback for intent-checking actions which often take several seconds.
**Action:** When adding asynchronous intent check actions (like WebDAV or thread validations), always combine `disabled={isLoading}`, `aria-busy={isLoading}`, a `Loader2` spinner, and a dynamic text label (e.g. `isLoading ? '์ ๊ฒ€ ์ค‘' : '์ ๊ฒ€'`) to give immediate, unambiguous feedback.
## 2024-07-06 - Ensure active tabs use `aria-current` and keyboard focus styles
**Learning:** When using raw HTML `<button>` elements to create custom active tabs, missing `aria-current="page"` fails to expose the active state to screen readers. Also, missing Tailwind `focus-visible` utilities prevents keyboard navigation users from seeing which tab is focused.
**Action:** Always include `aria-current={active ? 'page' : undefined}` (and optionally `aria-pressed={active}`) on active tabs, and explicitly add Tailwind's `focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-1 focus-visible:ring-offset-background` to maintain keyboard accessibility and visual focus indicators when using raw HTML buttons over UI components.
## 2024-07-06 - Update: Use semantic `role="tab"` for view mode toggles
**Learning:** For view mode toggles acting as tabs (switching content panes without navigating away), using `aria-current="page"` or `aria-pressed` is incorrect.
**Action:** When implementing view toggles, wrap the buttons in a container with `role="tablist"` and give each button `role="tab"` and `aria-selected={active}` to correctly convey the semantic relationship to screen readers.
6 changes: 4 additions & 2 deletions frontend/src/components/ProjectsLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -851,13 +851,15 @@ export function ProjectsLayout() {
</button>
))}
</div>
<div className="flex overflow-x-auto rounded-md border border-border">
<div className="flex overflow-x-auto rounded-md border border-border" role="tablist" aria-label="ํ”„๋กœ์ ํŠธ ๋ทฐ ๋ชจ๋“œ">
{(['ํ”„๋กœ์ ํŠธ ์ƒ์„ธ', '๋งˆ์ผ์Šคํ†ค', '์˜์‚ฌ๊ฒฐ์ • ๋กœ๊ทธ'] as ProjectViewMode[]).map((mode) => (
<button
key={mode}
type="button"
role="tab"
onClick={() => setViewMode(mode)}
className={`min-h-9 shrink-0 px-3 text-xs font-semibold transition-colors sm:px-4 sm:text-sm ${viewMode === mode ? 'bg-primary text-primary-foreground' : 'bg-background hover:bg-secondary'}`}
aria-selected={viewMode === mode}
className={`min-h-9 shrink-0 px-3 text-xs font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-1 focus-visible:ring-offset-background sm:px-4 sm:text-sm ${viewMode === mode ? 'bg-primary text-primary-foreground' : 'bg-background hover:bg-secondary'}`}
>
{mode}
</button>
Expand Down
Loading