Skip to content

Commit 5e7c557

Browse files
authored
Merge pull request #58 from chytanka/develop
feat: update version to 0.13.58 and enhance viewer functionality
2 parents 5baba41 + e11337a commit 5e7c557

20 files changed

Lines changed: 217 additions & 59 deletions

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "chytanka",
3-
"version": "0.13.56",
3+
"version": "0.13.58",
44
"scripts": {
55
"ng": "ng",
66
"start": "ng serve",

src/app/@site-modules/@common-read/utils/read-base-component.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ export abstract class ReadBaseComponent {
2222
constructor() {
2323
this.route.pathFromRoot[0].queryParams.subscribe(q => {
2424
const vm = q['vm'] // view mode param
25-
this.viewerService.setViewModeOptionByCode(vm)
25+
26+
if(vm && vm !== this.viewerService.viewModeOption().code)
27+
this.viewerService.setViewModeOptionByCode(vm)
2628

2729
const pl = q['list'] // playlist
2830

@@ -32,7 +34,7 @@ export abstract class ReadBaseComponent {
3234
this.playlistService.resetPlaylist();
3335

3436
this.plObserv = this.playlistService.getPlaylist(pl).subscribe(data => {
35-
if (!isPlaylist) return;
37+
if (!isPlaylist(data)) return;
3638

3739
this.playlistService.setPlaylist(data)
3840
})

src/app/core/facades/language-facade.service.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export class LanguageFacadeService {
1515
route.queryParams.subscribe(q => {
1616
const l = q['lang'];
1717

18+
if (l == this.lang.lang()) return;
19+
1820
if (l) this.lang.setLang(l);
1921
if (l && this.lang.manifests.has(l)) {
2022
this.lang.updateManifest();

src/app/shared/shared.module.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ import { SourceCopyrightComponent } from './ui/source-copyright/source-copyright
3131
import { SourceCopyrightLogoComponent } from './ui/source-copyright-logo/source-copyright-logo.component';
3232
import { SloganComponent } from './ui/slogan/slogan.component';
3333
import { ToggleBarComponent } from './ui/toggle-bar/toggle-bar.component';
34+
import { SvgTextBoxComponent } from './ui/svg-text-box/svg-text-box.component';
3435

35-
const components = [GamepadCursorComponent, TruncatePipe, TextEmbracerComponent, OverlayComponent, ViewModeBarComponent, MadeInUkraineComponent, DialogComponent, LangToggleComponent, TitleCardComponent, LoadingComponent, SeparatorComponent, FileChangeComponent, ChytankaLogoWithTagsComponent, FileSizePipe, VibrateHapticDirective, SircleBlurComponent, DropZoneComponent, SourceCopyrightComponent, SourceCopyrightLogoComponent, SloganComponent, NsfwWarningComponent, ImgMetaDirective, NewTabDirective, PagesIndicatorComponent, WarmFilterComponent, WarmControlComponent, ToggleBarComponent]
36+
const components = [GamepadCursorComponent, TruncatePipe, TextEmbracerComponent, OverlayComponent, ViewModeBarComponent, MadeInUkraineComponent, DialogComponent, LangToggleComponent, TitleCardComponent, LoadingComponent, SeparatorComponent, FileChangeComponent, ChytankaLogoWithTagsComponent, FileSizePipe, VibrateHapticDirective, SircleBlurComponent, DropZoneComponent, SourceCopyrightComponent, SourceCopyrightLogoComponent, SloganComponent, NsfwWarningComponent, ImgMetaDirective, NewTabDirective, PagesIndicatorComponent, WarmFilterComponent, WarmControlComponent, ToggleBarComponent, SvgTextBoxComponent]
3637

3738
@NgModule({
3839
declarations: [...components],
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<svg dir="ltr" frame="1" [attr.viewBox]="viewBox()" [style.maxWidth]="maxWidth()">
2+
3+
<text #textEl fill="currentColor" [attr.font-size]="fontSize()" text-anchor="middle">
4+
@if(link().length > 0) {
5+
<a [routerLink]="link()" [queryParams]="params()">
6+
@for (line of lines(); track $index) {
7+
<tspan x="50%" [attr.y]="getTspanY($index)">{{ line }}</tspan>
8+
}
9+
</a>
10+
} @else {
11+
@for (line of lines(); track $index) {
12+
<tspan x="50%" [attr.y]="getTspanY($index)">{{ line }}</tspan>
13+
}
14+
}
15+
</text>
16+
17+
</svg>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
:host {
2+
font-family: monospace;
3+
}
4+
5+
svg {
6+
display: block;
7+
width: 100%;
8+
height: 100%;
9+
10+
text {
11+
text-anchor: middle;
12+
font-family: inherit;
13+
direction: ltr;
14+
text-transform: uppercase;
15+
}
16+
}
17+
18+
:host.bubble {
19+
svg {
20+
background-color: white;
21+
border: 1px solid black;
22+
border-radius: 2px;
23+
}
24+
25+
&.info {
26+
svg {
27+
background-color: #f0e8e0;
28+
}
29+
}
30+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { AfterViewInit, Component, computed, ElementRef, input, signal, ViewChild } from '@angular/core';
2+
3+
@Component({
4+
selector: 'svg-text-box',
5+
standalone: false,
6+
7+
templateUrl: './svg-text-box.component.html',
8+
styleUrl: './svg-text-box.component.scss'
9+
})
10+
export class SvgTextBoxComponent implements AfterViewInit {
11+
12+
link = input<string | any[]>("");
13+
params = input<any>({});
14+
15+
box = signal({ x: 0, y: 0, width: 0, height: 0 });
16+
17+
viewBox = computed(() => {
18+
const box = this.box();
19+
return `0 0 ${box.width} ${box.height}`;
20+
});
21+
22+
maxWidth = computed(() => this.box().width + 'px');
23+
24+
ngAfterViewInit(): void {
25+
queueMicrotask(() => this.updateBox());
26+
}
27+
28+
updateBox() {
29+
const bbox = this.textEl.nativeElement.getBBox();
30+
this.box.set({
31+
x: bbox.x - this.padding(),
32+
y: bbox.y - this.padding(),
33+
width: bbox.width + this.padding() * 2,
34+
height: bbox.height + this.padding() * 2
35+
});
36+
}
37+
38+
@ViewChild('textEl', { static: true }) textEl!: ElementRef<SVGTextElement>;
39+
40+
lines = input<string[]>([]);
41+
42+
fontSize = input<number>(14);
43+
width = input<number>(280);
44+
padding = input<number>(10);
45+
lineHeightRatio = input<number>(1.15);
46+
47+
48+
protected getTspanY(index: number): string {
49+
const lineHeight = this.fontSize() * this.lineHeightRatio();
50+
51+
return `${lineHeight * index + this.fontSize() + this.padding()}`;
52+
}
53+
}

src/app/shared/utils/phrases.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ export class Phrases {
7676
softMode = "Soft mode"
7777
baseSettings = "Base settings"
7878
fileSettings = "File settings"
79+
viewModeChangeHint = "You can change the reading orientation in the top right corner"
80+
showHidePanelHint = "Tap 👆 anywhere to toggle the panel"
81+
keyboardHorNavigationHint = "for navigation: ⬅️➡️ or AD"
82+
keyboardVerNavigationHint = "for navigation: ⬆️⬇️ or WS"
83+
keyboardFullscreenHint = "Toggle fullscreen: F"
84+
keyboardShareHint = "Share link: Ctrl+E"
85+
keyboardPlaylistHint = "Open playlist: Ctrl+P"
86+
keyboardDownloadHint = "Download for offline reading: Ctrl+S"
7987
getByKey = (key: string) => (Object.keys(this).includes(key)) ? this[key as keyof Phrases] : null;
8088

8189
static getTemplate(phrase: string, value: string) {
Lines changed: 23 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,39 @@
1+
@let ph = lang.ph();
12
<manga-page [dir]="viewer.viewModeOption().dir" style="margin: auto 0;">
2-
<svg dir="ltr" frame="3" viewBox="0 0 300 200">
3-
<text x="50%" y="42%" font-size="28" style="font-family:'Troubleside'">
4-
{{lang.ph().getByKey(viewer.viewModeOption().hintPhraceKey)}}
5-
</text>
6-
<text x="50%" y="58%" font-size="24">{{viewer.viewModeOption().emoji}}</text>
7-
</svg>
83

9-
<svg dir="ltr" frame="1" viewBox="0 0 280 280">
10-
<rect x="20" y="80" width="240" height="120" rx="4" stroke-width="2" fill="white" stroke="black" />
11-
<text fill="currentColor" font-size="14">
12-
<tspan x="50%" y="38%">Тицьни 👆</tspan>
13-
<tspan x="50%" y="46%">у будь-якому місці,</tspan>
14-
<tspan x="50%" y="54%">щоб показати/приховати</tspan>
15-
<tspan x="50%" y="62%">панень</tspan>
16-
</text>
17-
</svg>
4+
<svg-text-box dir="ltr" style="font-family:'Troubleside'" frame="3" [fontSize]="32" [lines]="[
5+
ph.getByKey(viewer.viewModeOption().hintPhraceKey) + '',
6+
viewer.viewModeOption().emoji
7+
]" />
188

9+
@let viewModeChangeHint = splitPhrase(ph.viewModeChangeHint);
1910
<svg dir="ltr" frame="3" class="abs" viewBox="0 0 200 150">
2011
<text class="hand-text" fill="currentColor" font-size="11">
21-
<tspan x="50%" y="38%">Вгорі справа можна змінити</tspan>
22-
<tspan x="50%" y="48%">орієнтацію читання</tspan>
12+
<tspan x="50%" y="38%">{{viewModeChangeHint[0]}}</tspan>
13+
<tspan x="50%" y="48%">{{viewModeChangeHint[1]}}</tspan>
2314
</text>
2415
</svg>
2516

26-
<svg dir="ltr" frame="2" viewBox="0 0 320 320">
27-
<rect x="-20" y="85" width="360" height="150" rx="4" stroke-width="2" fill="white" stroke="black"></rect>
28-
<text fill="currentColor" font-size="14">
29-
<tspan x="50%" y="34%">для навігації: ⬅➡ або ad</tspan>
30-
<tspan x="50%" y="42%">Fullscreen: f</tspan>
31-
<tspan x="50%" y="50%">Поділитися посиланням: Ctrl+E</tspan>
32-
<tspan x="50%" y="58%">Відкрити список епізодів: Ctrl+P</tspan>
33-
<tspan x="50%" y="66%">Скачати для перегляду офлайн: Ctrl+S</tspan>
34-
</text>
35-
</svg>
17+
@let showHidePanelHint = splitPhrase(ph.showHidePanelHint, 3);
18+
<svg-text-box class="bubble" dir="ltr" frame="1" [lines]="showHidePanelHint" />
19+
<svg-text-box class="bubble" dir="ltr" frame="2" [lines]="[
20+
viewer.viewModeOption().mode === 'pages' ? ph.keyboardHorNavigationHint : ph.keyboardVerNavigationHint,
21+
ph.keyboardFullscreenHint,
22+
ph.keyboardShareHint,
23+
ph.keyboardPlaylistHint,
24+
25+
]" />
26+
<!-- ph.keyboardDownloadHint -->
3627

3728
<img frame="4" style="display: block;" src="/assets/icons/chtnk.svg" alt="Chytanka logo">
3829

3930
<div dir="ltr" frame="5">
4031
@if (getPrevIndex() >=0 && playlist()[getPrevIndex()]; as prev) {
41-
<a dir="ltr" [routerLink]="['/', prev.site, prev.id]"
42-
[queryParams]="{lang: lang.lang(), list: playlistLink, vm: viewer.viewModeOption().code}">
43-
{{prev.title??
44-
lang.ph().untitled + ' ' + (getPrevIndex() + 1)}}</a>
32+
@let label = '⏪' + (prev.title ?? ph.untitled) + ' ' + (getPrevIndex() + 1);
33+
@let routerLink = ['/', prev.site, prev.id];
34+
@let queryParams = {lang: lang.lang(), list: playlistLink(), vm: viewer.viewModeOption().code};
35+
<svg-text-box class="bubble" dir="ltr" frame="1" [lines]="[label]" [link]="routerLink" [params]="queryParams" />
4536
}
4637
</div>
4738

48-
</manga-page>
39+
</manga-page>

src/app/viewer/viewer/components/hint-page/hint-page.component.scss

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
11
:host {
22
&.long {
33
manga-page {
4+
--page-ratio: 10 / 16;
45
max-height: unset;
56
width: 100%;
67
}
78
}
89
}
910

11+
svg-text-box {
12+
display: grid;
13+
place-content: center;
14+
width: 100%;
15+
height: 100%;
16+
padding: 1ch;
17+
}
18+
1019
svg {
1120
display: block;
1221
width: 100%;
1322
height: 100%;
1423

1524
text {
1625
text-anchor: middle;
17-
font-family: monospace;
26+
font-family: monospace;
1827
direction: ltr;
1928
text-transform: uppercase;
2029
}

0 commit comments

Comments
 (0)