Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
8d5e318
Replace manual click/keyboard wrappers with semantic HTML
az108 May 14, 2026
aae762e
Merge remote-tracking branch 'origin/main' into chore/semantic-intera…
az108 May 19, 2026
6065126
Merge branch 'main' into chore/semantic-interactive-elements
az108 May 21, 2026
ab9741b
Merge remote-tracking branch 'origin/main' into chore/semantic-intera…
az108 May 21, 2026
98092de
Merge branch 'main' into chore/semantic-interactive-elements
az108 Jul 5, 2026
319f3d5
Merge branch 'main' into chore/semantic-interactive-elements
Cathy0123456789 Jul 13, 2026
cd97ebe
Merge branch 'main' into chore/semantic-interactive-elements
Cathy0123456789 Jul 24, 2026
ca8149a
Merge branch 'main' into chore/semantic-interactive-elements
az108 Jul 25, 2026
cb2341f
Merge branch 'main' into chore/semantic-interactive-elements
Cathy0123456789 Jul 25, 2026
f5bb288
`Bugfix`: Keep the button reset from overriding Tailwind utilities
az108 Jul 25, 2026
73b7019
`Bugfix`: Stretch the sidebar button so its highlight covers the whol…
az108 Jul 26, 2026
a791e0c
`General`: Trim the bare button class to what Tailwind does not alrea…
az108 Jul 26, 2026
0644566
`General`: Fix keyboard and layout regressions from the semantic elem…
az108 Jul 26, 2026
f5b2199
Merge remote-tracking branch 'origin/main' into chore/semantic-intera…
az108 Jul 26, 2026
1bb2ff9
`Bugfix`: Move focus into confirmation dialogs and show it on hover-o…
az108 Jul 28, 2026
7420c08
`Development`: Move through the candidate lists with the arrow keys
az108 Jul 28, 2026
0b0f214
Merge remote-tracking branch 'origin/main' into chore/semantic-intera…
az108 Jul 28, 2026
25cc819
`General`: Reuse one focus indicator style for the candidate lists
az108 Aug 9, 2026
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
2 changes: 1 addition & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ export default [
'prettier/prettier': ['error', { parser: 'angular' }],
'@angular-eslint/template/alt-text': 'error',
'@angular-eslint/template/button-has-type': 'error',
'@angular-eslint/template/click-events-have-key-events': 'error',
'@angular-eslint/template/click-events-have-key-events': ['error', { ignoreWithDirectives: ['jhiClickable'] }],
'@angular-eslint/template/elements-content': 'off',
'@angular-eslint/template/interactive-supports-focus': 'error',
'@angular-eslint/template/label-has-associated-control': 'error',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
<div
class="w-full rounded-lg p-2.5 cursor-pointer transition-all border"
<button
type="button"
class="btn-bare w-full rounded-lg p-2.5 cursor-pointer transition-all border"
[class.border-primary-default]="selected()"
[class.bg-background-surface-alt]="selected()"
[class.hover:bg-background-surface-alt]="selected()"
[class.border-border-default]="!selected()"
[class.hover:bg-background-surface]="!selected()"
tabindex="0"
role="button"
(click)="onSelect()"
(keydown.enter)="onSelect()"
>
<!-- Time Range -->
<div class="text-sm font-semibold text-text">{{ timeRange() }}</div>
Expand All @@ -31,4 +29,4 @@
}
</div>
</div>
</div>
</button>
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<div
class="flex flex-col lg:flex-row lg:items-center justify-between p-3 bg-background-default border rounded border-border-default min-h-[4rem] h-auto cursor-pointer hover:bg-background-surface transition-colors gap-3"
jhiClickable
role="link"
tabindex="0"
role="button"
(click)="navigateToAssessment()"
(keydown.enter)="navigateToAssessment()"
>
<div class="flex flex-col lg:flex-row lg:items-center gap-3 lg:gap-0 flex-1 min-w-0">
<!-- Identity Group (Name + Status) - Kept together for alignment -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { map } from 'rxjs';
import { IntervieweeDTO, IntervieweeDTOStateEnum } from 'app/generated/model/interviewee-dto';
import { ButtonComponent } from 'app/shared/components/atoms/button/button.component';
import { UserAvatarComponent } from 'app/shared/components/atoms/user-avatar/user-avatar.component';
import { ClickableDirective } from 'app/shared/directives/clickable.directive';
import TranslateDirective from 'app/shared/language/translate.directive';
import { formatDate, formatTimeRange, getLocale } from 'app/shared/util/date-time.util';
import { formatFullName } from 'app/shared/util/name.util';
Expand All @@ -18,7 +19,7 @@ import { formatFullName } from 'app/shared/util/name.util';
@Component({
selector: 'jhi-interviewee-card',
standalone: true,
imports: [TranslateModule, TranslateDirective, ButtonComponent, FontAwesomeModule, UserAvatarComponent],
imports: [TranslateModule, TranslateDirective, ButtonComponent, FontAwesomeModule, UserAvatarComponent, ClickableDirective],
templateUrl: './interviewee-card.component.html',
})
export class IntervieweeCardComponent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,7 @@

