完成书本解析
parent
4b4ef306c2
commit
71aebe5cbd
|
@ -1 +1 @@
|
|||
html{font-size:12.8px;width:100%;height:100vh}body{overflow:hidden;display:flex;flex-direction:column;width:100%;height:100%;line-height:1.25;font-size:14px;color:var(--color-dark-1);background:rgba(255,255,255,0.3)}.app-drag{-webkit-app-region:drag;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.app-nodrag{-webkit-app-region:no-drag}.app{position:relative;display:flex;height:100%}.app .category{width:200px;height:100%;background:#fff}.app .category .item{display:flex;justify-content:space-between;align-items:center;height:54px;padding:8px;border-bottom:1px solid var(--color-plain-1);background:#fff;transition:background 0.2s ease-in-out, color 0.2s ease-in-out;cursor:pointer}.app .category .item strong{max-width:150px}.app .category .item .num{display:flex;justify-content:center;align-items:center;min-width:16px;height:16px;padding:2px;line-height:1;border-radius:50%;font-size:12px;background:var(--color-grey-1);color:#fff}.app .category .item:last-child{border-bottom:0}.app .category .item:hover{color:var(--color-blue-1);background:var(--color-plain-1)}.app .category .item.active{color:var(--color-plain-1);background:var(--color-blue-1)}.app .category .item.active .num{background:#fff;color:var(--color-blue-1)}.app .detail{position:relative;flex:1;height:100%;border-left:1px solid var(--color-plain-2);background:rgba(255,255,255,0.5)}.app .detail .title{display:flex;justify-content:space-between;align-items:center;width:100%;height:35px;padding:0 16px;font-size:16px;font-weight:bold}.app .detail .title span{display:inline-flex}.app .detail .title wc-button{margin:0 6px}.app .detail .card{width:96%;padding:12px 12px 16px;margin:12px 2% 24px;border:0;background:#fff;box-shadow:0 0 8px rgba(0,0,0,0.075)}.app .detail .card legend{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;color:#64b5f6}.app .drag-mask{display:flex;align-items:center;position:fixed;left:0;top:0;z-index:9999;width:100%;height:100%;background:linear-gradient(to right, transparent, transparent 200px, #fff3e3 200px)}.app .drag-mask::after{font-size:46px;text-indent:300px;content:'Drop epub file here...';color:var(--color-grey-1)}.app .book-loading{display:flex;align-items:center;justify-content:center;position:fixed;left:0;top:0;z-index:9999;width:100%;height:100%;font-size:20px;background:rgba(255,255,255,0.01);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.app .book-loading .loading{display:flex;flex-direction:column;align-items:center;justify-content:center}.app .book-loading .loading::before{content:'🌑';font-size:36px;-webkit-animation:loading 1s infinite;animation:loading 1s infinite}@-webkit-keyframes loading{1%,100%{content:'🌑'}12.5%{content:'🌒'}25%{content:'🌓'}37.5%{content:'🌔'}50%{content:'🌕'}62.5%{content:'🌖'}75%{content:'🌗'}87.5%{content:'🌘'}}@keyframes loading{1%,100%{content:'🌑'}12.5%{content:'🌒'}25%{content:'🌓'}37.5%{content:'🌔'}50%{content:'🌕'}62.5%{content:'🌖'}75%{content:'🌗'}87.5%{content:'🌘'}}
|
||||
html{width:100%;height:100vh}body{overflow:hidden;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;height:100%}.app .category{width:200px;height:100%;background:#fff}.app .category .item{display:flex;justify-content:space-between;align-items:center;height:54px;padding:8px;border-bottom:1px solid var(--color-plain-1);background:#fff;transition:background 0.2s ease-in-out, color 0.2s ease-in-out;cursor:pointer}.app .category .item strong{max-width:150px}.app .category .item .num{display:flex;justify-content:center;align-items:center;min-width:16px;height:16px;padding:2px;line-height:1;border-radius:50%;font-size:12px;background:var(--color-grey-1);color:#fff}.app .category .item:last-child{border-bottom:0}.app .category .item:hover{color:var(--color-blue-1);background:var(--color-plain-1)}.app .category .item.active{color:var(--color-plain-1);background:var(--color-blue-1)}.app .category .item.active .num{background:#fff;color:var(--color-blue-1)}.app .books-scroll{flex:1;height:100%;border-left:1px solid var(--color-plain-2)}.app .books{display:flex;flex-wrap:wrap}.app .books .book{display:flex;flex-direction:column;width:128px;margin:24px;background:#fff;box-shadow:0 0 12px rgba(0,0,0,0.15);transition:box-shadow 0.1s ease-in;cursor:pointer}.app .books .book img{width:100%;height:160px;-o-object-fit:fill;object-fit:fill}.app .books .book:hover{box-shadow:0 0 12px rgba(0,0,0,0.35)}.app .drag-mask{display:flex;align-items:center;position:fixed;left:0;top:0;z-index:9999;width:100%;height:100%;background:linear-gradient(to right, transparent, transparent 200px, rgba(252,232,207,0.6) 200px)}.app .drag-mask::after{font-size:46px;text-indent:360px;content:'Drop epub file here...';color:var(--color-grey-1)}.app .book-loading{display:flex;align-items:center;justify-content:center;position:fixed;left:0;top:0;z-index:9999;width:100%;height:100%;font-size:20px;background:rgba(255,255,255,0.01);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.app .book-loading .loading{display:flex;flex-direction:column;align-items:center;justify-content:center}.app .book-loading .loading::before{content:'🌑';font-size:36px;-webkit-animation:loading 1s infinite;animation:loading 1s infinite}@-webkit-keyframes loading{1%,100%{content:'🌑'}12.5%{content:'🌒'}25%{content:'🌓'}37.5%{content:'🌔'}50%{content:'🌕'}62.5%{content:'🌖'}75%{content:'🌗'}87.5%{content:'🌘'}}@keyframes loading{1%,100%{content:'🌑'}12.5%{content:'🌒'}25%{content:'🌓'}37.5%{content:'🌔'}50%{content:'🌕'}62.5%{content:'🌖'}75%{content:'🌗'}87.5%{content:'🌘'}}
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
*/
|
||||
|
||||
html {
|
||||
font-size: 12.8px;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
@ -14,7 +13,6 @@ html {
|
|||
body {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height: 1.25;
|
||||
|
@ -23,14 +21,6 @@ body {
|
|||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.app-drag {
|
||||
-webkit-app-region: drag;
|
||||
user-select: none;
|
||||
}
|
||||
.app-nodrag {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.app {
|
||||
position: relative;
|
||||
display: flex;
|
||||
|
@ -90,43 +80,34 @@ body {
|
|||
}
|
||||
}
|
||||
|
||||
.detail {
|
||||
position: relative;
|
||||
.books-scroll {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
border-left: 1px solid var(--color-plain-2);
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.title {
|
||||
.books {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.book {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
padding: 0 16px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
|
||||
span {
|
||||
display: inline-flex;
|
||||
}
|
||||
wc-button {
|
||||
margin: 0 6px;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
width: 96%;
|
||||
padding: 12px 12px 16px;
|
||||
margin: 12px 2% 24px;
|
||||
border: 0;
|
||||
flex-direction: column;
|
||||
width: 128px;
|
||||
margin: 24px;
|
||||
background: #fff;
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.075);
|
||||
box-shadow: 0 0 12px rgba(0, 0, 0, 0.15);
|
||||
transition: box-shadow 0.1s ease-in;
|
||||
cursor: pointer;
|
||||
|
||||
legend {
|
||||
-webkit-touch-callout: none;
|
||||
user-select: none;
|
||||
color: #64b5f6;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
object-fit: fill;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 0 12px rgba(0, 0, 0, 0.35);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -144,12 +125,12 @@ body {
|
|||
to right,
|
||||
transparent,
|
||||
transparent 200px,
|
||||
#fff3e3 200px
|
||||
rgba(252, 232, 207, 0.6) 200px
|
||||
);
|
||||
|
||||
&::after {
|
||||
font-size: 46px;
|
||||
text-indent: 300px;
|
||||
text-indent: 360px;
|
||||
content: 'Drop epub file here...';
|
||||
color: var(--color-grey-1);
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
html{font-size:12.8px;width:100%;height:100vh}body{display:flex;flex-direction:column;width:100%;height:100%;line-height:1.25;font-size:14px;color:var(--color-dark-1);background:rgba(255,255,255,0.3)}.app-drag{-webkit-app-region:drag;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.app-nodrag{-webkit-app-region:no-drag}.app{position:relative;display:flex;flex-direction:column;height:100%;padding:6px 0}.app .list{flex:1}.app .list .item{display:flex;align-items:center;height:54px;padding:10px 12px;line-height:15px;border-bottom:1px solid rgba(155,155,155,0.3)}.app .list .item:last-child{border-bottom:0}.app .list .item .info{overflow:hidden;flex:1}.app .list .item .info h3{font-size:14px}.app .list .item .info cite{color:var(--color-grey-2)}.app .list .item .last-days{display:flex;width:64px;height:30px;margin:0 6px}.app .list .item .today{width:52px;font-size:12px;text-align:right}.app .list .item .today span{display:block;padding:0 4px}.app .list .item .today .percent{border-radius:2px;color:#fff}.app .list .item .today .percent.red{background:var(--color-red-1)}.app .list .item .today .percent.green{background:var(--color-green-3)}
|
|
@ -1,97 +0,0 @@
|
|||
@charset "UTF-8";
|
||||
/**
|
||||
* 浮窗样式
|
||||
* @authors yutent<yutent@doui.cc>
|
||||
* @date 2018/12/16 17:15:07
|
||||
*/
|
||||
|
||||
html {
|
||||
font-size: 12.8px;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
line-height: 1.25;
|
||||
font-size: 14px;
|
||||
color: var(--color-dark-1);
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.app-drag {
|
||||
-webkit-app-region: drag;
|
||||
user-select: none;
|
||||
}
|
||||
.app-nodrag {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.app {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
padding: 6px 0;
|
||||
|
||||
.list {
|
||||
flex: 1;
|
||||
|
||||
.item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 54px;
|
||||
padding: 10px 12px;
|
||||
line-height: 15px;
|
||||
border-bottom: 1px solid rgba(155, 155, 155, 0.3);
|
||||
|
||||
&:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.info {
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
|
||||
h3 {
|
||||
font-size: 14px;
|
||||
}
|
||||
cite {
|
||||
color: var(--color-grey-2);
|
||||
}
|
||||
}
|
||||
|
||||
.last-days {
|
||||
display: flex;
|
||||
width: 64px;
|
||||
height: 30px;
|
||||
margin: 0 6px;
|
||||
}
|
||||
|
||||
.today {
|
||||
width: 52px;
|
||||
font-size: 12px;
|
||||
text-align: right;
|
||||
|
||||
span {
|
||||
display: block;
|
||||
padding: 0 4px;
|
||||
}
|
||||
.percent {
|
||||
border-radius: 2px;
|
||||
color: #fff;
|
||||
|
||||
&.red {
|
||||
background: var(--color-red-1);
|
||||
}
|
||||
&.green {
|
||||
background: var(--color-green-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +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}
|
|
@ -0,0 +1,233 @@
|
|||
@charset "UTF-8";
|
||||
/**
|
||||
* 浮窗样式
|
||||
* @authors yutent<yutent@doui.cc>
|
||||
* @date 2018/12/16 17:15:07
|
||||
*/
|
||||
|
||||
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%;
|
||||
|
||||
.toc {
|
||||
width: 260px;
|
||||
height: 100%;
|
||||
|
||||
item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 36px;
|
||||
padding: 0 12px;
|
||||
border-bottom: 1px solid var(--color-plain-1);
|
||||
cursor: pointer;
|
||||
|
||||
&.lev-0 {
|
||||
font-weight: bold;
|
||||
}
|
||||
&.lev-1 {
|
||||
padding-left: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
&.lev-2 {
|
||||
padding-left: 36px;
|
||||
}
|
||||
&.lev-3 {
|
||||
padding-left: 48px;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: var(--color-blue-1);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #fff;
|
||||
background: var(--color-blue-1);
|
||||
}
|
||||
&:last-child {
|
||||
border-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chapter-box {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
border-left: 1px solid var(--color-plain-2);
|
||||
}
|
||||
|
||||
.chapter {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 8px 24px;
|
||||
|
||||
.detail {
|
||||
max-width: 768px;
|
||||
line-height: 1.5;
|
||||
font-size: 14px;
|
||||
|
||||
a {
|
||||
text-decoration: underline;
|
||||
color: var(--color-teal-2);
|
||||
}
|
||||
a:hover {
|
||||
color: var(--color-teal-1);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
em,
|
||||
del {
|
||||
color: var(--color-grey-2);
|
||||
}
|
||||
strong,
|
||||
strong em,
|
||||
strong {
|
||||
color: var(--color-dark-3);
|
||||
}
|
||||
a {
|
||||
strong,
|
||||
em {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
em,
|
||||
strong,
|
||||
del {
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
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);
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
> p {
|
||||
margin: 12px 0;
|
||||
// text-indent: 2em;
|
||||
}
|
||||
|
||||
ol {
|
||||
margin-left: 1em;
|
||||
list-style: decimal outside none;
|
||||
}
|
||||
ul {
|
||||
margin-left: 1em;
|
||||
list-style: disc outside none;
|
||||
}
|
||||
li {
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
li ol {
|
||||
margin-left: 1em;
|
||||
}
|
||||
li ul {
|
||||
margin-left: 1em;
|
||||
list-style-type: circle;
|
||||
}
|
||||
li ol ul,
|
||||
li ul ul {
|
||||
list-style-type: square;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
margin: 15px 0;
|
||||
line-height: 2;
|
||||
font-weight: bold;
|
||||
font-size: 16px;
|
||||
|
||||
code.inline {
|
||||
background: none;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
a {
|
||||
&::before {
|
||||
content: '∮ ';
|
||||
color: var(--color-teal-1);
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
h1 {
|
||||
margin: 0 0 30px;
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
h2 {
|
||||
margin: 20px 0;
|
||||
font-size: 22px;
|
||||
border-bottom: 1px solid var(--color-plain-2);
|
||||
}
|
||||
h3 {
|
||||
margin: 20px 0 15px;
|
||||
font-size: 20px;
|
||||
}
|
||||
h4 {
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
|
||||
tr {
|
||||
background-color: #fff;
|
||||
}
|
||||
thead tr {
|
||||
background: var(--color-plain-1);
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid var(--color-plain-2);
|
||||
}
|
||||
th {
|
||||
font-weight: bold;
|
||||
}
|
||||
tr:nth-child(2n) {
|
||||
background-color: #fcfdff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,15 +25,15 @@
|
|||
|
||||
|
||||
|
||||
<div class="detail" :class="{blur: !curr.code}">
|
||||
|
||||
<book :for="it in books">
|
||||
<img :src="'book://cache/' + it.title + '/' + it.cover">
|
||||
{{it.title}}
|
||||
</book>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<wc-scroll class="books-scroll">
|
||||
<list class="books">
|
||||
<book class="book" :for="it in books">
|
||||
<img :src="'book://cache/' + it.title + '/' + it.cover">
|
||||
</book>
|
||||
</list>
|
||||
</wc-scroll>
|
||||
|
||||
|
||||
|
||||
<div class="drag-mask" ref="mask" :visible="isDragIn"></div>
|
||||
|
|
|
@ -7,14 +7,9 @@
|
|||
*/
|
||||
|
||||
import '/lib/anot.js'
|
||||
import '/lib/form/button.js'
|
||||
import '/lib/form/switch.js'
|
||||
import '/lib/scroll/index.js'
|
||||
import '/lib/chart/rank.js'
|
||||
import '/lib/chart/line.js'
|
||||
|
||||
import layer from '/lib/layer/index.js'
|
||||
import Utils from '/lib/utils.js'
|
||||
|
||||
import app from '/lib/socket.js'
|
||||
|
||||
|
@ -37,14 +32,14 @@ Anot({
|
|||
load: {
|
||||
num: 0,
|
||||
curr: 0
|
||||
}
|
||||
},
|
||||
$db: {}
|
||||
},
|
||||
|
||||
watch: {},
|
||||
|
||||
mounted() {
|
||||
$doc.bind('dragover', ev => {
|
||||
ev.stopPropagation()
|
||||
ev.preventDefault()
|
||||
|
||||
this.isDragIn = true
|
||||
|
@ -56,9 +51,8 @@ Anot({
|
|||
})
|
||||
|
||||
$doc.bind('drop', ev => {
|
||||
ev.stopPropagation()
|
||||
ev.preventDefault()
|
||||
// clearTimeout(this.timer)
|
||||
|
||||
this.isDragIn = false
|
||||
|
||||
let files = Array.from(ev.dataTransfer.files)
|
||||
|
@ -73,20 +67,34 @@ Anot({
|
|||
this.load.curr = 0
|
||||
this.loading = true
|
||||
|
||||
console.time(1)
|
||||
while (this.load.curr < this.load.num) {
|
||||
this.load.curr++
|
||||
let book = files.pop()
|
||||
let res = app.dispatch('parse-book', { book, cate: this.curr })
|
||||
console.log(res)
|
||||
|
||||
if (res) {
|
||||
this.books.push(res)
|
||||
}
|
||||
}
|
||||
console.timeEnd(1)
|
||||
|
||||
this.loading = false
|
||||
})
|
||||
|
||||
let db = app.dispatch('get-books')
|
||||
let cates = [],
|
||||
books
|
||||
for (let k in db) {
|
||||
cates.push({ name: k, num: db[k].length })
|
||||
// 默认选中第一个
|
||||
if (!books) {
|
||||
this.curr = k
|
||||
books = db[k]
|
||||
}
|
||||
}
|
||||
// books = books.concat(books, books, books, books, books, books)
|
||||
this.$db = db
|
||||
this.cates = cates
|
||||
this.books = books
|
||||
},
|
||||
methods: {}
|
||||
})
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2020/12/10 19:53:05
|
||||
*/
|
||||
|
||||
import '/lib/anot.js'
|
||||
|
||||
import '/lib/scroll/index.js'
|
||||
import layer from '/lib/layer/index.js'
|
||||
import app from '/lib/socket.js'
|
||||
|
||||
function getJsonp(str) {
|
||||
if (~str.indexOf('jsonpgz')) {
|
||||
return new Function(`function jsonpgz(d){return d}; return ${str}`)()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Anot({
|
||||
$id: 'app',
|
||||
state: {
|
||||
list: []
|
||||
},
|
||||
mounted() {
|
||||
this.reloadGays()
|
||||
|
||||
app.on('float-visible', data => {
|
||||
var time = +Anot.ss('last_update') || 0
|
||||
var now = Date.now()
|
||||
|
||||
// 有触发小窗口显示时, 更新通知提醒
|
||||
if (Anot.ls('notify') === '1') {
|
||||
app.dispatch('notify')
|
||||
}
|
||||
|
||||
this.reloadGays()
|
||||
setTimeout(() => {
|
||||
// 如果离上次更新超过15分钟, 则自动更新
|
||||
if (now - time > 15 * 60 * 1000) {
|
||||
this.updateGays()
|
||||
Anot.ss('last_update', now)
|
||||
}
|
||||
}, 500)
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
reloadGays() {
|
||||
var gays = Anot.ls('gays') || '{}'
|
||||
var list = []
|
||||
|
||||
gays = JSON.parse(gays)
|
||||
|
||||
for (let code in gays) {
|
||||
let { name, cm, cp, t } = gays[code]
|
||||
list.push({ code, name, cm, cp, t })
|
||||
}
|
||||
list.sort((a, b) => b.cp - a.cp)
|
||||
|
||||
this.list = list
|
||||
},
|
||||
|
||||
getGayStat(id) {
|
||||
var res = app.dispatch(
|
||||
'fetch',
|
||||
`https://fundgz.1234567.com.cn/js/${id}.js`
|
||||
)
|
||||
return getJsonp(res)
|
||||
},
|
||||
|
||||
updateGay(item) {
|
||||
var info = this.getGayStat(item.code)
|
||||
item.cm = +info.gsz
|
||||
item.cp = +info.gszzl
|
||||
},
|
||||
|
||||
updateGays() {
|
||||
for (let it of this.list) {
|
||||
this.updateGay(it)
|
||||
}
|
||||
this.list.sort((a, b) => b.cp - a.cp)
|
||||
this.saveCache()
|
||||
app.dispatch('data-reload')
|
||||
},
|
||||
saveCache() {
|
||||
var dict = {}
|
||||
for (let it of this.list) {
|
||||
var { code, name, cm, cp, t } = it
|
||||
dict[code] = { name, cm, cp, t }
|
||||
}
|
||||
Anot.ls('gays', dict)
|
||||
}
|
||||
}
|
||||
})
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
*
|
||||
* @author yutent<yutent.io@gmail.com>
|
||||
* @date 2020/12/10 19:53:05
|
||||
*/
|
||||
|
||||
import '/lib/anot.js'
|
||||
|
||||
import '/lib/scroll/index.js'
|
||||
import '/lib/code/index.js'
|
||||
import layer from '/lib/layer/index.js'
|
||||
import fetch from '/lib/fetch/index.js'
|
||||
import app from '/lib/socket.js'
|
||||
|
||||
Anot({
|
||||
$id: 'app',
|
||||
state: {
|
||||
toc: [],
|
||||
title: 'HTML5 canvas开发详解(第2版) (无)',
|
||||
curr: '',
|
||||
file: '',
|
||||
chapter: ''
|
||||
},
|
||||
mounted() {
|
||||
// app.on('float-visible', data => {})
|
||||
|
||||
document.title = this.title
|
||||
this.getToc()
|
||||
},
|
||||
methods: {
|
||||
getToc() {
|
||||
fetch('book://cache/HTML5 canvas开发详解(第2版) (无)/toc.json')
|
||||
.then(r => r.json())
|
||||
.then(list => {
|
||||
for (let it of list) {
|
||||
delete it.id
|
||||
delete it.order
|
||||
}
|
||||
this.toc = list
|
||||
|
||||
this.viewChapter(list[23])
|
||||
})
|
||||
},
|
||||
|
||||
viewChapter(item) {
|
||||
let pathes = item.href.split('#')
|
||||
let file = pathes.shift()
|
||||
let hash = pathes.shift()
|
||||
|
||||
this.curr = item.title
|
||||
|
||||
if (this.file === file) {
|
||||
if (hash) {
|
||||
location.hash = hash
|
||||
} else {
|
||||
location.hash = ''
|
||||
this.$refs.chapter.scrollTop = 0
|
||||
}
|
||||
} else {
|
||||
this.file = file
|
||||
fetch('book://cache/HTML5 canvas开发详解(第2版) (无)/' + file)
|
||||
.then(r => r.text())
|
||||
.then(txt => {
|
||||
this.chapter = txt.replace(
|
||||
/<img[^>]*?src="(.*?)"[^>]*?\/?>/g,
|
||||
(m, s1) => {
|
||||
s1 = s1.replace('../', '')
|
||||
return `<img src="book://cache/${this.title}/${s1}">`
|
||||
}
|
||||
)
|
||||
|
||||
setTimeout(() => {
|
||||
if (hash) {
|
||||
location.hash = hash
|
||||
} else {
|
||||
location.hash = ''
|
||||
this.$refs.chapter.scrollTop = 0
|
||||
}
|
||||
}, 100)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
|
@ -1,253 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* @authors yutent (yutent.io@gmail.com)
|
||||
* @date 2020-12-08 11:30:52
|
||||
* @version v1.0.0
|
||||
*
|
||||
*/
|
||||
|
||||
import $ from '../utils.js'
|
||||
import '../form/button.js'
|
||||
|
||||
const DARK = '#62778d'
|
||||
const BLUE = '#64b5f6'
|
||||
const PLAIN = '#f2f5fc'
|
||||
|
||||
export default class Line extends HTMLElement {
|
||||
static get observedAttributes() {
|
||||
return ['list']
|
||||
}
|
||||
|
||||
props = {
|
||||
list: []
|
||||
}
|
||||
|
||||
state = {
|
||||
key: 1,
|
||||
list: []
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
Object.defineProperty(this, 'root', {
|
||||
value: this.attachShadow({ mode: 'open' }),
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
})
|
||||
|
||||
this.root.innerHTML = `<style>* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
::before,
|
||||
::after {
|
||||
box-sizing: border-box; }
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
width: 680px; }
|
||||
|
||||
.container {
|
||||
position: relative;
|
||||
padding: 24px 0 0; }
|
||||
|
||||
canvas {
|
||||
width: 680px;
|
||||
height: 230px; }
|
||||
|
||||
section {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0; }
|
||||
</style>
|
||||
<div class="container">
|
||||
<canvas></canvas>
|
||||
<section>
|
||||
<wc-button color="blue" data-key="1" size="mini">1月</wc-button>
|
||||
<wc-button data-key="3" size="mini">3月</wc-button>
|
||||
<wc-button data-key="6" size="mini">半年</wc-button>
|
||||
<wc-button data-key="12" size="mini">1年</wc-button>
|
||||
<wc-button data-key="36" size="mini">3年</wc-button>
|
||||
<wc-button data-key="999" size="mini">所有</wc-button>
|
||||
</section>
|
||||
</div>
|
||||
`
|
||||
|
||||
var elem = this.root.children[1]
|
||||
this.__SCENE__ = elem.firstElementChild
|
||||
this.__FILTER__ = elem.lastElementChild
|
||||
this.__CTX__ = this.__SCENE__.getContext('2d')
|
||||
this.__SCENE__.width = 680
|
||||
this.__SCENE__.height = 230
|
||||
}
|
||||
|
||||
_getTime(n) {
|
||||
var now = new Date()
|
||||
var time = { getTime: _ => 0 }
|
||||
var Y = now.getFullYear()
|
||||
var m = now.getMonth()
|
||||
var d = now.getDate()
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
time = new Date(Y, m - 1, d, 0, 0, 0)
|
||||
break
|
||||
case 3:
|
||||
time = new Date(Y, m - 3, d, 0, 0, 0)
|
||||
break
|
||||
case 6:
|
||||
time = new Date(Y, m - 6, d, 0, 0, 0)
|
||||
break
|
||||
case 12:
|
||||
time = new Date(Y - 1, m, d, 0, 0, 0)
|
||||
break
|
||||
case 36:
|
||||
time = new Date(Y - 3, m, d, 0, 0, 0)
|
||||
break
|
||||
}
|
||||
return time.getTime()
|
||||
}
|
||||
|
||||
_filter(n) {
|
||||
if (n < 999) {
|
||||
var time = this._getTime(n)
|
||||
this.state.list = this.props.list.filter(it => it.x >= time)
|
||||
} else {
|
||||
this.state.list = this.props.list.concat()
|
||||
}
|
||||
}
|
||||
|
||||
draw() {
|
||||
var { list, key } = this.state
|
||||
var ctx = this.__CTX__
|
||||
var x = 36
|
||||
var max = 0
|
||||
var min = Number.MAX_SAFE_INTEGER
|
||||
var step = 0 // 纵坐标间隔
|
||||
var dis = +(640 / list.length).toFixed(2) || 1 // 横坐标间隔
|
||||
var point
|
||||
var p1, p2, p3, p4
|
||||
var format = key > 12 ? 'Y/m' : 'm/d'
|
||||
|
||||
for (let it of list) {
|
||||
if (max < it.y) {
|
||||
max = it.y
|
||||
}
|
||||
if (min > it.y) {
|
||||
min = it.y
|
||||
}
|
||||
}
|
||||
|
||||
min = ~~(min / 100)
|
||||
max = Math.ceil(max / 100)
|
||||
step = ~~((max - min) / 3)
|
||||
|
||||
p1 = Math.floor(list.length / 4)
|
||||
p2 = Math.floor(list.length / 2)
|
||||
p3 = Math.floor((list.length * 3) / 4)
|
||||
p4 = list.length - 1
|
||||
|
||||
ctx.clearRect(0, 0, 680, 230)
|
||||
|
||||
// 纵坐标数值
|
||||
ctx.font = '12px Arial'
|
||||
ctx.textAlign = 'right'
|
||||
ctx.fillStyle = DARK
|
||||
ctx.fillText(min / 100, 32, 205)
|
||||
ctx.fillText((min + step) / 100, 32, 155)
|
||||
ctx.fillText((min + step + step) / 100, 32, 105)
|
||||
ctx.fillText((min + step + step + step) / 100, 32, 55)
|
||||
|
||||
ctx.font = '10px Arial'
|
||||
ctx.textAlign = 'left'
|
||||
ctx.fillText(new Date(list[0].x).format(format), x - 12, 225)
|
||||
ctx.fillText(new Date(list[p1].x).format(format), x + dis * p1 - 12, 225)
|
||||
ctx.fillText(new Date(list[p2].x).format(format), x + dis * p2 - 12, 225)
|
||||
ctx.fillText(new Date(list[p3].x).format(format), x + dis * p3 - 12, 225)
|
||||
ctx.fillText(
|
||||
new Date(list[p4].x).format(format),
|
||||
x + dis * p4 - 12 - (key > 12 ? 24 : 4),
|
||||
225
|
||||
)
|
||||
|
||||
// x轴参考线
|
||||
ctx.fillStyle = PLAIN
|
||||
ctx.fillRect(x, 50, 648, 1)
|
||||
ctx.fillRect(x, 100, 648, 1)
|
||||
ctx.fillRect(x, 150, 648, 1)
|
||||
ctx.fillRect(x, 200, 648, 1)
|
||||
|
||||
// y轴参考 线
|
||||
ctx.fillRect(x, 0, 1, 210)
|
||||
ctx.fillRect(x + dis * p1, 0, 1, 210)
|
||||
ctx.fillRect(x + dis * p2, 0, 1, 210)
|
||||
ctx.fillRect(x + dis * p3, 0, 1, 210)
|
||||
ctx.fillRect(x + dis * p4, 0, 1, 210)
|
||||
|
||||
point = list.shift()
|
||||
|
||||
// 曲线
|
||||
ctx.beginPath()
|
||||
ctx.strokeStyle = BLUE
|
||||
ctx.lineWidth = 1
|
||||
ctx.moveTo(x, 200 - (((point.y / 100 - min) / step) * 50).toFixed(0))
|
||||
|
||||
while (list.length) {
|
||||
let y
|
||||
|
||||
point = list.shift()
|
||||
|
||||
y = 200 - (((point.y / 100 - min) / step) * 50).toFixed(0)
|
||||
x += dis
|
||||
|
||||
ctx.lineTo(x, y)
|
||||
}
|
||||
ctx.stroke()
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
$.bind(this.__FILTER__, 'click', ev => {
|
||||
var el = ev.target
|
||||
if (this.props.list.length < 1) {
|
||||
return
|
||||
}
|
||||
if (el.tagName === 'WC-BUTTON') {
|
||||
var k = +el.dataset.key
|
||||
|
||||
$.each(this.__FILTER__.children, function(it) {
|
||||
it.removeAttribute('color')
|
||||
})
|
||||
el.setAttribute('color', 'blue')
|
||||
|
||||
this.state.key = k
|
||||
this._filter(k)
|
||||
this.draw()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, old, val) {
|
||||
if (val === null || old === val) {
|
||||
return
|
||||
}
|
||||
switch (name) {
|
||||
case 'list':
|
||||
try {
|
||||
var list = JSON.parse(val)
|
||||
list.forEach(it => (it.x = it.x * 1000))
|
||||
this.props.list = list
|
||||
this._filter(this.state.key)
|
||||
this.removeAttribute('list')
|
||||
this.draw()
|
||||
} catch (e) {}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!customElements.get('wc-line')) {
|
||||
customElements.define('wc-line', Line)
|
||||
}
|
|
@ -1,141 +0,0 @@
|
|||
/**
|
||||
*
|
||||
* @authors yutent (yutent.io@gmail.com)
|
||||
* @date 2020-12-08 11:30:52
|
||||
* @version v1.0.0
|
||||
*
|
||||
*/
|
||||
|
||||
const RED = '#ff5061'
|
||||
const GREEN = '#4caf50'
|
||||
const BLUE = '#64b5f6'
|
||||
const GREY = '#bdbdbd'
|
||||
const PLAIN = '#f2f5fc'
|
||||
const DARK = '#62778d'
|
||||
|
||||
export default class Rank extends HTMLElement {
|
||||
static get observedAttributes() {
|
||||
return ['stat']
|
||||
}
|
||||
|
||||
props = {
|
||||
stat: {}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
Object.defineProperty(this, 'root', {
|
||||
value: this.attachShadow({ mode: 'open' }),
|
||||
writable: true,
|
||||
enumerable: false,
|
||||
configurable: true
|
||||
})
|
||||
|
||||
this.root.innerHTML = `<style>* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
::before,
|
||||
::after {
|
||||
box-sizing: border-box; }
|
||||
|
||||
:host {
|
||||
display: flex; }
|
||||
|
||||
canvas {
|
||||
width: 680px;
|
||||
height: 100px; }
|
||||
</style>
|
||||
<canvas></canvas>
|
||||
`
|
||||
|
||||
this.__SCENE__ = this.root.children[1]
|
||||
this.__CTX__ = this.__SCENE__.getContext('2d')
|
||||
this.__SCENE__.width = 680
|
||||
this.__SCENE__.height = 100
|
||||
}
|
||||
|
||||
draw() {
|
||||
var { rank, e1, e3, e6, e12, cm, cp } = this.props.stat
|
||||
var ctx = this.__CTX__
|
||||
var x = 32
|
||||
|
||||
while (rank.length < 60) {
|
||||
rank.unshift(0)
|
||||
}
|
||||
|
||||
ctx.clearRect(0, 0, 680, 101)
|
||||
|
||||
ctx.font = '10px Arial'
|
||||
ctx.textAlign = 'right'
|
||||
ctx.fillStyle = RED
|
||||
ctx.fillText('10%', 28, 10)
|
||||
ctx.fillText('5%', 28, 30)
|
||||
ctx.fillStyle = GREEN
|
||||
ctx.fillText('-5%', 28, 80)
|
||||
ctx.fillText('-10%', 28, 100)
|
||||
|
||||
ctx.font = '10px menlo,Hiragino Sans GB'
|
||||
ctx.textAlign = 'left'
|
||||
ctx.fillStyle = DARK
|
||||
ctx.fillText('60天红绿榜', 160, 10)
|
||||
|
||||
ctx.font = '12px menlo,Hiragino Sans GB'
|
||||
ctx.fillText(`最近1个月收益: ${e1}%`, 360, 25)
|
||||
ctx.fillText(`最近3个月收益: ${e3}%`, 360, 45)
|
||||
ctx.fillText(`最近半年收益: ${e6}%`, 528, 25)
|
||||
ctx.fillText(`最近一年收益: ${e12}%`, 528, 45)
|
||||
|
||||
ctx.fillStyle = cp > 0 ? RED : cp === 0 ? GREY : GREEN
|
||||
ctx.fillRect(360, 65, 140, 20)
|
||||
ctx.fillRect(526, 65, 140, 20)
|
||||
ctx.fillStyle = '#fff'
|
||||
ctx.font = 'bold 14px menlo,Hiragino Sans GB'
|
||||
ctx.fillText(`实时净值: ¥${cm}`, 364, 80)
|
||||
ctx.fillText(`实时涨跌: ${cp}%`, 532, 80)
|
||||
|
||||
ctx.fillStyle = PLAIN
|
||||
ctx.fillRect(28, 25, 320, 1)
|
||||
ctx.fillRect(28, 75, 320, 1)
|
||||
ctx.fillStyle = GREY
|
||||
ctx.fillRect(28, 0, 1, 140)
|
||||
ctx.fillRect(0, 50, 348, 1)
|
||||
|
||||
while (rank.length) {
|
||||
var n = rank.shift()
|
||||
var y = Math.ceil(50 - (n / 10) * 50)
|
||||
|
||||
ctx.fillStyle = n > 0 ? RED : GREEN
|
||||
|
||||
if (y > 50) {
|
||||
ctx.fillRect(x, 50, 3, y - 50)
|
||||
} else {
|
||||
ctx.fillRect(x, y, 3, 50 - y)
|
||||
}
|
||||
|
||||
x += 5
|
||||
}
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, old, val) {
|
||||
if (val === null || old === val) {
|
||||
return
|
||||
}
|
||||
switch (name) {
|
||||
case 'stat':
|
||||
try {
|
||||
var stat = JSON.parse(val)
|
||||
this.props.stat = stat
|
||||
this.removeAttribute('stat')
|
||||
this.draw()
|
||||
} catch (e) {}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!customElements.get('wc-rank')) {
|
||||
customElements.define('wc-rank', Rank)
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
*
|
||||
* @authors yutent (yutent.io@gmail.com)
|
||||
* @date 2020-12-23 15:31:02
|
||||
* @version v1.0.0
|
||||
*
|
||||
*/
|
||||
|
||||
import"../scroll/index.js";import"../layer/index.js";import $ from"../utils.js";export default class Code extends HTMLElement{static get observedAttributes(){return["dark","lang"]}props={dark:"",lang:""};constructor(){super(),Object.defineProperty(this,"root",{value:this.attachShadow({mode:"open"}),writable:!0,enumerable:!1,configurable:!0}),this.root.innerHTML='<style>*{box-sizing:border-box;margin:0;padding:0}::before,::after{box-sizing:border-box}:host{--color-teal-1: #4db6ac;--color-teal-2: #26a69a;--color-teal-3: #009688;--color-green-1: #81c784;--color-green-2: #66bb6a;--color-green-3: #4caf50;--color-purple-1: #9575cd;--color-purple-2: #9575cd;--color-purple-3: #673ab7;--color-blue-1: #64b5f6;--color-blue-2: #42a5f5;--color-blue-3: #2196f3;--color-red-1: #ff5061;--color-red-2: #eb3b48;--color-red-3: #ce3742;--color-orange-1: #ffb618;--color-orange-2: #f39c12;--color-orange-3: #e67e22;--color-plain-1: #f2f5fc;--color-plain-2: #e8ebf4;--color-plain-3: #dae1e9;--color-grey-1: #bdbdbd;--color-grey-2: #9e9e9e;--color-grey-3: #757575;--color-dark-1: #62778d;--color-dark-2: #526273;--color-dark-3: #425064}:host{display:flex}.code-box{display:flex;flex-direction:column;position:relative;width:100%;max-height:610px;margin:10px 0;border:1px solid var(--color-plain-2);border-radius:2px}.code-box .title{display:flex;justify-content:space-between;align-items:center;width:100%;height:24px;padding:0 12px;line-height:1;font-size:12px;background:var(--color-plain-2);user-select:none}.code-box .title i{display:inline-block;width:10px;height:10px;margin-right:6px;border-radius:50%;background:var(--color-red-1)}.code-box .title i:nth-child(2){background:var(--color-orange-1)}.code-box .title i:nth-child(3){background:var(--color-green-1)}.code-box .title .act{--size: 16px;margin:0 2px;color:var(--color-grey-2);cursor:pointer}.code-box .title .act:hover{color:var(--color-grey-3)}.code-box .title .act.run{display:none}.code-box .code{flex:1;padding:5px 0;line-height:18px;font-family:Menlo, Monaco, Consolas, \'Courier New\', monospace;font-size:13px;background:linear-gradient(to right, var(--color-plain-1) 40px, #fff 40px);color:var(--color-dark-1);cursor:text;counter-reset:code}.code-box .code p{display:flex;position:relative;min-height:18px;padding:0 8px 0 45px;white-space:pre-wrap;word-wrap:break-word}.code-box .code p::before{position:absolute;left:0;width:40px;height:100%;padding-right:5px;text-align:right;color:var(--color-grey-1);content:counter(code);counter-increment:code}:host([exec]) .title .run{display:inline-block}:host([dark]) .code-box{border-color:var(--color-dark-2)}:host([dark]) .code-box .title{background:var(--color-dark-2)}:host([dark]) .code-box .code{background:linear-gradient(to right, #596b7f 40px, var(--color-dark-1) 40px);color:var(--color-plain-3)}:host([dark]) .code-box .code p::before{color:var(--color-grey-3)}</style> <div class="code-box"> <header class="title"> <span><i></i><i></i><i></i></span> <span></span> <span> <wc-icon title="运行" class="act run" is="live"></wc-icon> <wc-icon title="复制" class="act cp" is="doc"></wc-icon> </span> </header> <wc-scroll axis="y" class="code"></wc-scroll> </div> ';var e=this.root.children[1],o=e.children[0];this.__CODE__=e.children[1],this.__LANG__=o.children[1],this.__RUN__=o.children[2].firstElementChild,this.__CP__=o.children[2].lastElementChild}get value(){return this.props.content}set value(e){this.props.content=e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),e=(e=e.replace(/</g,"<").replace(/>/g,">").split("\n")).map(e=>`<p>${e}</p>`).join(""),this.__CODE__.innerHTML=e}connectedCallback(){var e=this.innerHTML||this.textContent;this.value=e.replace(/^[\r\n]|\s{2,}$/g,""),this.textContent="",this._cpFN=$.bind(this.__CP__,"click",e=>{try{navigator.clipboard.writeText(this.value),layer.toast("复制到粘贴板成功","success")}catch(e){layer.toast("复制到粘贴板失败","error")}}),this._runFN=$.bind(this.__RUN__,"click",e=>{this.dispatchEvent(new CustomEvent("run",{detail:this.value}))})}unmounted(){$.unbind(this.__CP__,"click",this._cpFN),$.unbind(this.__RUN__,"click",this._runFN)}attributeChangedCallback(e,o,r){if(null!==r&&o!==r)switch(e){case"lang":this.props.lang=r.toLowerCase(),this.__LANG__.textContent=this.props.lang;break;case"value":this.value=r,this.removeAttribute("value")}}}
|
||||
|
||||
if(!customElements.get('wc-code')){
|
||||
customElements.define('wc-code', Code)
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
import{Format,toS}from"./lib/format.js";const noop=function(e,t){this.defer.resolve(t)},NOBODY_METHODS=["GET","HEAD"],FORM_TYPES={form:"application/x-www-form-urlencoded; charset=UTF-8",json:"application/json; charset=UTF-8",text:"text/plain; charset=UTF-8"},ERRORS={10001:"Argument url is required",10012:"Parse error",10100:"Request canceled",10104:"Request pending...",10200:"Ok",10204:"No content",10304:"Not modified",10500:"Internal Server Error",10504:"Connected timeout"};Promise.defer=function(){var e={};return e.promise=new Promise(function(t,s){e.resolve=t,e.reject=s}),e};class _Request{constructor(e="",t={},{BASE_URL:s,__INIT__:r}){if(!e)throw new Error(ERRORS[10001]);if(e=e.replace(/#.*$/,""),s&&(/^([a-z]+:|\/\/)/.test(e)||(e=s+e)),t.method=(t.method||"get").toUpperCase(),this.xhr=new XMLHttpRequest,this.defer=Promise.defer(),this.options={headers:{"X-Requested-With":"XMLHttpRequest","content-type":FORM_TYPES.form},body:null,cache:"default",credentials:!1,signal:null,timeout:3e4},!t.signal){var o=new AbortController;t.signal=o.signal}this.defer.promise.abort=function(){o.abort()};var i=this.options.headers;return r.headers&&Object.assign(i,r.headers),t.headers&&(Object.assign(i,t.headers),delete t.headers),Object.assign(this.options,r,t,{url:e,headers:i}),this.__next__(),this.defer.promise}__next__(){var e=this.options,t=null,s=!1,r=!1,o=NOBODY_METHODS.includes(e.method);if(e.signal.onabort=(e=>{this.cancel=!0,this.xhr.abort()}),e.body)switch(typeof e.body){case"number":case"string":this.__type__("text"),t=e.body;break;case"object":if("FORM"===e.body.nodeName)e.method=e.body.method.toUpperCase()||"POST",s=(t=Format.parseForm(e.body)).constructor===FormData;else if(e.body.constructor===FormData)s=!0,o&&(e.method="POST"),t=e.body;else{for(let t in e.body)if("[object File]"===toS.call(e.body[t])){s=!0;break}s?(o&&(e.method="POST"),t=Format.mkFormData(e.body)):t=e.body}}s&&delete e.headers["content-type"];try{let t=document.createElement("a");t.href=e.url,r=location.protocol!==t.protocol||location.host!==t.host}catch(e){}r&&(e.credentials?this.xhr.withCredentials=!0:delete e.headers["X-Requested-With"]),o?((t=Format.param(t))&&(e.url+=(~e.url.indexOf("?")?"&":"?")+t),"no-store"===e.cache&&(e.url+=(~e.url.indexOf("?")?"&":"?")+"_t_="+Date.now())):s||(t=~e.headers["content-type"].indexOf("json")?JSON.stringify(t):Format.param(t)),this.xhr.responseType="blob",this.xhr.onreadystatechange=(t=>{e.timeout>0&&(e["time"+this.xhr.readyState]=t.timeStamp,4===this.xhr.readyState&&(e.isTimeout=e.time4-e.time1>e.timeout)),4===this.xhr.readyState&&this.__dispatch__(e.isTimeout)}),this.xhr.open(e.method,e.url);for(let t in e.headers)this.xhr.setRequestHeader(t,e.headers[t]);this.xhr.send(t),e.timeout&&e.timeout>0&&(this.xhr.timeout=e.timeout)}__type__(e){this.options.headers["content-type"]=FORM_TYPES[e]}__dispatch__(e){let t={status:200,statusText:"ok",body:"",headers:Object.create(null)};if(this.cancel)return this.__cancel__();if(e)return this.__timeout__();let s=this.xhr.status>=200&&this.xhr.status<400,r=this.xhr.getAllResponseHeaders().split("\n")||[];for(let e of r)if(e=e.trim()){let s=(e=e.split(":")).shift().toLowerCase();e=e.join(":").trim(),t.headers[s]=e}s?(t.status=this.xhr.status,204===t.status?t.statusText=ERRORS[10204]:304===t.status&&(t.statusText=ERRORS[10304])):(t.status=this.xhr.status||500,t.statusText=this.xhr.statusText||ERRORS[10500]),t.body=this.xhr.response,this.__success__(s,t)}__success__(e,t){var s=new _Response(t.status,t.statusText,t.body,t.headers);e?this.defer.resolve(s):this.defer.reject(s),delete this.xhr,delete this.options,delete this.defer}__cancel__(e){var t=new _Response(0,ERRORS[10100],Object.create(null));this.defer.reject(t),delete this.xhr,delete this.options,delete this.defer}__timeout__(e){var t=new _Response(504,ERRORS[10504],Object.create(null));this.defer.reject(t),delete this.xhr,delete this.options,delete this.defer}}class _Response{constructor(e=200,t="OK",s=null,r={}){this.status=e,this.statusText=t,this.ok=e>=200&&e<400,this.headers=r,Object.defineProperty(this,"__R__",{value:s,writable:!0,enumerable:!1,configurable:!0})}text(){return this.__R__.text()}json(){return this.__R__.text().then(e=>JSON.parse(e))}blob(){return this.__R__}arrayBuffer(){return this.__R__.arrayBuffer()}}const _fetch=function(e,t){return new _Request(e,t,{BASE_URL:_fetch.BASE_URL,__INIT__:_fetch.__INIT__||Object.create(null)})};_fetch.create=function(e,t=Object.create(null)){return function(s,r){return new _Request(s,r,{BASE_URL:e,__INIT__:t})}};export default _fetch;
|
|
@ -0,0 +1 @@
|
|||
export const toS=Object.prototype.toString;export const encode=encodeURIComponent;export const decode=decodeURIComponent;function serialize(e,t,o){var a;if(Array.isArray(t))t.forEach(function(t,r){a=e?`${e}[${Array.isArray(t)?r:""}]`:r,"object"==typeof t?serialize(a,t,o):o(a,t)});else for(let r in t)a=e?`${e}[${r}]`:r,"object"==typeof t[r]?serialize(a,t[r],o):o(a,t[r])}export const Format={parseForm(e){let t={},o=!1;for(let a,r=0;a=e.elements[r++];)switch(a.type){case"select-one":case"select-multiple":if(a.name.length&&!a.disabled)for(let e,o=0;e=a.options[o++];)e.selected&&(t[a.name]=e.value||e.text);break;case"file":a.name.length&&!a.disabled&&(t[a.name]=a.files[0],o=!0);break;case void 0:case"submit":case"reset":case"button":break;case"radio":case"checkbox":if(!a.checked)break;default:a.name.length&&!a.disabled&&(t[a.name]=a.value)}return o?this.mkFormData(t):t},mkFormData(e){let t=new FormData;for(let o in e){let a=e[o];Array.isArray(a)?a.forEach(function(e){t.append(o+"[]",e)}):t.append(o,e[o])}return t},param(e){if(!e||"string"==typeof e||"number"==typeof e)return e;let t=[];return"object"==typeof e&&serialize("",e,function(e,o){/native code/.test(o)||(o="function"==typeof o?o():o,o="[object File]"===toS.call(o)?o:encode(o),t.push(encode(e)+"="+o))}),t.join("&")}};
|
11
src/main.js
11
src/main.js
|
@ -9,7 +9,7 @@ const path = require('path')
|
|||
const fs = require('iofs')
|
||||
|
||||
require('./tools/init')
|
||||
const { createMainWindow, createFloatWindow } = require('./tools/window')
|
||||
const { createMainWindow, createViewWindow } = require('./tools/window')
|
||||
const createMenu = require('./tools/menu')
|
||||
const Socket = require('./tools/socket')
|
||||
|
||||
|
@ -50,7 +50,9 @@ protocol.registerSchemesAsPrivileged([
|
|||
app.once('ready', () => {
|
||||
// 注册协议
|
||||
protocol.registerStreamProtocol('app', function(req, cb) {
|
||||
var file = decodeURIComponent(req.url.replace(/^app:\/\/local\//, ''))
|
||||
var file = decodeURIComponent(
|
||||
req.url.replace(/^app:\/\/local\//, '')
|
||||
).replace(/\#.*$/, '')
|
||||
var ext = path.extname(file)
|
||||
|
||||
file = path.resolve(ROOT, file)
|
||||
|
@ -69,7 +71,6 @@ app.once('ready', () => {
|
|||
var ext = path.extname(file)
|
||||
|
||||
file = path.resolve(CACHE_DIR, file)
|
||||
console.log(file)
|
||||
cb({
|
||||
data: fs.origin.createReadStream(file),
|
||||
mimeType: MIME_TYPES[ext] || MIME_TYPES.all,
|
||||
|
@ -81,14 +82,14 @@ app.once('ready', () => {
|
|||
|
||||
// 创建浏览器窗口
|
||||
app.__main__ = createMainWindow(path.resolve(ROOT, './images/app.png'))
|
||||
// app.__float__ = createFloatWindow()
|
||||
app.__view__ = createViewWindow()
|
||||
|
||||
createMenu(app.__main__)
|
||||
Socket(app)
|
||||
|
||||
app.__main__.on('closed', () => {
|
||||
app.__main__ = null
|
||||
app.__float__ = null
|
||||
app.__view__ = null
|
||||
app.exit()
|
||||
})
|
||||
|
||||
|
|
|
@ -45,13 +45,18 @@ module.exports = function(app) {
|
|||
})
|
||||
break
|
||||
|
||||
case 'get-books':
|
||||
ev.returnValue = JSON.parse(fs.cat(DB_FILE))
|
||||
break
|
||||
|
||||
case 'parse-book':
|
||||
let { book, cate } = conn.data
|
||||
let eb = new Epub(book.path)
|
||||
let cache = JSON.parse(fs.cat(DB_FILE))
|
||||
|
||||
eb.on('end', async _ => {
|
||||
let { title, cover } = eb.metadata
|
||||
let { title } = eb.metadata
|
||||
let cover = 'cover'
|
||||
let dir = path.join(CACHE_DIR, title)
|
||||
|
||||
function saveImage(id, name) {
|
||||
|
@ -65,12 +70,21 @@ module.exports = function(app) {
|
|||
|
||||
function saveHtml(id, name) {
|
||||
return new Promise(done => {
|
||||
eb.getChapter(id, (err, txt) => {
|
||||
// txt = (txt + '').replace(
|
||||
// /<(?!img|image)([\w\-]+)[^>]*>/g,
|
||||
// '<$1>'
|
||||
// )
|
||||
fs.echo(txt, path.join(dir, name.replace('.xhtml', '.html')))
|
||||
eb.getChapterRaw(id, (err, txt) => {
|
||||
let m = (txt + '').match(/<body[^>]*?>([\w\W]+)<\/body>/)
|
||||
if (m) {
|
||||
let htm = m[1]
|
||||
.replace(
|
||||
/<(?!img|image)([\w\-]+)[^>]*?( id="[^\s]*?")?[^>]*?>/g,
|
||||
'<$1$2>'
|
||||
)
|
||||
.replace(/<pre><code>/g, '<wc-code>')
|
||||
.replace(/<\/code><\/pre>/g, '</wc-code>')
|
||||
|
||||
fs.echo(htm, path.join(dir, name.replace('.xhtml', '.html')))
|
||||
} else {
|
||||
console.log(id, name, txt)
|
||||
}
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
|
|
@ -27,10 +27,10 @@ exports.createMainWindow = function(icon) {
|
|||
|
||||
win.loadURL('app://local/index.html')
|
||||
|
||||
win.on('ready-to-show', _ => {
|
||||
win.show()
|
||||
win.openDevTools()
|
||||
})
|
||||
// win.on('ready-to-show', _ => {
|
||||
// win.show()
|
||||
// win.openDevTools()
|
||||
// })
|
||||
|
||||
win.on('close', ev => {
|
||||
ev.preventDefault()
|
||||
|
@ -41,16 +41,14 @@ exports.createMainWindow = function(icon) {
|
|||
}
|
||||
|
||||
// 创建悬浮窗口
|
||||
exports.createFloatWindow = function() {
|
||||
exports.createViewWindow = function() {
|
||||
var win = new BrowserWindow({
|
||||
width: 280,
|
||||
height: 360,
|
||||
resizable: false,
|
||||
maximizable: false,
|
||||
frame: false,
|
||||
show: false,
|
||||
vibrancy: 'hud',
|
||||
visualEffectState: 'active',
|
||||
width: 1024,
|
||||
height: 768,
|
||||
minWidth: 1024,
|
||||
minHeight: 768,
|
||||
// show: false,
|
||||
title: 'E-pub Reader',
|
||||
webPreferences: {
|
||||
experimentalFeatures: true,
|
||||
nodeIntegration: true,
|
||||
|
@ -58,13 +56,9 @@ exports.createFloatWindow = function() {
|
|||
}
|
||||
})
|
||||
|
||||
// win.openDevTools()
|
||||
win.openDevTools()
|
||||
|
||||
win.on('blur', ev => {
|
||||
win.hide()
|
||||
})
|
||||
|
||||
win.loadURL('app://local/float.html')
|
||||
win.loadURL('app://local/view.html')
|
||||
|
||||
return win
|
||||
}
|
||||
|
|
|
@ -6,31 +6,28 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
|
||||
<title></title>
|
||||
<link href="/lib/css/reset-basic.css" rel="stylesheet">
|
||||
<link href="/css/float.css" rel="stylesheet">
|
||||
<script src="/js/float.js" type="module"></script>
|
||||
<link href="/css/view.css" rel="stylesheet">
|
||||
<script src="/js/view.js" type="module"></script>
|
||||
</head>
|
||||
<body class="noselect">
|
||||
<body>
|
||||
|
||||
<div class="app" anot="app">
|
||||
<wc-scroll class="list">
|
||||
<section class="item" :for="it in list">
|
||||
<div class="info">
|
||||
<h3 class="text-ell" :text="it.name"></h3>
|
||||
<cite :text="it.code"></cite>
|
||||
</div>
|
||||
<div class="app" anot="app">
|
||||
<wc-scroll class="toc noselect">
|
||||
<item
|
||||
:for="it in toc"
|
||||
:class="{['lev-' + it.level]: 1, active: it.title === curr}"
|
||||
@click="viewChapter(it)"
|
||||
>
|
||||
<span class="text-ell" :attr-title="it.title" :text="it.title"></span>
|
||||
</item>
|
||||
</wc-scroll>
|
||||
|
||||
<div class="today">
|
||||
<span class="money" :text="'¥' + it.cm"></span>
|
||||
<span
|
||||
class="percent"
|
||||
:class="{red: it.cp > 0, green: it.cp < 0}"
|
||||
:text="it.cp + '%'">
|
||||
</span>
|
||||
</div>
|
||||
</section>
|
||||
<section :if="list.length === 0" class="item">啥基都没有...</section>
|
||||
</wc-scroll>
|
||||
</div>
|
||||
<wc-scroll class="chapter-box" ref="chapter">
|
||||
<div class="chapter">
|
||||
<article class="detail" :html="chapter"></article>
|
||||
</div>
|
||||
</wc-scroll>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
|
Loading…
Reference in New Issue