[Feature]
All checks were successful
Node.js CI / build-and-test (push) Successful in 25s

移除书签机制
更新了项目描述
增加对有章节作品阅读支持

[BugFix]
BetterHr 无法在 Markdown 显示的问题

[Base]
增加 Markdown 渲染锚点支持
This commit is contained in:
2025-05-18 13:33:39 +08:00
parent 9ef6da3efb
commit 4323acb4d6
13 changed files with 165 additions and 217 deletions

View File

@ -20,6 +20,7 @@ function convert(from) {
}
} else if (from.includes('https://archiveofourown.org/works/')) {
const sid = from.split('https://archiveofourown.org/works/')[1];
console.log(sid)
if ( sid ) {
const id = Number(sid)
if (id) {
@ -27,17 +28,24 @@ function convert(from) {
type: 's',
id
}
} else {
const splited = sid.split('/chapters/')
const id = Number(splited[0])
const cid = Number(splited[1])
if (id && cid) {
return {
type: 'c',
id, cid
}
}
}
}
}
return {
type: null,
}
return { type: null }
}
function onConvert(data) {
const { type, id, cid } = convert(data.src)
console.log(type, id, cid)
if (type == null) {
err.value = true
srcText.value?.focus()

View File

@ -10,11 +10,8 @@ const workReadState = useWorkReadState()
import { useRouteStore } from '@/stores/route.js'
const routeState = useRouteStore()
import { useBookmarkStore } from '../stores/db.js'
import 'mdui/components/list.js'
import 'mdui/components/list-item.js'
import 'mdui/components/dialog.js'
import 'mdui/components/divider.js'
import 'mdui/components/linear-progress.js'
import 'mdui/components/fab.js'
@ -37,16 +34,11 @@ import { mduiSnackbar } from '../utils.js'
const fabExtended = ref(false)
const content = ref(null)
const readPercent = ref(0)
const bookmarkDialog = ref(null)
const bookmarks = ref([])
const bookmarkMenu = ref(false)
const bookmarkSelect = ref(null)
let readIndex = 0
let lastPercent = 0
let lastCloseTimer = null
let isObserver = null
let bookmarkStore = null
let paragraphs = []
let currentParagraph = null
@ -56,100 +48,22 @@ const categoryName = {
fm: '女/男'
}
async function addBookmark() {
if (currentParagraph) {
const id = await bookmarkStore.add(workReadState.id, readIndex, currentParagraph.textContent.slice(0,20), '')
bookmarks.value.push(await bookmarkStore.get(id))
snackbar({
message: `在第 ${readIndex} 段 (${readPercent.value}%) 处新建了一个书签`,
action: "编辑",
onActionClick: () => {
prompt({
headline: "修改书签",
description: "新名字:",
confirmText: "完成",
cancelText: "算了",
onConfirm: (value) => {
bookmarkStore.updateName(id, value)
bookmarks.value[bookmarks.value.length - 1].name = value
}
});
}})
}
}
async function jumpTo(index) {
const value = bookmarks.value[index].index
const target = paragraphs[value]
bookmarkDialog.value.open = false
await nextTick()
if (target) {
target.scrollIntoView({
behavior: 'smooth',
block: 'end',
inline: 'nearest'
})
}
}
async function delAllBookmark() {
confirm({
headline: '警告',
description: '这会清空所有书签! 不可恢复!',
confirmText: '我明白',
cancelText: '算了',
closeOnOverlayClick: true,
closeOnEsc: true,
onConfirm: () => {
bookmarkStore.delByWork(workReadState.id)
bookmarks.value = []
mduiSnackbar('书签清空辣!')
},
})
}
async function editBookmark() {
prompt({
headline: "修改书签",
description: "新名字:",
confirmText: "完成",
cancelText: "算了",
onConfirm: (value) => {
bookmarkStore.updateName(bookmarkSelect.value.bk.id, value)
bookmarks.value[bookmarkSelect.value.index].name = value
}
});
}
function openBookmarkMenu(bk, index) {
bookmarkSelect.value = { bk, index };
bookmarkMenu.value.open = true
}
async function deleteBookmark() {
if (bookmarkSelect.value) {
bookmarkStore.del(bookmarkSelect.value.bk.id)
bookmarks.value.splice(bookmarkSelect.value.index,1)
bookmarkSelect.value = null
}
}
onServerPrefetch(async () => {
await workReadState.loadWork(route.params.id)
await workReadState.loadWork(route.params.id, route.params.cid)
})
onMounted(async () => {
bookmarkStore = useBookmarkStore()
if (workReadState.state != 'ssrnotfound') await workReadState.loadWork(route.params.id)
if (workReadState.state != 'ssrnotfound') await workReadState.loadWork(route.params.id, route.params.cid)
if (workReadState.state == 'ready') {
routeState.customTitle = workReadState.title
const paraCount = workReadState.text.length - 2
const paraCount = workReadState.text.length - 1
isObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
currentParagraph = entry.target
readIndex = entry.target.dataset.index;
readPercent.value = parseInt(readIndex / paraCount * 100)
readPercent.value = parseInt(readIndex / paraCount * 100)
if (lastPercent == 0) {
lastPercent = readPercent.value
return
@ -171,7 +85,6 @@ onMounted(async () => {
await nextTick()
paragraphs = content.value?.querySelectorAll('p');
paragraphs?.forEach(p => isObserver.observe(p));
bookmarks.value = await bookmarkStore.getAll(workReadState.id)
}
})
@ -189,7 +102,10 @@ onBeforeUnmount(() => {
<template v-if="workReadState.state == 'notfound' || workReadState.state == 'ssrnotfound'">
<h2>文章不存在...</h2>
是不是链接没有复制完全?<br/>
ID: {{workReadState.id}}<br/>
ID: {{ workReadState.id }}<br/>
<template v-if="workReadState.cid">
CID: {{ workReadState.cid }}
</template>
<a @click="$router.back()">返回</a>
</template>
<template v-if="workReadState.state == 'ready'">
@ -200,14 +116,14 @@ onBeforeUnmount(() => {
<mdui-collapse-item value="info"><mdui-list-item class="infoblockhead" slot="header">
作品信息
</mdui-list-item><div class="infoblock"><dl>
<dt>分类</dt><ul>
<template v-if="workReadState.category"><dt>分类</dt><ul>
<li v-for="item in workReadState.category" :key="item">
{{ categoryName[item] }}</li>
</ul>
<dt>原著</dt><ul>
</ul></template>
<template v-if="workReadState.fandom"><dt>作品圈</dt><ul>
<li v-for="item in workReadState.fandom" :key="item">
{{ item }}</li>
</ul>
</ul></template>
<dt>语言</dt><dd>
{{ workReadState.lang }}
</dd>
@ -236,57 +152,33 @@ onBeforeUnmount(() => {
<p v-for="(para, index) in workReadState.text" :key="para" :data-index="index">{{ para }}</p>
</div>
</article>
<mdui-fab class="mdui-fab" :extended="fabExtended" @click="bookmarkDialog.open = true">
<mdui-fab class="mdui-fab" :extended="fabExtended">
<mdui-icon-bookmark slot="icon"></mdui-icon-bookmark>
{{ readPercent }}%
</mdui-fab>
<mdui-dialog ref='bookmarkDialog' close-on-overlay-click>
<span slot="headline">书签</span>
<span slot="description">
{{ bookmarks.length }}
<br/>
点击跳转, 长按条目以 更新/删除
</span>
<mdui-list v-if="bookmarks.length" style="max-width: 50vh; max-height: 90vh;">
<mdui-list-item
v-for="(bk, index) in bookmarks"
@click="jumpTo(index)"
@contextmenu.prevent="openBookmarkMenu(bk, index)"
>
{{ bk.name || bk.para }}
</mdui-list-item>
</mdui-list>
<span v-else>还没有书签</span>
<mdui-dropdown ref='bookmarkMenu' trigger="manual" open-on-pointer>
<span slot="trigger" />
<mdui-menu>
<mdui-menu-item @click="deleteBookmark()">删除</mdui-menu-item>
<mdui-menu-item @click="editBookmark()">编辑</mdui-menu-item>
</mdui-menu>
</mdui-dropdown>
<mdui-button slot="action" @click="delAllBookmark" variant="filled">清空</mdui-button>
<mdui-button slot="action" @click="addBookmark" variant="text">新建</mdui-button>
</mdui-dialog>
</template>
<template #ssr>
<template v-if="workReadState.state == 'notfound' || workReadState.state == 'ssrnotfound'">
<h2>文章不存在...</h2>
是不是链接没有复制完全?<br/>
ID: {{workReadState.id}}<br/>
<template v-if="workReadState.cid">
CID: {{ workReadState.cid }}
</template>
<a @click="$router.back()">返回</a>
</template>
<template v-if="workReadState.state == 'ready'">
<h1>{{ workReadState.title }}</h1>
<h2>{{ workReadState.pesud }}</h2>
<dl>
<dt>分类</dt><ul>
<template v-if="workReadState.category"><dt>作品圈</dt><ul>
<li v-for="item in workReadState.category" :key="item">
{{ categoryName[item] }}</li>
</ul>
<dt>原著</dt><ul>
</ul></template>
<template v-if="workReadState.fandom"><dt>原著</dt><ul>
<li v-for="item in workReadState.fandom" :key="item">
{{ item }}</li>
</ul>
</ul></template>
<dt>语言</dt><dd>
{{ workReadState.lang }}
</dd>