<!-- Template for name column with checkbox -->
<ng-template #nameTemplate let-row>
<div
class="flex items-center gap-3 cursor-pointer"
tabindex="0"
role="button"
(click)="toggleSelection(row.applicationId)"
(keydown.enter)="toggleSelection(row.applicationId)"
>
<div class="flex items-center gap-3 cursor-pointer" jhiClickable tabindex="0" (click)="toggleSelection(row.applicationId)">
<jhi-checkbox [model]="row.selected" [errorEnabled]="false" (click)="$event.stopPropagation(); toggleSelection(row.applicationId)" />
<jhi-user-avatar [fullName]="row.name" [avatarUrl]="row.avatar" loading="lazy" />
<span class="font-medium text-text-primary">{{ row.name }}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import TranslateDirective from 'app/shared/language/translate.directive';
import { ConfirmDialog } from 'app/shared/components/atoms/confirm-dialog/confirm-dialog';
import { CheckboxComponent } from 'app/shared/components/atoms/checkbox/checkbox.component';
import { UserAvatarComponent } from 'app/shared/components/atoms/user-avatar/user-avatar.component';
import { ClickableDirective } from 'app/shared/directives/clickable.directive';

import { CancelInterviewModalComponent } from '../cancel-interview-modal/cancel-interview-modal.component';

