Skip to content

Commit f8d7035

Browse files
committed
Make url dynamic and state-synced
1 parent ef63296 commit f8d7035

File tree

8 files changed

+144
-52
lines changed

8 files changed

+144
-52
lines changed

components/OptionPanel.vue

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
const settings = useSettingsStore();
33
const sources = useSourcesStore();
4+
const progress = useProgressStore();
45
</script>
56

67
<template>
@@ -28,12 +29,16 @@ const sources = useSourcesStore();
2829
:class="settings.showPanel ? 'left-[0.5rem]' : 'right-[0.5rem]'"
2930
/>
3031
</div>
31-
<header class="flex h-12 w-full align-middle">
32-
<IconButton icon="i-[ic--round-close]" class="p-2" />
33-
<h1 class="flex-1 p-3 text-center">
34-
<a class="hover:underline" href="#">Example Title</a>
32+
<header class="flex min-h-12 w-full align-middle">
33+
<div class="h-12">
34+
<IconButton icon="i-[ic--round-close]" class="p-2" />
35+
</div>
36+
<h1 class="flex h-max p-3 text-center">
37+
<a class="text-balance break-words text-lg hover:underline" href="#">{{
38+
progress.title
39+
}}</a>
3540
</h1>
36-
<div class="h-12 w-12"></div>
41+
<div class="h-12 w-12 flex-none"></div>
3742
</header>
3843
<div class="flex h-8 w-full items-center justify-end gap-1 px-2 py-1.5">
3944
<IconButton icon="i-[mdi--share-variant-outline]" />
@@ -42,7 +47,7 @@ const sources = useSourcesStore();
4247
class="flex h-12 w-full justify-between bg-neutral-900 p-2.5 text-center align-middle"
4348
>
4449
<IconButton icon="i-[iconamoon--arrow-left-2]" />
45-
<p>Chapter 1</p>
50+
<p>Chapter {{ progress.chapter }}</p>
4651
<IconButton icon="i-[iconamoon--arrow-right-2]" />
4752
</div>
4853
<div class="flex h-8 w-full justify-end gap-1 py-1.5 align-middle">

components/PageSelector.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ const currentPage = defineModel<number>();
1111
>
1212
<span
1313
class="pointer-events-none absolute right-1/2 z-10 self-center align-middle text-sm font-bold text-white"
14-
>{{ (currentPage ?? 0) + 1 }}/{{ sources.current.pageCount }}</span
14+
>{{ currentPage ?? 1 }}/{{ sources.current.pageCount }}</span
1515
>
1616
<template v-for="n in sources.current.pageCount">
1717
<div
1818
@click="
1919
() => {
20-
currentPage = sources.current.pageCount - n;
20+
currentPage = sources.current.pageCount - n + 1;
2121
}
2222
"
2323
class="relative flex h-8 grow items-end hover:bottom-1"
2424
:class="[
2525
{
2626
[tw`bg-gradient-to-t from-white`]:
27-
sources.current.pageCount - n == currentPage,
27+
sources.current.pageCount - n + 1 == currentPage,
2828
},
2929
]"
3030
>

