Fix Skip to Main Content Button
This commit is contained in:
1 parent
f343f3e977
commit
214dfb498e
10 files changed
+60
-13
No files matched your search
+2
-2
@@ -1,10 +1,10 @@
|
||||
<skip-links ngSkipHydration>
|
||||
<a href="#main-content">{{ translation.common.skipToContent }}</a>
|
||||
<button (click)="skipToContent()">{{ translation.common.skipToContent }}</button>
|
||||
</skip-links>
|
||||
|
||||
<header-menu></header-menu>
|
||||
|
||||
<main id="main-content">
|
||||
<main #content>
|
||||
<router-outlet />
|
||||
</main>
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
main:focus-visible {
|
||||
outline: none;
|
||||
}
|
||||
+10
-1
@@ -1,4 +1,4 @@
|
||||
import { Component, inject, effect, PLATFORM_ID } from '@angular/core';
|
||||
import { Component, inject, effect, PLATFORM_ID, ElementRef, viewChild } from '@angular/core';
|
||||
import { RouterOutlet } from '@angular/router';
|
||||
import { HeaderMenu } from './features/header-menu/header-menu';
|
||||
import { PopupService } from './services/popup.service';
|
||||
@@ -19,6 +19,8 @@ export class App {
|
||||
protected translation = inject(TranslationService).translation;
|
||||
private platformID = inject(PLATFORM_ID);
|
||||
|
||||
private contentElement = viewChild<ElementRef<HTMLElement>>("content");
|
||||
|
||||
private document = inject(DOCUMENT);
|
||||
private rootHtmlElement!: HTMLElement;
|
||||
|
||||
@@ -50,4 +52,11 @@ export class App {
|
||||
const reduceMotion = this.settingsService.reduceAnimation();
|
||||
this.rootHtmlElement.classList.toggle('reduce-motion', reduceMotion);
|
||||
}
|
||||
|
||||
skipToContent() {
|
||||
this.contentElement()!.nativeElement.tabIndex = 0;
|
||||
this.contentElement()!.nativeElement.focus();
|
||||
|
||||
this.contentElement()!.nativeElement.tabIndex = -1;
|
||||
}
|
||||
}
|
||||
@@ -13,10 +13,10 @@
|
||||
</section>
|
||||
|
||||
<section class="buttons">
|
||||
<button>
|
||||
<button [aria-label]="translation.common.preview">
|
||||
<div class="material-symbols-outlined icon-40 button-icon">play_arrow</div>
|
||||
</button>
|
||||
<button>
|
||||
<button [aria-label]="translation.common.download">
|
||||
<div class="material-symbols-outlined icon-40 button-icon">download</div>
|
||||
</button>
|
||||
</section>
|
||||
@@ -21,14 +21,17 @@ $default_animation_duration: 0.2s;
|
||||
outline: light-dark(oklch(0 0 0 / 20%), oklch(1 0 0 / 20%)) 2px solid;
|
||||
overflow: hidden;
|
||||
|
||||
&:focus-visible {
|
||||
outline-offset: 0;
|
||||
outline: 2px solid var(--selection-outline-color);
|
||||
}
|
||||
|
||||
section.information {
|
||||
width: calc(100% - 64px);
|
||||
padding: 12px;
|
||||
box-sizing: border-box;
|
||||
flex-shrink: 0;
|
||||
|
||||
border-radius: 8px;
|
||||
|
||||
z-index: 1;
|
||||
background-color: light-dark(white, black);
|
||||
|
||||
@@ -103,7 +106,7 @@ $default_animation_duration: 0.2s;
|
||||
flex-shrink: 0;
|
||||
|
||||
flex-grow: 1;
|
||||
margin-left: -80px;
|
||||
margin-left: 0;
|
||||
|
||||
button {
|
||||
display: flex;
|
||||
@@ -127,12 +130,24 @@ $default_animation_duration: 0.2s;
|
||||
--hover-state: 1;
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline-offset: -2px;
|
||||
}
|
||||
|
||||
div.button-icon {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-right: 12px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
border-top-right-radius: 8px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
border-bottom-right-radius: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,21 @@
|
||||
import { Component, computed, input } from '@angular/core';
|
||||
import { Component, computed, inject, input } from '@angular/core';
|
||||
import { TranslationService } from '../../services/translation.service';
|
||||
|
||||
@Component({
|
||||
selector: 'level-card',
|
||||
imports: [],
|
||||
templateUrl: './level-card.html',
|
||||
styleUrl: './level-card.scss',
|
||||
host: {
|
||||
tabindex: '0',
|
||||
},
|
||||
})
|
||||
export class LevelCard {
|
||||
artist = input.required<string>()
|
||||
trackName = input.required<string>()
|
||||
protected translation = inject(TranslationService).translation;
|
||||
|
||||
artist = input.required<string>();
|
||||
trackName = input.required<string>();
|
||||
creator = input<string[]>([]);
|
||||
|
||||
creatorString = computed(() => this.creator().join(" & "));
|
||||
creatorString = computed(() => this.creator().join(' & '));
|
||||
}
|
||||
@@ -30,11 +30,19 @@ $default_animation_duration: 0.4s;
|
||||
outline: 2px solid var(--selection-outline-color);
|
||||
}
|
||||
|
||||
::ng-deep a {
|
||||
::ng-deep * {
|
||||
appearance: none;
|
||||
color: light-dark(black, white);
|
||||
text-decoration: none;
|
||||
background: none;
|
||||
font: inherit;
|
||||
|
||||
border: none;
|
||||
outline: none;
|
||||
min-width: unset;
|
||||
min-height: unset;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 0;
|
||||
|
||||
opacity: 0;
|
||||
|
||||
@@ -22,6 +22,8 @@ export const EN = {
|
||||
close: 'Close',
|
||||
save: 'Save',
|
||||
skipToContent: 'Skip to main content',
|
||||
preview: 'Soundtrack Preview',
|
||||
download: 'Download',
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -24,5 +24,7 @@ export const JP: Translation = {
|
||||
close: '閉じる',
|
||||
save: '保存',
|
||||
skipToContent: '本文へスキップ',
|
||||
preview: '楽曲プレビュー',
|
||||
download: 'ダウンロード',
|
||||
},
|
||||
};
|
||||
@@ -24,5 +24,7 @@ export const KR: Translation = {
|
||||
close: '닫기',
|
||||
save: '저장',
|
||||
skipToContent: '본문으로 건너뛰기',
|
||||
preview: '곡 프리뷰',
|
||||
download: '다운로드',
|
||||
},
|
||||
};
|
||||
Reference in new issue
Block a user