Expand Down Expand Up @@ -55,6 +56,7 @@ interface ApplicantRow {
CheckboxComponent,
UserAvatarComponent,
CancelInterviewModalComponent,
ClickableDirective,
],
templateUrl: './interviewee-section.component.html',
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,7 @@ <h3 class="text-base font-semibold text-text-primary">{{ slotDate() }} | {{ slot

<ng-template #applicantTpl let-person>
@let displayName = person.user?.name ?? ((person.user?.firstName ?? '') + ' ' + (person.user?.lastName ?? '')).trim();
<div
class="flex items-center gap-3 cursor-pointer"
tabindex="0"
role="button"
(click)="selectApplicant(person)"
(keydown.enter)="selectApplicant(person)"
>
<div class="flex items-center gap-3 cursor-pointer" jhiClickable tabindex="0" (click)="selectApplicant(person)">
<jhi-checkbox [model]="isSelected(person)" [errorEnabled]="false" (click)="$event.stopPropagation(); selectApplicant(person)" />
<jhi-user-avatar [fullName]="displayName" [avatarUrl]="person.user?.avatar" loading="lazy" />
<span class="font-medium text-text-primary">{{ displayName }}</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { isVirtualLocation } from 'app/shared/util/location.util';
import { CheckboxComponent } from 'app/shared/components/atoms/checkbox/checkbox.component';
import { DynamicTableComponent } from 'app/shared/components/organisms/dynamic-table/dynamic-table.component';
import { UserAvatarComponent } from 'app/shared/components/atoms/user-avatar/user-avatar.component';
import { ClickableDirective } from 'app/shared/directives/clickable.directive';

// Modal component for assigning an applicant to an interview slot.
// Displays available interviewees and allows single selection for slot assignment.
Expand All @@ -32,6 +33,7 @@ import { UserAvatarComponent } from 'app/shared/components/atoms/user-avatar/use
CheckboxComponent,
DynamicTableComponent,
UserAvatarComponent,
ClickableDirective,
],
templateUrl: './assign-applicant-modal.component.html',
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
<article
<button
type="button"
(click)="onCardClick()"
(keydown.enter)="onCardClick()"
tabindex="0"
role="button"
class="flex flex-row rounded-lg border border-border-default bg-background-default overflow-hidden cursor-pointer transition-all hover:bg-background-surface group"
class="btn-bare flex flex-row rounded-lg border border-border-default bg-background-default overflow-hidden cursor-pointer transition-all hover:bg-background-surface group w-full text-left"
[class.opacity-80]="isClosed()"
>
<!-- Image -->
Expand Down Expand Up @@ -89,4 +87,4 @@ <h3 class="text-base font-semibold line-clamp-2 m-0 leading-tight text-text flex
</div>
</div>
</div>
</article>
</button>
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<div
(click)="navigateToAssessment($event)"
(keydown.enter)="navigateToAssessment($event)"
jhiClickable
role="link"
tabindex="0"
(click)="navigateToAssessment($event)"
class="flex flex-col p-3 bg-background-default border rounded-lg border-border-default hover:bg-background-surface gap-2 group h-[8.5rem] w-full overflow-hidden cursor-pointer"
>
<!-- Row 1: Avatar + Name -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ import { Router } from '@angular/router';
import { UpcomingInterviewDTO } from 'app/generated/model/upcoming-interview-dto';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { UserAvatarComponent } from 'app/shared/components/atoms/user-avatar/user-avatar.component';
import { ClickableDirective } from 'app/shared/directives/clickable.directive';
import dayjs from 'dayjs/esm';

@Component({
selector: 'jhi-upcoming-interview-card',
imports: [FontAwesomeModule, UserAvatarComponent],
imports: [FontAwesomeModule, UserAvatarComponent, ClickableDirective],
templateUrl: './upcoming-interview-card.component.html',
})
export class UpcomingInterviewCardComponent {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -419,10 +419,9 @@ <h1 jhiTranslate="{{ pageTitle() }}"></h1>
<ng-template #imageCard let-image="image" let-showDelete="showDelete" let-isNoImage="isNoImage" let-isSelected="isSelected">
<div
[class]="'relative rounded-lg transition-all cursor-pointer hover:shadow-lg hover:-translate-y-1' + (showDelete ? ' group' : '')"
jhiClickable
tabindex="0"
role="button"
(click)="isNoImage ? clearImageSelection() : selectImage(image)"
(keydown.enter)="isNoImage ? clearImageSelection() : selectImage(image)"
>
<div
class="relative rounded-lg overflow-hidden border-[0.2rem] transition-colors aspect-video"
Expand All @@ -443,13 +442,7 @@ <h1 jhiTranslate="{{ pageTitle() }}"></h1>
}
</div>
@if (showDelete) {
<div
class="absolute top-2 right-2"
tabindex="0"
role="button"
(click)="$event.stopPropagation()"
(keydown.enter)="$event.stopPropagation()"
>
<div class="absolute top-2 right-2" role="presentation" (click)="$event.stopPropagation()">
<jhi-confirm-dialog
#deleteDialog
label="button.delete"
Expand Down Expand Up @@ -537,7 +530,8 @@ <h1 jhiTranslate="{{ pageTitle() }}"></h1>
[shouldTranslate]="true"
/>
} @else if (aiToggleSignal() && complianceCount() > 0) {
<div tabindex="0" (click)="handleMessageClick($event)" (keydown.enter)="handleMessageClick($event)">
<!-- Delegates for the link inside the translated message, which is the actual control and carries its own tabindex. -->
<div role="presentation" (click)="handleMessageClick($event)" (keydown.enter)="handleMessageClick($event)">
<jhi-message
[severity]="hasCriticalCompliance() ? 'error' : 'warn'"
classStyling="py-1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import {
ImageUploadError,
} from 'app/shared/components/atoms/image-upload-button/image-upload-button.component';
import { CheckboxComponent } from 'app/shared/components/atoms/checkbox/checkbox.component';
import { ClickableDirective } from 'app/shared/directives/clickable.directive';
import {
JobFormDTOFundingTypeEnum,
JobFormDTOLocationEnum,
Expand Down Expand Up @@ -126,6 +127,7 @@ const DEFAULT_RECOMMENDATION_TYPE_OPTION =
CompliancePopoverComponent,
TooltipModule,
SavingBadgeComponent,
ClickableDirective,
],
providers: [JobResourceApi],
})
Expand Down
Comment thread
Cathy0123456789 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
<div
class="group rounded-lg border border-border-default bg-background-default hover:scale-[1.02] hover:bg-background-surface focus-within:ring-2 focus-within:ring-primary focus-within:outline-none transition-all duration-200 overflow-hidden cursor-pointer w-full h-full max-h-[26rem] flex flex-col"
tabindex="0"
role="button"
<a
[routerLink]="detailLink()"
[attr.aria-label]="'jobOverviewPage.ariaLabels.viewJobDetails' | translate: { title: jobTitle() }"
(click)="onViewDetails()"
(keydown)="onKeyDown($event)"
class="group rounded-lg border border-border-default bg-background-default hover:scale-[1.02] hover:bg-background-surface focus-within:ring-2 focus-within:ring-primary focus-within:outline-none transition-all duration-200 overflow-hidden cursor-pointer w-full h-full max-h-[26rem] flex flex-col no-underline text-inherit"
>
<div
class="h-32 px-4 py-3 bg-cover bg-center flex flex-shrink-0 flex-col"
Expand Down Expand Up @@ -98,4 +95,4 @@ <h3 class="text-lg font-semibold line-clamp-2 leading-snug mb-2" [title]="jobTit
}
</div>
</div>
</div>
</a>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, computed, inject, input } from '@angular/core';
import { toSignal } from '@angular/core/rxjs-interop';
import { Router } from '@angular/router';
import { RouterLink } from '@angular/router';
import { CardModule } from 'primeng/card';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { TooltipModule } from 'primeng/tooltip';
Expand Down Expand Up @@ -31,6 +31,7 @@ export const ApplicationStatusExtended = {
LocalizedDatePipe,
UserAvatarComponent,
TagComponent,
RouterLink,
],
})
export class JobCardComponent {
Expand Down Expand Up @@ -59,6 +60,8 @@ export class JobCardComponent {

currentLang = toSignal(this.translate.onLangChange);

readonly detailLink = computed(() => `/job/detail/${this.jobId()}`);

readonly formattedWorkload = computed(() => {
const workloadValue = this.workload();
if (workloadValue === undefined) {
Expand Down Expand Up @@ -88,17 +91,4 @@ export class JobCardComponent {
const state = this.applicationState();
return state !== ApplicationStatusExtended.NotYetApplied && state !== JobCardDTOApplicationStateEnum.Saved;
});

private router = inject(Router);

onViewDetails(): void {
void this.router.navigate([`/job/detail/${this.jobId()}`]);
}

onKeyDown(event: KeyboardEvent): void {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
this.onViewDetails();
}
}
}
31 changes: 5 additions & 26 deletions src/main/webapp/app/layouts/footer/footer.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,31 +35,10 @@
}

<div class="flex ml-auto pr-4 gap-[0.3rem] max-[600px]:px-2 max-[600px]:ml-0! max-[600px]:pr-0!">
<p
(click)="navigateToImprint()"
(keydown.enter)="navigateToImprint()"
class="inline-flex cursor-pointer text-primary hover:underline"
jhiTranslate="footer.imprint"
tabindex="0"
role="button"
></p>
<span>|</span>
<p
(click)="navigateToPrivacy()"
(keydown.enter)="navigateToPrivacy()"
class="inline-flex cursor-pointer text-primary hover:underline"
jhiTranslate="footer.privacy"
tabindex="0"
role="button"
></p>
<span>|</span>
<p
(click)="navigateToAboutUs()"
(keydown.enter)="navigateToAboutUs()"
class="inline-flex cursor-pointer text-primary hover:underline"
jhiTranslate="footer.about-us"
tabindex="0"
role="button"
></p>
<a routerLink="/imprint" class="inline-flex cursor-pointer text-primary hover:underline" jhiTranslate="footer.imprint"></a>
<span class="divider">|</span>
<a routerLink="/privacy" class="inline-flex cursor-pointer text-primary hover:underline" jhiTranslate="footer.privacy"></a>
<span class="divider">|</span>
<a routerLink="/about-us" class="inline-flex cursor-pointer text-primary hover:underline" jhiTranslate="footer.about-us"></a>
</div>
</div>
20 changes: 3 additions & 17 deletions src/main/webapp/app/layouts/footer/footer.component.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Component, ViewEncapsulation, inject } from '@angular/core';
import { DatePipe } from '@angular/common';
import { Router } from '@angular/router';
import { RouterLink } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
import { VERSION } from 'app/app.constants';
import { hasText } from 'app/shared/util/text.util';
Expand All @@ -13,34 +13,20 @@ import { GitInfo } from '../profiles/profile-info.model';
selector: 'jhi-footer',
standalone: true,
templateUrl: './footer.component.html',
imports: [DatePipe, TranslateDirective],
imports: [DatePipe, TranslateDirective, RouterLink],
encapsulation: ViewEncapsulation.None,
})
export default class FooterComponent {
version: string;
readonly version = VERSION;

protected profileInfo;

private router = inject(Router);
private profileService = inject(ProfileService);

constructor() {
this.version = VERSION;
this.profileInfo = toSignal(this.profileService.getProfileInfo());
}

navigateToImprint(): void {
void this.router.navigate(['/imprint']);
}

navigateToPrivacy(): void {
void this.router.navigate(['/privacy']);
}

navigateToAboutUs(): void {
void this.router.navigate(['/about-us']);
}

protected get gitInfo(): GitInfo | undefined {
const info = this.profileInfo();
return hasText(info?.ribbonEnv) && info.gitInfo ? info.gitInfo : undefined;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div [class]="containerClasses()" tabindex="0" role="button" (click)="fileInput.click()" (keydown.enter)="fileInput.click()">
<button type="button" [class]="'btn-bare ' + containerClasses()" (click)="fileInput.click()">
<input type="file" [accept]="acceptedImageTypes()" (change)="onImageSelected($event)" #fileInput class="hidden" />
<div [class]="innerClasses()">
@if (isUploading()) {
Expand All @@ -7,4 +7,4 @@
<fa-icon [icon]="['fas', 'plus']" size="3x" class="text-primary" />
}
</div>
</div>
</button>
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ export class ImageUploadButtonComponent {
});

readonly containerClasses = computed(() => {
const base = 'relative rounded-lg transition-all';
// A button is inline-block and would shrink to its icon, so it is made to fill its grid cell like a div would.
const base = 'block w-full relative rounded-lg transition-all';

if (this.isUploading()) {
return `${base} opacity-50 pointer-events-none`;
Expand Down
Loading
Loading