components/Reader.vue

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,11 @@
11
<script setup lang="ts">
22
const settings = useSettingsStore();
3+
const progress = useProgressStore();
34
const sources = useSourcesStore();
45
5-
const currentPage = ref(0);
6-
7-
watchEffect(() => {
8-
if (currentPage.value < 0) currentPage.value = 0;
9-
if (currentPage.value >= sources.current.pageCount) {
10-
currentPage.value = sources.current.pageCount - 1;
11-
}
12-
});
13-
146
const currentImageSrc = computed(() => {
157
if (sources.current) {
16-
return sources.getPage(sources.currentSourceId!, currentPage.value);
8+
return sources.getPage(sources.currentSourceId!, progress.page);
179
}
1810
});
1911
@@ -43,18 +35,18 @@ function onClick(e: MouseEvent) {
4335
let rem = parseFloat(getComputedStyle(document.documentElement).fontSize);
4436
let calc = w / 2 - e.offsetX;
4537
if (Math.abs(calc) > 2 * rem) {
46-
currentPage.value += calc > 0 ? 1 : -1;
38+
progress.page += calc > 0 ? 1 : -1;
4739
}
4840
}
4941
5042
onMounted(() => {
5143
document.addEventListener("keydown", function (event) {
5244
switch (event.key) {
5345
case "ArrowLeft":
54-
currentPage.value++;
46+
progress.page++;
5547
break;
5648
case "ArrowRight":
57-
currentPage.value--;
49+
progress.page--;
5850
break;
5951
case "j":
6052
sources.changeSource();
@@ -68,7 +60,7 @@ onMounted(() => {
6860
@click="onClick"
6961
class="max-w-screen align-start relative flex h-screen grow select-none bg-black"
7062
>
71-
<PageSelector v-model="currentPage" />
63+
<PageSelector v-model="progress.page" />
7264
<div class="h-full w-full overflow-y-auto">
7365
<img :src="currentImageSrc" :class="['m-auto', pageFitImageClass]" />
7466
</div>

pages/read.vue

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<script async setup lang="ts">
2+
import { isClient } from "@vueuse/core";
3+
4+
const route = useRoute();
5+
const router = useRouter();
6+
const sources = useSourcesStore();
7+
const progress = useProgressStore();
8+
9+
if (typeof route.query.src == "string") {
10+
await sources.setup(route.query.src);
11+
}
12+
13+
function updateUrl() {
14+
const newUrl = router.resolve({
15+
name: "read-title-chapter-page",
16+
params: {
17+
title: progress.title.replace(/ /g, "_"),
18+
chapter: progress.chapter,
19+
page: progress.page,
20+
},
21+
query: { ...route.query, sid: sources.currentSourceId },
22+
});
23+
if (typeof newUrl.fullPath == "string")
24+
window.history.replaceState(null, "", newUrl.fullPath);
25+
}
26+
if (typeof route.query.sid == "string") {
27+
let sid = parseInt(route.query.sid);
28+
if (sid) sources.changeSource(sid);
29+
}
30+
progress.setTitle(route.params.title);
31+
progress.setChapter(route.params.chapter);
32+
progress.setPage(route.params.page);
33+
if (isClient) updateUrl();
34+
35+
useHead({
36+
title: progress.status,
37+
});
38+
39+
watch(
40+
[
41+
() => progress.title,
42+
() => progress.chapter,
43+
() => progress.page,
44+
() => sources.currentSourceId,
45+
],
46+
updateUrl
47+
);
48+
</script>
49+
50+
<template>
51+
<div class="max-w-screen flex min-h-screen flex-col md:flex-row">
52+
<OptionPanel />
53+
<Reader></Reader>
54+
</div>
55+
</template>

stores/progress.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
export const useProgressStore = defineStore("progressStore", () => {
2+
const sources = useSourcesStore();
3+
4+
const title = ref("Unknown");
5+
const chapter = ref(1);
6+
const page = ref(1);
7+
const source = toRef(sources.currentSourceId);
8+
9+
function setSource(value: any) {
10+
value = parseInt(value);
11+
source.value = value ? value : 0;
12+
}
13+
14+
function setTitle(value: any) {
15+
let t = typeof value == "string" ? value : "Unknown";
16+
t = t.replace(/_/g, " ");
17+
title.value = t;
18+
}
19+
20+
function setChapter(value: any) {
21+
value = parseInt(value);
22+
chapter.value = value ? value : 1;
23+
}
24+
25+
function setPage(value: any) {
26+
value = parseInt(value);
27+
page.value = value ? clamp(value, 0, sources.current.pageCount) : 1;
28+
}
29+
30+
watchEffect(() => {
31+
if (page.value <= 1) page.value = 1;
32+
if (page.value >= sources.current.pageCount) {
33+
page.value = sources.current.pageCount;
34+
}
35+
});
36+
37+
const status = computed(() => {
38+
return `${title.value} - Chapter ${chapter.value}`;
39+
});
40+
41+
return {
42+
source,
43+
title,
44+
chapter,
45+
page,
46+
47+
setSource,
48+
setTitle,
49+
setChapter,
50+
setPage,
51+
52+
status,
53+
};
54+
});

stores/sources.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,15 @@ interface MangaSource {
99
export const useSourcesStore = defineStore("sourcesStore", {
1010
state: () => ({
1111
_sourceList: [] as Array<MangaSource>,
12-
currentSourceId: undefined as number | undefined,
12+
currentSourceId: 0,
1313
loadedUrls: new Set([]) as Set<string>,
1414
_loadedIds: [] as Array<Array<number>>,
1515
}),
1616
getters: {
1717
current(state) {
1818
let source: MangaSource | undefined;
1919
let loadedPages: Array<number> | undefined;
20-
if (
21-
state._sourceList != undefined &&
22-
state.currentSourceId != undefined
23-
) {
20+
if (state._sourceList != undefined) {
2421
source = state._sourceList[state.currentSourceId];
2522
loadedPages = state._loadedIds[state.currentSourceId];
2623
}
@@ -39,10 +36,8 @@ export const useSourcesStore = defineStore("sourcesStore", {
3936
* @param index
4037
*/
4138
changeSource(index: number | undefined = undefined) {
42-
if (this.currentSourceId != undefined) {
43-
if (index == undefined) index = this.currentSourceId + 1;
44-
this.currentSourceId = index % this._sourceList.length;
45-
}
39+
if (index == undefined) index = this.currentSourceId + 1;
40+
this.currentSourceId = index % this._sourceList.length;
4641
},
4742
preloadImage(url: string, source: number, index: number) {
4843
return new Promise<void>((resolve) => {
@@ -109,14 +104,15 @@ export const useSourcesStore = defineStore("sourcesStore", {
109104

110105
this.currentSourceId = 0;
111106
},
112-
getPage(sourceId: number, pageId: number) {
107+
getPage(sourceId: number, page: number) {
108+
page = clamp(page - 1, 0);
113109
if (
114110
this._sourceList[sourceId] &&
115-
pageId < this._sourceList[sourceId].pages.length
111+
page < this._sourceList[sourceId].pages.length
116112
) {
117113
return (
118114
(this._sourceList[sourceId].pages_base ?? "") +
119-
this._sourceList[sourceId].pages[pageId]
115+
this._sourceList[sourceId].pages[page]
120116
);
121117
}
122118
},

utils/index.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
export function clamp(value: number, min: number, max: number) {
2-
max = Math.max(max - 1, 0); // Exclude last
3-
return Math.max(Math.min(value, min), max);
1+
export function clamp(value: number, min: number, max: number | null = null) {
2+
let ret = Math.max(value, min);
3+
if (max != null) {
4+
max = Math.max(max - 1, 0); // Exclude last
5+
ret = Math.min(ret, max);
6+
}
7+
return ret;
48
}

0 commit comments

Comments
 (0)