mirror of
https://github.com/lifegpc/bookdownload.git
synced 2026-06-12 00:28:54 +08:00
Add support to open new tab
This commit is contained in:
2
build.js
2
build.js
@@ -4,6 +4,7 @@ import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import colors from 'colors';
|
||||
import esbuildPluginEslint from 'esbuild-plugin-eslint';
|
||||
import { svgrPlugin } from 'esbuild-svgr-plugin'
|
||||
|
||||
const is_dev = process.argv.includes('--dev');
|
||||
const is_dbg = process.argv.includes('--debug');
|
||||
@@ -45,6 +46,7 @@ function displayResult(result) {
|
||||
|
||||
const plugins = [
|
||||
esbuildPluginEslint(),
|
||||
svgrPlugin(),
|
||||
];
|
||||
|
||||
async function build(name, is_content_script = true) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"name": "bookdownload",
|
||||
"dependencies": {
|
||||
"@ant-design/icons": "^6.1.0",
|
||||
"@material-icons/svg": "^1.0.33",
|
||||
"@stablelib/sha256": "^2.0.1",
|
||||
"@types/chrome": "^0.1.36",
|
||||
"@types/react": "^19.2.14",
|
||||
@@ -10,6 +11,7 @@
|
||||
"colors": "^1.4.0",
|
||||
"esbuild": "^0.27.3",
|
||||
"esbuild-plugin-eslint": "^0.3.12",
|
||||
"esbuild-svgr-plugin": "^0.2.0",
|
||||
"eslint": "9",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"lodash.isequal": "^4.5.0",
|
||||
@@ -29,5 +31,6 @@
|
||||
"buildrel": "node build.js",
|
||||
"lint": "eslint src"
|
||||
},
|
||||
"type": "module"
|
||||
"type": "module",
|
||||
"types": "./data.d.ts"
|
||||
}
|
||||
|
||||
22
src/components/Icon.module.css
Normal file
22
src/components/Icon.module.css
Normal file
@@ -0,0 +1,22 @@
|
||||
.icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
color: inherit;
|
||||
font-style: normal;
|
||||
line-height: 0;
|
||||
text-align: center;
|
||||
text-transform: none;
|
||||
vertical-align: -0.125em;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.icon svg {
|
||||
display: inline-block;
|
||||
vertical-align: inherit;
|
||||
}
|
||||
|
||||
.icon > * {
|
||||
line-height: 1;
|
||||
}
|
||||
8
src/components/Icon.tsx
Normal file
8
src/components/Icon.tsx
Normal file
@@ -0,0 +1,8 @@
|
||||
import { HTMLProps } from "react";
|
||||
import styles from "./Icon.module.css";
|
||||
|
||||
export default function Icon(props: HTMLProps<HTMLSpanElement>) {
|
||||
return (
|
||||
<span {...props} className={`${styles.icon}${props.className ? ` ${props.className}` : ''}`}>{props.children}</span>
|
||||
)
|
||||
}
|
||||
4
src/css.d.ts
vendored
4
src/css.d.ts
vendored
@@ -1,4 +0,0 @@
|
||||
declare module '*.css' {
|
||||
const content: { [className: string]: string };
|
||||
export = content;
|
||||
}
|
||||
10
src/data.d.ts
vendored
Normal file
10
src/data.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
declare module '*.css' {
|
||||
const content: { [className: string]: string };
|
||||
export = content;
|
||||
}
|
||||
|
||||
declare module "*.svg" {
|
||||
import { ReactElement, SVGProps } from "react";
|
||||
const content: (props: SVGProps<SVGElement>) => ReactElement;
|
||||
export default content;
|
||||
}
|
||||
@@ -8,7 +8,20 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.action {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.saved {
|
||||
margin-left: auto;
|
||||
color: green;
|
||||
}
|
||||
|
||||
.open {
|
||||
color: gray;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.open:hover {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { Collapse, Flex } from "antd";
|
||||
import { Collapse, Flex, Tooltip } from "antd";
|
||||
import type { Volume } from "../../qdtypes";
|
||||
import styles from './VolumesList.module.css';
|
||||
import { Link } from "react-router";
|
||||
import { CheckCircleOutlined } from "@ant-design/icons";
|
||||
import OpenInNewTab from "../../../node_modules/@material-icons/svg/svg/open_in_new/twotone.svg";
|
||||
import Icon from "../../components/Icon";
|
||||
|
||||
export type VolumesListProps = {
|
||||
volumes: Volume[];
|
||||
@@ -10,13 +12,33 @@ export type VolumesListProps = {
|
||||
oneLine?: boolean;
|
||||
}
|
||||
|
||||
async function open_in_qidian(bookId: number, chapterId: number) {
|
||||
const url = `https://www.qidian.com/chapter/${bookId}/${chapterId}/`;
|
||||
if (chrome && chrome.tabs) {
|
||||
try {
|
||||
const current = await chrome.tabs.getCurrent();
|
||||
await chrome.tabs.create({ url, active: true, openerTabId: current?.id, index: current ? current.index + 1 : undefined });
|
||||
} catch (e) {
|
||||
console.error('Failed to open in new tab, falling back to window.open', e);
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
} else {
|
||||
window.open(url, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
export default function VolumesList({ volumes, bookId, oneLine }: VolumesListProps) {
|
||||
return (<Collapse
|
||||
items={volumes.map(v => {
|
||||
const children = v.chapters.map(chapter => (
|
||||
<Flex className={oneLine ? styles.chone : styles.ch} key={chapter.id}>
|
||||
<Link to={`/qd/book/${bookId}/chapter/${chapter.id}`}>{chapter.name}</Link>
|
||||
{chapter.isSaved && <CheckCircleOutlined className={styles.saved} />}
|
||||
<Flex className={styles.action}>
|
||||
{chapter.isSaved && <CheckCircleOutlined className={styles.saved} />}
|
||||
<Tooltip title="在起点上查看(新标签页)">
|
||||
<Icon><OpenInNewTab fill="currentColor" width="20" className={styles.open} onClick={() => open_in_qidian(bookId, chapter.id)} /></Icon>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</Flex>
|
||||
));
|
||||
return {
|
||||
|
||||
10
yarn.lock
10
yarn.lock
@@ -297,6 +297,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba"
|
||||
integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==
|
||||
|
||||
"@material-icons/svg@^1.0.33":
|
||||
version "1.0.33"
|
||||
resolved "https://registry.yarnpkg.com/@material-icons/svg/-/svg-1.0.33.tgz#c3f4a5395c3b2267ce032081e9fe426995442ced"
|
||||
integrity sha512-sYXcybBWH3rNijK1D6Dv1Se/aZ7OAC2cCNkn4HiZOXQwkswtRVoDqHPw+GfsBoIC70UintfPXUsmiuaxMicWtw==
|
||||
|
||||
"@rc-component/async-validator@^5.1.0":
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@rc-component/async-validator/-/async-validator-5.1.0.tgz#e81f31e676d9cadc71e4310bbf1749c7a5882291"
|
||||
@@ -1364,6 +1369,11 @@ esbuild-plugin-eslint@^0.3.12:
|
||||
resolved "https://registry.yarnpkg.com/esbuild-plugin-eslint/-/esbuild-plugin-eslint-0.3.12.tgz#729cc6661acc5f3640078163e32e76efdf687129"
|
||||
integrity sha512-n37Nn6vmh2tdGMnm6GZebiYJDrqERAReyvLFwdCWCw15ZvAu251i6cIeJWoVB8AiS+j3N97gylvf58ysIwii4g==
|
||||
|
||||
esbuild-svgr-plugin@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/esbuild-svgr-plugin/-/esbuild-svgr-plugin-0.2.0.tgz#08319365a1ef642ce16c3d83c847ff31370dc4e5"
|
||||
integrity sha512-2+bY5KBjBieCBcsETx3wrmbsTAgRz2NZvRAgHl/xHqUG4g0E7k3J1/uumP0LwBGuOU3xKdDBjccU8Me/sKWL6A==
|
||||
|
||||
esbuild@^0.27.3:
|
||||
version "0.27.3"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.27.3.tgz#5859ca8e70a3af956b26895ce4954d7e73bd27a8"
|
||||
|
||||
Reference in New Issue
Block a user