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