paginar 0.1.7 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/demo/slot/slot-chapter1.html +183 -5
- package/dist/index.es.js +760 -475
- package/dist/index.es.js.map +1 -1
- package/dist/style.css +126 -19
- package/package.json +1 -1
- package/src/App.ce.vue +25 -5
- package/src/assets/main.css +5 -0
- package/src/components/FootnotesAside.vue +123 -0
- package/src/components/HeaderSlot/OptionsButton/OptionsButton.vue +7 -1
- package/src/components/HeaderSlot/OptionsButton/OptionsDropdown.vue +16 -1
- package/src/components/HeaderSlot/SummaryButton/SummaryButton.vue +7 -1
- package/src/components/ReferencePopup.vue +6 -1
- package/src/components/icons/Footnote.vue +5 -0
- package/src/components/icons/Notes.vue +5 -0
- package/src/composables/useEstimatePages.js +28 -28
- package/src/composables/useFootnotes.js +25 -2
- package/src/composables/usePagination.js +14 -4
- package/src/composables/useReaderSettings.js +9 -1
- package/src/composables/useReferences.js +6 -14
- package/src/composables/useTextContent.js +30 -5
- package/src/tailwind.css +109 -19
package/dist/style.css
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
|
|
2
|
+
.width-enter-active[data-v-a72e8c45],
|
|
3
|
+
.width-leave-active[data-v-a72e8c45] {
|
|
4
|
+
transition: width .5s;
|
|
5
|
+
}
|
|
6
|
+
.width-enter-active>*[data-v-a72e8c45] {
|
|
7
|
+
transition-property: opacity;
|
|
8
|
+
transition-duration: .2s;
|
|
9
|
+
transition-delay: .3s;
|
|
10
|
+
}
|
|
11
|
+
.width-leave-active>*[data-v-a72e8c45] {
|
|
12
|
+
transition: opacity .25s;
|
|
13
|
+
}
|
|
14
|
+
.width-enter[data-v-a72e8c45],
|
|
15
|
+
.width-leave-to[data-v-a72e8c45] {
|
|
16
|
+
width: 0;
|
|
17
|
+
}
|
|
1
18
|
/*
|
|
2
19
|
! tailwindcss v3.1.8 | MIT License | https://tailwindcss.com
|
|
3
20
|
*/
|
|
@@ -563,10 +580,22 @@ video {
|
|
|
563
580
|
position: relative;
|
|
564
581
|
}
|
|
565
582
|
|
|
583
|
+
.top-0 {
|
|
584
|
+
top: 0px;
|
|
585
|
+
}
|
|
586
|
+
|
|
566
587
|
.right-0 {
|
|
567
588
|
right: 0px;
|
|
568
589
|
}
|
|
569
590
|
|
|
591
|
+
.top-4 {
|
|
592
|
+
top: 1rem;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.right-8 {
|
|
596
|
+
right: 2rem;
|
|
597
|
+
}
|
|
598
|
+
|
|
570
599
|
.bottom-0 {
|
|
571
600
|
bottom: 0px;
|
|
572
601
|
}
|
|
@@ -583,6 +612,10 @@ video {
|
|
|
583
612
|
left: -0.5rem;
|
|
584
613
|
}
|
|
585
614
|
|
|
615
|
+
.z-20 {
|
|
616
|
+
z-index: 20;
|
|
617
|
+
}
|
|
618
|
+
|
|
586
619
|
.z-40 {
|
|
587
620
|
z-index: 40;
|
|
588
621
|
}
|
|
@@ -614,6 +647,22 @@ video {
|
|
|
614
647
|
margin-bottom: 2rem;
|
|
615
648
|
}
|
|
616
649
|
|
|
650
|
+
.mb-6 {
|
|
651
|
+
margin-bottom: 1.5rem;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.ml-4 {
|
|
655
|
+
margin-left: 1rem;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.ml-10 {
|
|
659
|
+
margin-left: 2.5rem;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
.mt-10 {
|
|
663
|
+
margin-top: 2.5rem;
|
|
664
|
+
}
|
|
665
|
+
|
|
617
666
|
.mt-3 {
|
|
618
667
|
margin-top: 0.75rem;
|
|
619
668
|
}
|
|
@@ -626,10 +675,6 @@ video {
|
|
|
626
675
|
margin-left: 0.75rem;
|
|
627
676
|
}
|
|
628
677
|
|
|
629
|
-
.ml-4 {
|
|
630
|
-
margin-left: 1rem;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
678
|
.mb-2 {
|
|
634
679
|
margin-bottom: 0.5rem;
|
|
635
680
|
}
|
|
@@ -650,14 +695,22 @@ video {
|
|
|
650
695
|
display: none;
|
|
651
696
|
}
|
|
652
697
|
|
|
653
|
-
.h-
|
|
654
|
-
height:
|
|
698
|
+
.h-screen {
|
|
699
|
+
height: 100vh;
|
|
655
700
|
}
|
|
656
701
|
|
|
657
702
|
.h-6 {
|
|
658
703
|
height: 1.5rem;
|
|
659
704
|
}
|
|
660
705
|
|
|
706
|
+
.h-8 {
|
|
707
|
+
height: 2rem;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.h-full {
|
|
711
|
+
height: 100%;
|
|
712
|
+
}
|
|
713
|
+
|
|
661
714
|
.h-10 {
|
|
662
715
|
height: 2.5rem;
|
|
663
716
|
}
|
|
@@ -670,14 +723,22 @@ video {
|
|
|
670
723
|
width: 100%;
|
|
671
724
|
}
|
|
672
725
|
|
|
673
|
-
.w-
|
|
674
|
-
width:
|
|
726
|
+
.w-96 {
|
|
727
|
+
width: 24rem;
|
|
675
728
|
}
|
|
676
729
|
|
|
677
730
|
.w-6 {
|
|
678
731
|
width: 1.5rem;
|
|
679
732
|
}
|
|
680
733
|
|
|
734
|
+
.w-8 {
|
|
735
|
+
width: 2rem;
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.w-4\/5 {
|
|
739
|
+
width: 80%;
|
|
740
|
+
}
|
|
741
|
+
|
|
681
742
|
.w-5 {
|
|
682
743
|
width: 1.25rem;
|
|
683
744
|
}
|
|
@@ -686,6 +747,10 @@ video {
|
|
|
686
747
|
width: 15rem;
|
|
687
748
|
}
|
|
688
749
|
|
|
750
|
+
.flex-shrink-0 {
|
|
751
|
+
flex-shrink: 0;
|
|
752
|
+
}
|
|
753
|
+
|
|
689
754
|
.scale-95 {
|
|
690
755
|
--tw-scale-x: .95;
|
|
691
756
|
--tw-scale-y: .95;
|
|
@@ -738,10 +803,18 @@ video {
|
|
|
738
803
|
align-self: flex-end;
|
|
739
804
|
}
|
|
740
805
|
|
|
806
|
+
.overflow-auto {
|
|
807
|
+
overflow: auto;
|
|
808
|
+
}
|
|
809
|
+
|
|
741
810
|
.overflow-hidden {
|
|
742
811
|
overflow: hidden;
|
|
743
812
|
}
|
|
744
813
|
|
|
814
|
+
.overflow-x-hidden {
|
|
815
|
+
overflow-x: hidden;
|
|
816
|
+
}
|
|
817
|
+
|
|
745
818
|
.rounded {
|
|
746
819
|
border-radius: 0.25rem;
|
|
747
820
|
}
|
|
@@ -772,6 +845,10 @@ video {
|
|
|
772
845
|
border-color: rgb(209 213 219 / var(--tw-border-opacity));
|
|
773
846
|
}
|
|
774
847
|
|
|
848
|
+
.border-b-white\/25 {
|
|
849
|
+
border-bottom-color: rgb(255 255 255 / 0.25);
|
|
850
|
+
}
|
|
851
|
+
|
|
775
852
|
.bg-gray-800 {
|
|
776
853
|
--tw-bg-opacity: 1;
|
|
777
854
|
background-color: rgb(31 41 55 / var(--tw-bg-opacity));
|
|
@@ -800,6 +877,11 @@ video {
|
|
|
800
877
|
padding-right: 2.5rem;
|
|
801
878
|
}
|
|
802
879
|
|
|
880
|
+
.py-4 {
|
|
881
|
+
padding-top: 1rem;
|
|
882
|
+
padding-bottom: 1rem;
|
|
883
|
+
}
|
|
884
|
+
|
|
803
885
|
.px-2 {
|
|
804
886
|
padding-left: 0.5rem;
|
|
805
887
|
padding-right: 0.5rem;
|
|
@@ -810,11 +892,6 @@ video {
|
|
|
810
892
|
padding-bottom: 0.75rem;
|
|
811
893
|
}
|
|
812
894
|
|
|
813
|
-
.py-4 {
|
|
814
|
-
padding-top: 1rem;
|
|
815
|
-
padding-bottom: 1rem;
|
|
816
|
-
}
|
|
817
|
-
|
|
818
895
|
.px-3 {
|
|
819
896
|
padding-left: 0.75rem;
|
|
820
897
|
padding-right: 0.75rem;
|
|
@@ -824,6 +901,14 @@ video {
|
|
|
824
901
|
padding-top: 2.5rem;
|
|
825
902
|
}
|
|
826
903
|
|
|
904
|
+
.pl-4 {
|
|
905
|
+
padding-left: 1rem;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
.pb-10 {
|
|
909
|
+
padding-bottom: 2.5rem;
|
|
910
|
+
}
|
|
911
|
+
|
|
827
912
|
.text-left {
|
|
828
913
|
text-align: left;
|
|
829
914
|
}
|
|
@@ -851,6 +936,10 @@ video {
|
|
|
851
936
|
font-weight: 300;
|
|
852
937
|
}
|
|
853
938
|
|
|
939
|
+
.lowercase {
|
|
940
|
+
text-transform: lowercase;
|
|
941
|
+
}
|
|
942
|
+
|
|
854
943
|
.tracking-wide {
|
|
855
944
|
letter-spacing: 0.025em;
|
|
856
945
|
}
|
|
@@ -875,6 +964,10 @@ video {
|
|
|
875
964
|
color: rgb(0 0 0 / var(--tw-text-opacity));
|
|
876
965
|
}
|
|
877
966
|
|
|
967
|
+
.opacity-50 {
|
|
968
|
+
opacity: 0.5;
|
|
969
|
+
}
|
|
970
|
+
|
|
878
971
|
.opacity-100 {
|
|
879
972
|
opacity: 1;
|
|
880
973
|
}
|
|
@@ -891,6 +984,12 @@ video {
|
|
|
891
984
|
opacity: 0.3;
|
|
892
985
|
}
|
|
893
986
|
|
|
987
|
+
.shadow-2xl {
|
|
988
|
+
--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
|
|
989
|
+
--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);
|
|
990
|
+
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
|
|
991
|
+
}
|
|
992
|
+
|
|
894
993
|
.shadow {
|
|
895
994
|
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
896
995
|
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
|
|
@@ -915,12 +1014,6 @@ video {
|
|
|
915
1014
|
transition-duration: 150ms;
|
|
916
1015
|
}
|
|
917
1016
|
|
|
918
|
-
.transition-opacity {
|
|
919
|
-
transition-property: opacity;
|
|
920
|
-
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
921
|
-
transition-duration: 150ms;
|
|
922
|
-
}
|
|
923
|
-
|
|
924
1017
|
.transition {
|
|
925
1018
|
transition-property: color, background-color, border-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-text-decoration-color, -webkit-backdrop-filter;
|
|
926
1019
|
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
|
|
@@ -929,6 +1022,12 @@ video {
|
|
|
929
1022
|
transition-duration: 150ms;
|
|
930
1023
|
}
|
|
931
1024
|
|
|
1025
|
+
.transition-opacity {
|
|
1026
|
+
transition-property: opacity;
|
|
1027
|
+
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
1028
|
+
transition-duration: 150ms;
|
|
1029
|
+
}
|
|
1030
|
+
|
|
932
1031
|
.duration-100 {
|
|
933
1032
|
transition-duration: 100ms;
|
|
934
1033
|
}
|
|
@@ -949,6 +1048,10 @@ video {
|
|
|
949
1048
|
transition-timing-function: cubic-bezier(0.4, 0, 1, 1);
|
|
950
1049
|
}
|
|
951
1050
|
|
|
1051
|
+
.last\:border-transparent:last-child {
|
|
1052
|
+
border-color: transparent;
|
|
1053
|
+
}
|
|
1054
|
+
|
|
952
1055
|
.hover\:bg-gray-100:hover {
|
|
953
1056
|
--tw-bg-opacity: 1;
|
|
954
1057
|
background-color: rgb(243 244 246 / var(--tw-bg-opacity));
|
|
@@ -986,6 +1089,10 @@ video {
|
|
|
986
1089
|
display: grid;
|
|
987
1090
|
}
|
|
988
1091
|
|
|
1092
|
+
.md\:w-\[40em\] {
|
|
1093
|
+
width: 40em;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
989
1096
|
.md\:w-2\/5 {
|
|
990
1097
|
width: 40%;
|
|
991
1098
|
}
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"description": "A flipping page web component for reading long texts on the brower",
|
|
5
5
|
"main": "dist/index.es.js",
|
|
6
6
|
"module": "dist/index.es.js",
|
|
7
|
-
"version": "0.1
|
|
7
|
+
"version": "0.2.1",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/educkf/paginar.git"
|
package/src/App.ce.vue
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import { ref, onMounted, defineProps,
|
|
2
|
+
import { ref, onMounted, defineProps, watch } from 'vue'
|
|
3
3
|
import { useWindowSize, watchDebounced } from '@vueuse/core'
|
|
4
4
|
|
|
5
5
|
import HeaderSlot from './components/HeaderSlot/HeaderSlot.vue'
|
|
@@ -8,18 +8,19 @@ import EngineWrapper from './components/EngineWrapper.vue'
|
|
|
8
8
|
import ReaderWrapper from './components/ReaderWrapper.vue'
|
|
9
9
|
import ReferencePopup from './components/ReferencePopup.vue'
|
|
10
10
|
import FooterSlot from './components/FooterSlot.vue'
|
|
11
|
+
import FootnotesAside from './components/FootnotesAside.vue'
|
|
11
12
|
|
|
12
13
|
import usePagination from './composables/usePagination'
|
|
13
14
|
import useEstimatePages from './composables/useEstimatePages'
|
|
14
15
|
import useTextContent from './composables/useTextContent'
|
|
15
16
|
import useReaderSettings from './composables/useReaderSettings'
|
|
16
|
-
import useReferences from './composables/useReferences'
|
|
17
17
|
import useStyles from './composables/useStyles'
|
|
18
18
|
|
|
19
19
|
const props = defineProps({
|
|
20
20
|
bookTitle: String,
|
|
21
21
|
bookContent: String,
|
|
22
22
|
readerSettings: String,
|
|
23
|
+
readerBlocked: Boolean,
|
|
23
24
|
rootClass: {
|
|
24
25
|
type: String,
|
|
25
26
|
default: ''
|
|
@@ -30,8 +31,7 @@ const props = defineProps({
|
|
|
30
31
|
|
|
31
32
|
const { initSettings, baseFont, textFont, fontSize, columns, setColumns, mode } = useReaderSettings
|
|
32
33
|
const { currentPage, totalPages, init } = usePagination
|
|
33
|
-
const { content } = useTextContent
|
|
34
|
-
const { listenToReferencesClick } = useReferences
|
|
34
|
+
const { content, listenToClicks } = useTextContent
|
|
35
35
|
const { width, height } = useWindowSize()
|
|
36
36
|
|
|
37
37
|
const readerComponent = ref(null)
|
|
@@ -42,6 +42,10 @@ onMounted(async () => {
|
|
|
42
42
|
init(readerComponent, contentArea)
|
|
43
43
|
initSettings(props.readerSettings)
|
|
44
44
|
|
|
45
|
+
if (['string', 'boolean'].includes(typeof props.readerBlocked)) {
|
|
46
|
+
useReaderSettings.setBlocked(props.readerBlocked)
|
|
47
|
+
}
|
|
48
|
+
|
|
45
49
|
if (props.cssFile) {
|
|
46
50
|
useStyles.stylesheetLoader(props.cssFile, rootComponent)
|
|
47
51
|
}
|
|
@@ -51,6 +55,20 @@ onMounted(async () => {
|
|
|
51
55
|
}
|
|
52
56
|
})
|
|
53
57
|
|
|
58
|
+
watch(
|
|
59
|
+
props,
|
|
60
|
+
() => {
|
|
61
|
+
console.log(props)
|
|
62
|
+
if (props.hasOwnProperty('readerBlocked')) {
|
|
63
|
+
const readerBlocked = typeof props.readerBlocked === 'boolean'
|
|
64
|
+
? props.readerBlocked
|
|
65
|
+
: props.readerBlocked === 'true'
|
|
66
|
+
console.log(readerBlocked)
|
|
67
|
+
useReaderSettings.setBlocked(readerBlocked)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
|
|
54
72
|
watchDebounced(
|
|
55
73
|
[width, height, content, columns, fontSize, textFont],
|
|
56
74
|
() => {
|
|
@@ -63,7 +81,7 @@ watchDebounced(
|
|
|
63
81
|
)
|
|
64
82
|
|
|
65
83
|
watchDebounced(content,
|
|
66
|
-
() =>
|
|
84
|
+
() => listenToClicks(contentArea),
|
|
67
85
|
{ debounce: 125, maxWait: 250 }
|
|
68
86
|
)
|
|
69
87
|
|
|
@@ -126,6 +144,8 @@ watchDebounced(content,
|
|
|
126
144
|
|
|
127
145
|
<ReferencePopup />
|
|
128
146
|
</main>
|
|
147
|
+
|
|
148
|
+
<FootnotesAside />
|
|
129
149
|
</div>
|
|
130
150
|
</template>
|
|
131
151
|
|
package/src/assets/main.css
CHANGED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, onMounted, watch, ref } from 'vue'
|
|
3
|
+
import { onKeyStroke } from '@vueuse/core'
|
|
4
|
+
|
|
5
|
+
import useFootnotes from '../composables/useFootnotes'
|
|
6
|
+
import useReaderSettings from '../composables/useReaderSettings'
|
|
7
|
+
|
|
8
|
+
import IconClose from '../components/icons/Close.vue'
|
|
9
|
+
import IconNotes from '../components/icons/Notes.vue'
|
|
10
|
+
|
|
11
|
+
const show = computed(() => useFootnotes.footnote.value)
|
|
12
|
+
const footnote = computed(() => useFootnotes.footnote.value)
|
|
13
|
+
const showFootnotes = computed(() => useFootnotes.showFootnotes.value)
|
|
14
|
+
const footnotes = computed(() => useFootnotes.footnotes.value)
|
|
15
|
+
|
|
16
|
+
const oldBlockedValue = ref(null)
|
|
17
|
+
const footnoteList = ref(null)
|
|
18
|
+
|
|
19
|
+
function hideAside() {
|
|
20
|
+
useFootnotes.setHighlightedFootnote(null)
|
|
21
|
+
useFootnotes.setShowFootnotes(false)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
onKeyStroke('Escape', () => {
|
|
25
|
+
if (footnote.value || showFootnotes.value) {
|
|
26
|
+
hideAside()
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
watch(
|
|
31
|
+
[footnote, showFootnotes],
|
|
32
|
+
() => {
|
|
33
|
+
if (footnote.value || showFootnotes.value) {
|
|
34
|
+
if (useReaderSettings.blocked.value === false) {
|
|
35
|
+
oldBlockedValue.value = useReaderSettings.blocked.value
|
|
36
|
+
}
|
|
37
|
+
useReaderSettings.setBlocked(true)
|
|
38
|
+
|
|
39
|
+
} else {
|
|
40
|
+
if (oldBlockedValue.value === false) {
|
|
41
|
+
useReaderSettings.setBlocked(oldBlockedValue.value)
|
|
42
|
+
}
|
|
43
|
+
oldBlockedValue.value = null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (footnote.value) {
|
|
47
|
+
setTimeout(() => {
|
|
48
|
+
const element = footnoteList.value.querySelector(`#${footnote.value.id}`)
|
|
49
|
+
element.scrollIntoView()
|
|
50
|
+
element.focus()
|
|
51
|
+
}, 50)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<template>
|
|
59
|
+
<transition name="width">
|
|
60
|
+
<div v-if="show || showFootnotes" id="asidebar"
|
|
61
|
+
class="absolute top-0 right-0 w-96 md:w-[40em] flex-shrink-0 h-screen overflow-auto overflow-x-hidden z-20 shadow-2xl"
|
|
62
|
+
>
|
|
63
|
+
<button @click.prevent="hideAside()" class="fixed top-4 right-8 z-20">
|
|
64
|
+
<IconClose class="w-6 h-6 text-white" />
|
|
65
|
+
</button>
|
|
66
|
+
|
|
67
|
+
<div class="w-full p-4">
|
|
68
|
+
<header class="text-areia py-4 pl-4">
|
|
69
|
+
<div class="flex items-center mb-6">
|
|
70
|
+
<IconNotes class="w-8 h-8" />
|
|
71
|
+
<span class="ml-4">
|
|
72
|
+
|
|
73
|
+
Notas de rodapé
|
|
74
|
+
<span class="ml-10">
|
|
75
|
+
{{ footnotes.length }}
|
|
76
|
+
</span>
|
|
77
|
+
</span>
|
|
78
|
+
</div>
|
|
79
|
+
</header>
|
|
80
|
+
|
|
81
|
+
<section>
|
|
82
|
+
<ul ref="footnoteList">
|
|
83
|
+
<li v-for="(footnoteItem, index) in footnotes"
|
|
84
|
+
:key="footnoteItem.id"
|
|
85
|
+
:id="footnoteItem.id"
|
|
86
|
+
v-html="`<span class='footnote-index'>${index + 1}.</span> ${footnoteItem.text}`"
|
|
87
|
+
class="text-left border-b border-b-white/25 last:border-transparent
|
|
88
|
+
pb-10 mt-10 px-10 relative
|
|
89
|
+
"
|
|
90
|
+
:class="footnote && footnote.id !== footnoteItem.id
|
|
91
|
+
? 'opacity-50'
|
|
92
|
+
: 'opacity-100'
|
|
93
|
+
"></li>
|
|
94
|
+
</ul>
|
|
95
|
+
</section>
|
|
96
|
+
</div>
|
|
97
|
+
</div>
|
|
98
|
+
</transition>
|
|
99
|
+
</template>
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
<style scoped>
|
|
104
|
+
.width-enter-active,
|
|
105
|
+
.width-leave-active {
|
|
106
|
+
transition: width .5s;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.width-enter-active>* {
|
|
110
|
+
transition-property: opacity;
|
|
111
|
+
transition-duration: .2s;
|
|
112
|
+
transition-delay: .3s;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.width-leave-active>* {
|
|
116
|
+
transition: opacity .25s;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.width-enter,
|
|
120
|
+
.width-leave-to {
|
|
121
|
+
width: 0;
|
|
122
|
+
}
|
|
123
|
+
</style>
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { ref } from 'vue'
|
|
3
3
|
import { onClickOutside, onKeyStroke, useFullscreen } from '@vueuse/core'
|
|
4
4
|
|
|
5
|
+
import useReaderSettings from '../../../composables/useReaderSettings'
|
|
6
|
+
|
|
5
7
|
import IconThreeDots from '../../icons/ThreeDots.vue'
|
|
6
8
|
import IconClose from '../../icons/Close.vue'
|
|
7
9
|
import IconExpand from '../../icons/Expand.vue'
|
|
@@ -11,7 +13,11 @@ const show = ref(false)
|
|
|
11
13
|
const button = ref(null)
|
|
12
14
|
|
|
13
15
|
const toggleSummary = () => show.value = !show.value
|
|
14
|
-
const hide = () =>
|
|
16
|
+
const hide = () => {
|
|
17
|
+
if (!useReaderSettings.blocked.value) {
|
|
18
|
+
show.value = false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
15
21
|
|
|
16
22
|
onClickOutside(button, () => hide())
|
|
17
23
|
onKeyStroke('Escape', () => hide())
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import IconEye from '../../icons/Eye.vue'
|
|
3
|
+
import IconFootnote from '../../icons/Footnote.vue'
|
|
4
|
+
|
|
3
5
|
import OptionsColumns from './OptionsColumns.vue';
|
|
4
6
|
import OptionsFontFamily from './OptionsFontFamily.vue';
|
|
5
7
|
import OptionsFontSize from './OptionsFontSize.vue';
|
|
6
8
|
import OptionsColor from './OptionsColor.vue'
|
|
9
|
+
|
|
10
|
+
import useFootnotes from '../../../composables/useFootnotes'
|
|
11
|
+
|
|
7
12
|
</script>
|
|
8
13
|
|
|
9
14
|
<template>
|
|
@@ -18,7 +23,17 @@ import OptionsColor from './OptionsColor.vue'
|
|
|
18
23
|
|
|
19
24
|
<slot name="optionsTop" />
|
|
20
25
|
|
|
21
|
-
<
|
|
26
|
+
<button @click.prevent="useFootnotes.setShowFootnotes(true)"
|
|
27
|
+
class="w-full flex justify-center items-center py-3 lowercase"
|
|
28
|
+
>
|
|
29
|
+
<IconFootnote class="w-6 h-6" />
|
|
30
|
+
<span class="ml-4">Notas de rodapé</span>
|
|
31
|
+
</button>
|
|
32
|
+
|
|
33
|
+
<div class="w-full border-b border-areia my-3"></div>
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
<div class="w-full flex justify-center items-center py-3 lowercase">
|
|
22
37
|
<IconEye class="w-6 h-6" />
|
|
23
38
|
<span class="ml-4">Visualização</span>
|
|
24
39
|
</div>
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
import { ref } from 'vue'
|
|
3
3
|
import { onClickOutside, onKeyStroke } from '@vueuse/core'
|
|
4
4
|
|
|
5
|
+
import useReaderSettings from '../../../composables/useReaderSettings'
|
|
6
|
+
|
|
5
7
|
import IconHome from '../../icons/Home.vue'
|
|
6
8
|
import IconClose from '../../icons/Close.vue'
|
|
7
9
|
import IconSummary from '../../icons/Summary.vue'
|
|
@@ -11,7 +13,11 @@ const show = ref(false)
|
|
|
11
13
|
const button = ref(null)
|
|
12
14
|
|
|
13
15
|
const toggleSummary = () => show.value = !show.value
|
|
14
|
-
const hide = () =>
|
|
16
|
+
const hide = () => {
|
|
17
|
+
if (!useReaderSettings.blocked.value) {
|
|
18
|
+
show.value = false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
15
21
|
|
|
16
22
|
onClickOutside(button, () => hide())
|
|
17
23
|
onKeyStroke('Escape', () => hide())
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { onKeyStroke } from '@vueuse/core'
|
|
3
|
+
|
|
4
|
+
import useReaderSettings from '../composables/useReaderSettings'
|
|
3
5
|
import useReferences from '../composables/useReferences'
|
|
6
|
+
|
|
4
7
|
const { reference, setHighlightedReference } = useReferences
|
|
5
8
|
|
|
6
9
|
function closeRef() {
|
|
@@ -8,7 +11,9 @@ function closeRef() {
|
|
|
8
11
|
}
|
|
9
12
|
|
|
10
13
|
onKeyStroke('Escape', () => {
|
|
11
|
-
|
|
14
|
+
if (!useReaderSettings.blocked.value) {
|
|
15
|
+
setHighlightedReference(null)
|
|
16
|
+
}
|
|
12
17
|
})
|
|
13
18
|
|
|
14
19
|
</script>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
|
3
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
4
|
+
</svg>
|
|
5
|
+
</template>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
3
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z" />
|
|
4
|
+
</svg>
|
|
5
|
+
</template>
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import { computed, reactive } from 'vue'
|
|
2
|
-
|
|
3
|
-
const state = reactive({
|
|
4
|
-
totalPages: 1
|
|
5
|
-
})
|
|
6
|
-
|
|
7
|
-
function estimate(viewport, content) {
|
|
8
|
-
if (viewport && content) {
|
|
9
|
-
const { width: viewportWidth } = viewport.value.getBoundingClientRect()
|
|
10
|
-
const { width: contentWidth } = content.value.getBoundingClientRect()
|
|
11
|
-
|
|
12
|
-
if (contentWidth > viewportWidth) {
|
|
13
|
-
state.totalPages = Math.ceil(contentWidth / viewportWidth)
|
|
14
|
-
|
|
15
|
-
} else {
|
|
16
|
-
state.totalPages = 1
|
|
17
|
-
}
|
|
18
|
-
} else {
|
|
19
|
-
state.totalPages = 1
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const totalPages = computed(() => state.totalPages)
|
|
24
|
-
|
|
25
|
-
export default {
|
|
26
|
-
totalPages,
|
|
27
|
-
estimate
|
|
28
|
-
}
|
|
1
|
+
import { computed, reactive } from 'vue'
|
|
2
|
+
|
|
3
|
+
const state = reactive({
|
|
4
|
+
totalPages: 1
|
|
5
|
+
})
|
|
6
|
+
|
|
7
|
+
function estimate(viewport, content) {
|
|
8
|
+
if (viewport && content) {
|
|
9
|
+
const { width: viewportWidth } = viewport.value.getBoundingClientRect()
|
|
10
|
+
const { width: contentWidth } = content.value.getBoundingClientRect()
|
|
11
|
+
|
|
12
|
+
if (contentWidth > viewportWidth) {
|
|
13
|
+
state.totalPages = Math.ceil(contentWidth / viewportWidth)
|
|
14
|
+
|
|
15
|
+
} else {
|
|
16
|
+
state.totalPages = 1
|
|
17
|
+
}
|
|
18
|
+
} else {
|
|
19
|
+
state.totalPages = 1
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const totalPages = computed(() => state.totalPages)
|
|
24
|
+
|
|
25
|
+
export default {
|
|
26
|
+
totalPages,
|
|
27
|
+
estimate
|
|
28
|
+
}
|