Skip to content

Commit

Permalink
feat: generate toc and spine
Browse files Browse the repository at this point in the history
  • Loading branch information
yjl9903 committed Mar 4, 2023
1 parent ad0759a commit 6d189c2
Show file tree
Hide file tree
Showing 9 changed files with 92 additions and 38 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ const ebook = await Epubook.create({
description: 'something'
})

await ebook.cover('./assets/cover.jpg')
const cover = await ebook.cover('./assets/cover.jpg')

ebook.toc(cover)

await ebook.writeFile('./output.epub')
```
Expand Down
24 changes: 16 additions & 8 deletions packages/core/src/xhtml/builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,33 +14,41 @@ const builder = new XMLBuilder({
unpairedTags: ['link']
});

interface HTMLMeta {
export interface HTMLMeta {
language: string;
title: string;
}

export class XHTML extends Item {
private meta: HTMLMeta;
private _meta: HTMLMeta;

private content: string;
private _content: string;

public constructor(file: string, meta: HTMLMeta, content: string) {
super(file, TextXHTML);
this.meta = meta;
this.content = content;
this._meta = meta;
this._content = content;
}

public meta() {
return this._meta;
}

public title() {
return this.meta.title;
return this._meta.title;
}

public language() {
return this.meta.language;
return this._meta.language;
}

public content() {
return this._content;
}

public async bundle(): Promise<Uint8Array> {
// TODO: check encode format
return strToU8(this.content);
return strToU8(this._content);
}
}

Expand Down
30 changes: 15 additions & 15 deletions packages/core/test/bundle.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,20 +150,20 @@ describe('XHTML Builder', () => {
const res = builder.build();
expect(res).toMatchInlineSnapshot(`
XHTML {
"_properties": undefined,
"content": "<html xmlns=\\"http://www.w3.org/1999/xhtml\\" xmlns:epub=\\"http://www.idpf.org/2007/ops\\" lang=\\"en\\" xml:lang=\\"en\\">
"_content": "<html xmlns=\\"http://www.w3.org/1999/xhtml\\" xmlns:epub=\\"http://www.idpf.org/2007/ops\\" lang=\\"en\\" xml:lang=\\"en\\">
<head>
<title>a.xhtml</title>
</head>
<body></body>
</html>
",
"file": "a.xhtml",
"mediaType": "application/xhtml+xml",
"meta": {
"_meta": {
"language": "en",
"title": "a.xhtml",
},
"_properties": undefined,
"file": "a.xhtml",
"mediaType": "application/xhtml+xml",
}
`);
});
Expand All @@ -173,8 +173,7 @@ describe('XHTML Builder', () => {
const res = builder.title('with style').style('123').style('456').build();
expect(res).toMatchInlineSnapshot(`
XHTML {
"_properties": undefined,
"content": "<html xmlns=\\"http://www.w3.org/1999/xhtml\\" xmlns:epub=\\"http://www.idpf.org/2007/ops\\" lang=\\"en\\" xml:lang=\\"en\\">
"_content": "<html xmlns=\\"http://www.w3.org/1999/xhtml\\" xmlns:epub=\\"http://www.idpf.org/2007/ops\\" lang=\\"en\\" xml:lang=\\"en\\">
<head>
<title>with style</title>
<link href=\\"123\\" rel=\\"stylesheet\\" type=\\"text/css\\"/>
Expand All @@ -183,12 +182,13 @@ describe('XHTML Builder', () => {
<body></body>
</html>
",
"file": "a.xhtml",
"mediaType": "application/xhtml+xml",
"meta": {
"_meta": {
"language": "en",
"title": "with style",
},
"_properties": undefined,
"file": "a.xhtml",
"mediaType": "application/xhtml+xml",
}
`);
});
Expand All @@ -208,8 +208,7 @@ describe('XHTML Builder', () => {

expect(res).toMatchInlineSnapshot(`
XHTML {
"_properties": undefined,
"content": "<html xmlns=\\"http://www.w3.org/1999/xhtml\\" xmlns:epub=\\"http://www.idpf.org/2007/ops\\" lang=\\"en\\" xml:lang=\\"en\\">
"_content": "<html xmlns=\\"http://www.w3.org/1999/xhtml\\" xmlns:epub=\\"http://www.idpf.org/2007/ops\\" lang=\\"en\\" xml:lang=\\"en\\">
<head>
<title>Nav</title>
</head>
Expand All @@ -236,12 +235,13 @@ describe('XHTML Builder', () => {
</body>
</html>
",
"file": "nav.xhtml",
"mediaType": "application/xhtml+xml",
"meta": {
"_meta": {
"language": "en",
"title": "Nav",
},
"_properties": undefined,
"file": "nav.xhtml",
"mediaType": "application/xhtml+xml",
}
`);
});
Expand Down
4 changes: 3 additions & 1 deletion packages/epubook/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ const ebook = await Epubook.create({
description: 'something'
})

await ebook.cover('./assets/cover.jpg')
const cover = await ebook.cover('./assets/cover.jpg')

ebook.toc(cover)

await ebook.writeFile('./output.epub')
```
Expand Down
44 changes: 32 additions & 12 deletions packages/epubook/src/epubook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import type { DefaultTheme } from '@epubook/theme-default';

import * as path from 'node:path';

import { Cover } from './pages';
import { EpubookError } from './error';

export interface EpubookOption<T extends Theme<{}> = Awaited<ReturnType<typeof DefaultTheme>>> {
title: string;

Expand All @@ -35,7 +38,13 @@ export class Epubook<P extends Record<string, PageTemplate> = {}> {

private theme!: Theme<P>;

private content: Array<XHTML> = [];
private _toc: XHTML | undefined;

private _cover: XHTML | undefined;

private _pages: Array<XHTML> = [];

private _spine: Array<XHTML> = [];

private counter: Record<string, number> = {
image: 1
Expand Down Expand Up @@ -107,9 +116,9 @@ export class Epubook<P extends Record<string, PageTemplate> = {}> {
return image;
}

public async cover(img: string): Promise<Image | undefined>;
public async cover(img: Uint8Array, ext: ImageExtension): Promise<Image | undefined>;
public async cover(img: string | Uint8Array, ext?: ImageExtension) {
public async cover(img: string): Promise<Cover>;
public async cover(img: Uint8Array, ext: ImageExtension): Promise<Cover>;
public async cover(img: string | Uint8Array, ext?: ImageExtension): Promise<Cover> {
if (typeof img === 'string') {
ext = path.extname(img).slice(1) as ImageExtension;
}
Expand All @@ -120,10 +129,11 @@ export class Epubook<P extends Record<string, PageTemplate> = {}> {
if (image) {
image.update({ properties: 'cover-image' });
const page = this.page('cover', { image }, { file: `cover.xhtml` });
this.content.unshift(page);
return image;
this._cover = page;
this._pages.unshift(page);
return Cover.from(image, page);
} else {
return undefined;
throw new EpubookError('Can not load image');
}
}

Expand All @@ -145,17 +155,27 @@ export class Epubook<P extends Record<string, PageTemplate> = {}> {
return xhtml;
}

public toc() {
return this;
public toc(...items: Array<XHTML | { title: string; list: XHTML[] }>) {
this.container.toc(
items.map((i) =>
i instanceof XHTML
? { title: i.title(), page: i }
: { title: i.title, list: i.list.map((i) => ({ title: i.title(), page: i })) }
)
);

const spine = items.flatMap((i) => (i instanceof XHTML ? [i] : i.list));
this.spine(...spine);
}

public spine() {
public spine(...items: Array<XHTML>) {
this._spine.splice(0, this._spine.length, ...items);
return this;
}

private async preBundle() {
this.container.toc(this.content.map((c) => ({ title: c.title(), page: c })));
this.container.spine(...this.content);
this.container.toc(this._pages.map((c) => ({ title: c.title(), page: c })));
this.container.spine(...this._spine);
}

public async bundle() {
Expand Down
5 changes: 5 additions & 0 deletions packages/epubook/src/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class EpubookError extends Error {
constructor(msg: string) {
super(msg);
}
}
15 changes: 15 additions & 0 deletions packages/epubook/src/pages/cover.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Image, XHTML } from '@epubook/core';

export class Cover extends XHTML {
private _image!: Image;

public static from(image: Image, xhtml: XHTML) {
const cover = new Cover(xhtml.filename(), xhtml.meta(), xhtml.content());
cover._image = image;
return cover;
}

public image() {
return this._image;
}
}
1 change: 1 addition & 0 deletions packages/epubook/src/pages/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './cover';
3 changes: 2 additions & 1 deletion packages/epubook/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ describe('epubook', () => {
description: 'This is generated for testing cover image'
});

await book.cover('../../assets/cover.jpg');
const cover = await book.cover('../../assets/cover.jpg');
book.toc(cover);

await book.writeFile('../../.output/test-cover.epub');
});
Expand Down

0 comments on commit 6d189c2

Please sign in to comment.