diff --git a/package.json b/package.json index 700b6d4..594cbb7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "org.bytedo.epub", - "version": "1.0.0", + "version": "1.0.1", "description": "E-pub Reader", "main": "src/main.js", "scripts": { diff --git a/src/css/view.css b/src/css/view.css index 20a8033..6e53718 100644 --- a/src/css/view.css +++ b/src/css/view.css @@ -1 +1 @@ -html{width:100%;height:100vh}body{display:flex;width:100%;height:100%;line-height:1.25;font-size:14px;color:var(--color-dark-1);background:rgba(255,255,255,0.3)}.app{position:relative;display:flex;width:100%;height:100%}.app .toc{width:260px;height:100%}.app .toc item{display:flex;align-items:center;height:36px;padding:0 12px;border-bottom:1px solid var(--color-plain-1);cursor:pointer}.app .toc item.lev-0{font-weight:bold}.app .toc item.lev-1{padding-left:24px;font-weight:bold}.app .toc item.lev-2{padding-left:36px}.app .toc item.lev-3{padding-left:48px}.app .toc item:hover{color:var(--color-blue-1)}.app .toc item.active{color:#fff;background:var(--color-blue-1)}.app .toc item:last-child{border-bottom:0}.app .chapter-box{flex:1;height:100%;border-left:1px solid var(--color-plain-2)}.app .chapter{display:flex;justify-content:center;padding:8px 24px}.app .chapter .detail{max-width:768px;line-height:1.5;font-size:14px}.app .chapter .detail a{text-decoration:underline;color:var(--color-teal-2)}.app .chapter .detail a:hover{color:var(--color-teal-1);text-decoration:none}.app .chapter .detail em,.app .chapter .detail del{color:var(--color-grey-2)}.app .chapter .detail strong,.app .chapter .detail strong em,.app .chapter .detail strong{color:var(--color-dark-3)}.app .chapter .detail a strong,.app .chapter .detail a em{color:inherit}.app .chapter .detail em,.app .chapter .detail strong,.app .chapter .detail del{padding:0 2px}.app .chapter .detail img{max-width:100%}.app .chapter .detail blockquote{margin:10px 0;padding:5px 10px;line-height:1.5;border-left:5px solid var(--color-teal-1);background:#f2faf7;color:var(--color-grey-2)}.app .chapter .detail blockquote p{margin:0}.app .chapter .detail>p{margin:12px 0}.app .chapter .detail ol{margin-left:1em;list-style:decimal outside none}.app .chapter .detail ul{margin-left:1em;list-style:disc outside none}.app .chapter .detail li{margin:0.5em 0}.app .chapter .detail li ol{margin-left:1em}.app .chapter .detail li ul{margin-left:1em;list-style-type:circle}.app .chapter .detail li ol ul,.app .chapter .detail li ul ul{list-style-type:square}.app .chapter .detail h1,.app .chapter .detail h2,.app .chapter .detail h3,.app .chapter .detail h4,.app .chapter .detail h5,.app .chapter .detail h6{margin:15px 0;line-height:2;font-weight:bold;font-size:16px}.app .chapter .detail h1 code.inline,.app .chapter .detail h2 code.inline,.app .chapter .detail h3 code.inline,.app .chapter .detail h4 code.inline,.app .chapter .detail h5 code.inline,.app .chapter .detail h6 code.inline{background:none}.app .chapter .detail h1 a,.app .chapter .detail h2 a,.app .chapter .detail h3 a,.app .chapter .detail h4 a,.app .chapter .detail h5 a,.app .chapter .detail h6 a{text-decoration:none;color:#333}.app .chapter .detail h3 a::before,.app .chapter .detail h4 a::before,.app .chapter .detail h5 a::before,.app .chapter .detail h6 a::before{content:'∮ ';color:var(--color-teal-1);font-weight:normal}.app .chapter .detail h1{margin:0 0 30px;font-size:24px;text-align:center}.app .chapter .detail h2{margin:20px 0;font-size:22px;border-bottom:1px solid var(--color-plain-2)}.app .chapter .detail h3{margin:20px 0 15px;font-size:20px}.app .chapter .detail h4{font-size:18px}.app .chapter .detail table{width:100%;border-spacing:0;border-collapse:collapse}.app .chapter .detail table tr{background-color:#fff}.app .chapter .detail table thead tr{background:var(--color-plain-1)}.app .chapter .detail table th,.app .chapter .detail table td{padding:6px 13px;border:1px solid var(--color-plain-2)}.app .chapter .detail table th{font-weight:bold}.app .chapter .detail table tr:nth-child(2n){background-color:#fcfdff} +html{width:100%;height:100vh}body{display:flex;width:100%;height:100%;line-height:1.25;font-size:14px;color:var(--color-dark-1);background:rgba(255,255,255,0.3)}.app{position:relative;display:flex;width:100%;height:100%}.app .toc{width:260px;height:100%}.app .toc item{display:flex;align-items:center;height:36px;padding:0 12px;border-bottom:1px solid var(--color-plain-1);cursor:pointer}.app .toc item.lev-0{font-weight:bold}.app .toc item.lev-1{padding-left:24px;font-weight:bold}.app .toc item.lev-2{padding-left:36px}.app .toc item.lev-3{padding-left:48px}.app .toc item:hover{color:var(--color-blue-1)}.app .toc item.active{color:#fff;background:var(--color-blue-1)}.app .toc item:last-child{border-bottom:0}.app .chapter-box{flex:1;height:100%;border-left:1px solid var(--color-plain-2)}.app .chapter{display:flex;justify-content:center;padding:8px 24px}.app .chapter .detail{max-width:768px;line-height:1.5;font-size:14px}.app .chapter .detail a{text-decoration:underline;color:var(--color-teal-2)}.app .chapter .detail a:hover{color:var(--color-teal-1);text-decoration:none}.app .chapter .detail em,.app .chapter .detail del{color:var(--color-grey-2)}.app .chapter .detail strong,.app .chapter .detail strong em,.app .chapter .detail strong{color:var(--color-dark-3)}.app .chapter .detail a strong,.app .chapter .detail a em{color:inherit}.app .chapter .detail em,.app .chapter .detail strong,.app .chapter .detail del{padding:0 2px}.app .chapter .detail img{max-width:100%}.app .chapter .detail blockquote{margin:10px 0;padding:5px 10px;line-height:1.5;border-left:5px solid var(--color-teal-1);background:#f2faf7;color:var(--color-grey-2)}.app .chapter .detail blockquote p{margin:0}.app .chapter .detail code{display:inline;margin:0 2px;padding:0 2px;color:var(--color-orange-3);background:var(--color-plain-1);border-radius:2px;font-family:Menlo, Monaco, Consolas, 'Courier New', monospace}.app .chapter .detail>p{margin:12px 0}.app .chapter .detail ol{margin-left:1em;list-style:decimal outside none}.app .chapter .detail ul{margin-left:1em;list-style:disc outside none}.app .chapter .detail li{margin:0.5em 0}.app .chapter .detail li ol{margin-left:1em}.app .chapter .detail li ul{margin-left:1em;list-style-type:circle}.app .chapter .detail li ol ul,.app .chapter .detail li ul ul{list-style-type:square}.app .chapter .detail h1,.app .chapter .detail h2,.app .chapter .detail h3,.app .chapter .detail h4,.app .chapter .detail h5,.app .chapter .detail h6{margin:15px 0;line-height:2;font-weight:bold;font-size:16px}.app .chapter .detail h1 code,.app .chapter .detail h2 code,.app .chapter .detail h3 code,.app .chapter .detail h4 code,.app .chapter .detail h5 code,.app .chapter .detail h6 code{background:none}.app .chapter .detail h1 a,.app .chapter .detail h2 a,.app .chapter .detail h3 a,.app .chapter .detail h4 a,.app .chapter .detail h5 a,.app .chapter .detail h6 a{text-decoration:none;color:#333}.app .chapter .detail h3 a::before,.app .chapter .detail h4 a::before,.app .chapter .detail h5 a::before,.app .chapter .detail h6 a::before{content:'∮ ';color:var(--color-teal-1);font-weight:normal}.app .chapter .detail h1{margin:0 0 30px;font-size:24px;text-align:center}.app .chapter .detail h2{margin:20px 0;font-size:22px;border-bottom:1px solid var(--color-plain-2)}.app .chapter .detail h3{margin:20px 0 15px;font-size:20px}.app .chapter .detail h4{font-size:18px}.app .chapter .detail table{width:100%;border-spacing:0;border-collapse:collapse}.app .chapter .detail table tr{background-color:#fff}.app .chapter .detail table thead tr{background:var(--color-plain-1)}.app .chapter .detail table th,.app .chapter .detail table td{padding:6px 13px;border:1px solid var(--color-plain-2)}.app .chapter .detail table th{font-weight:bold}.app .chapter .detail table tr:nth-child(2n){background-color:#fcfdff} diff --git a/src/css/view.scss b/src/css/view.scss index 6834bd7..8044c48 100644 --- a/src/css/view.scss +++ b/src/css/view.scss @@ -128,6 +128,16 @@ body { } } + code { + display: inline; + margin: 0 2px; + padding: 0 2px; + color: var(--color-orange-3); + background: var(--color-plain-1); + border-radius: 2px; + font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; + } + > p { margin: 12px 0; // text-indent: 2em; @@ -167,7 +177,7 @@ body { font-weight: bold; font-size: 16px; - code.inline { + code { background: none; } a { diff --git a/src/index.html b/src/index.html index b6d5607..64791ae 100644 --- a/src/index.html +++ b/src/index.html @@ -36,7 +36,10 @@ @dblclick="read(it)" @contextmenu="pickCtx2(it, $event)" > - + diff --git a/src/js/app.js b/src/js/app.js index 41f93cf..b682e1b 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -121,6 +121,10 @@ Anot({ this.$db = db this.cates = cates this.books = books || [] + + app.on('draw-cover', title => { + this.drawCover(title) + }) }, methods: { view(item) { @@ -174,10 +178,61 @@ Anot({ this.$refs.ctx2.show() }) }, + saveDB() { app.dispatch('save-books', Anot.deepCopy(this.$db)) }, + drawCover(name) { + var canvas = document.createElement('canvas') + var ctx = canvas.getContext('2d') + var tmp = name.split('').map(s => (/[\w\s\(\)]/.test(s) ? 1 : 2)) + + canvas.width = 128 + canvas.height = 160 + + ctx.fillStyle = + '#' + + Buffer.from(name) + .toString('hex') + .slice(-6) + + ctx.fillRect(0, 0, 128, 160) + + ctx.fillStyle = '#fff' + ctx.font = '14px menlo,Hiragino Sans GB' + ctx.textAlign = 'center' + + let row = 0 + let last = 0 + tmp.reduce((sum, c, i) => { + sum += c + + if (sum >= 14 && row === 0) { + ctx.fillText(name.slice(0, i + 1), 64, 60, 100) + last = i + row = 1 + } else if (sum >= 28 && row === 1) { + ctx.fillText(name.slice(last, i + 1), 64, 60 + row * 26, 100) + row = 2 + last = i + } else if (sum >= 42 && row === 2) { + ctx.fillText(name.slice(last, i + 1), 64, 60 + row * 26, 100) + } + return sum + }, 0) + + if (last === 0) { + ctx.fillText(name, 64, 76, 100) + } else { + if (last < tmp.length) { + ctx.fillText(name.slice(last + 1), 64, 60 + row * 26, 100) + } + } + let base64 = canvas.toDataURL('image/webp', 1).split(',')[1] + app.dispatch('save-cover', { base64, name }) + }, + deleteCate() { // this.$refs.ctx1.close() diff --git a/src/js/view.js b/src/js/view.js index 18bb245..146b389 100644 --- a/src/js/view.js +++ b/src/js/view.js @@ -12,6 +12,8 @@ import { md5 } from '/lib/md5.js' import fetch from '/lib/fetch/index.js' import app from '/lib/socket.js' +const { dirname, join } = require('path') + Anot({ $id: 'app', state: { @@ -89,7 +91,9 @@ Anot({ this.chapter = txt.replace( /]*?src="(.*?)"[^>]*?\/?>/g, (m, s1) => { - s1 = s1.replace('../', '') + // s1 = s1.replace('../', '') + s1 = join(dirname(file), s1) + console.log(file, s1) return `` } ) diff --git a/src/main.js b/src/main.js index c262347..f6ee240 100644 --- a/src/main.js +++ b/src/main.js @@ -44,8 +44,6 @@ protocol.registerSchemesAsPrivileged([ /* ----------------------------------------------------- */ -// app.dock.hide() - // 初始化应用 app.once('ready', () => { // 注册协议 diff --git a/src/tools/socket.js b/src/tools/socket.js index 77acf86..70c0a6b 100644 --- a/src/tools/socket.js +++ b/src/tools/socket.js @@ -26,9 +26,10 @@ module.exports = function(app, createViewWindow) { break case 'read': + let params = JSON.parse(Buffer.from(conn.data, 'base64')) if (app.__view__) { // 打开同一个文档, 直接忽略 - if (app.__view__.__title__ === conn.data.title) { + if (app.__view__.__title__ === params.title) { app.__view__.focus() ev.returnValue = true return @@ -36,7 +37,7 @@ module.exports = function(app, createViewWindow) { app.__view__.destroy() } app.__view__ = createViewWindow(conn.data) - app.__view__.__title__ = conn.data.title + app.__view__.__title__ = params.title ev.returnValue = true break @@ -46,6 +47,13 @@ module.exports = function(app, createViewWindow) { ev.returnValue = true break + case 'save-cover': + let file = path.join(CACHE_DIR, conn.data.name, 'cover.webp') + let buf = Buffer.from(conn.data.base64, 'base64') + fs.echo(buf, file) + ev.returnValue = true + break + case 'parse-book': let { book, cate } = conn.data let eb = new Epub(book.path) @@ -53,7 +61,7 @@ module.exports = function(app, createViewWindow) { eb.on('end', async _ => { let { title } = eb.metadata - let cover = 'cover' + let cover = '' let dir = path.join(CACHE_DIR, title) function saveImage(id, name) { @@ -78,6 +86,14 @@ module.exports = function(app, createViewWindow) { .replace(/
/g, '')
                     .replace(/<\/code><\/pre>/g, '')
 
+                  htm = htm.replace(/([\w\W]*?)<\/wc-code>/g, function(
+                    m,
+                    s
+                  ) {
+                    s = s.replace(/<\/?\w+>/g, '')
+                    return `${s}`
+                  })
+
                   fs.echo(htm, path.join(dir, name.replace('.xhtml', '.html')))
                 } else {
                   console.log(id, name, txt)
@@ -106,15 +122,23 @@ module.exports = function(app, createViewWindow) {
               default:
                 if (it['media-type'].startsWith('image')) {
                   saveImage(it.id, it.href)
-                  if (it.href.includes(cover)) {
+                  if (it.href.includes('cover')) {
                     cover = it.href
                   }
                 }
                 break
             }
           }
+          if (!cover) {
+            cover = 'cover.webp'
+            app.__main__.webContents.send('app', {
+              type: 'draw-cover',
+              data: title
+            })
+          }
 
           let info = { title, cover }
+
           if (cache[cate]) {
             if (!cache[cate].some(it => it.title === title)) {
               cache[cate].push(info)