paginar 0.3.0 → 0.3.2
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/.editorconfig +13 -13
- package/.env +1 -1
- package/.vscode/extensions.json +3 -3
- package/LICENSE.md +21 -21
- package/README.md +244 -244
- package/demo/slot/slot-chapter1.html +384 -384
- package/demo/slot/slot-chapter2.html +366 -366
- package/demo/slot/slot-chapter3.html +265 -265
- package/demo/summary/_content/1chapter.html +100 -100
- package/demo/summary/_content/2chapter.html +311 -311
- package/demo/summary/_content/3chapter.html +211 -211
- package/demo/summary/index.html +134 -134
- package/dist/index.es.js +849 -840
- package/dist/index.es.js.map +1 -1
- package/dist/style.css +9 -9
- package/index.html +18 -18
- package/package.json +1 -1
- package/src/App.ce.vue +148 -148
- package/src/assets/main.css +392 -392
- package/src/components/BookContent.vue +23 -23
- package/src/components/FooterSlot.vue +32 -32
- package/src/components/FootnotesAside.vue +123 -123
- package/src/components/HeaderSlot/HeaderSlot.vue +30 -30
- package/src/components/HeaderSlot/OptionsButton/OptionsButton.vue +67 -67
- package/src/components/HeaderSlot/OptionsButton/OptionsColor.vue +28 -28
- package/src/components/HeaderSlot/OptionsButton/OptionsColumns.vue +51 -51
- package/src/components/HeaderSlot/OptionsButton/OptionsDropdown.vue +59 -59
- package/src/components/HeaderSlot/OptionsButton/OptionsFontFamily.vue +17 -17
- package/src/components/HeaderSlot/OptionsButton/OptionsFontSize.vue +17 -17
- package/src/components/HeaderSlot/SummaryButton/SummaryButton.vue +70 -70
- package/src/components/HeaderSlot/SummaryButton/SummaryDropdown.vue +6 -6
- package/src/components/ReaderWrapper.vue +37 -37
- package/src/components/ReferencePopup.vue +36 -36
- package/src/components/icons/Close.vue +6 -6
- package/src/components/icons/DoubleColumn.vue +15 -15
- package/src/components/icons/Expand.vue +7 -7
- package/src/components/icons/Eye.vue +9 -9
- package/src/components/icons/Footnote.vue +5 -5
- package/src/components/icons/Home.vue +6 -6
- package/src/components/icons/Moon.vue +5 -5
- package/src/components/icons/Notes.vue +5 -5
- package/src/components/icons/SingleColumn.vue +3 -3
- package/src/components/icons/Summary.vue +10 -10
- package/src/components/icons/Sun.vue +5 -5
- package/src/components/icons/ThreeDots.vue +8 -8
- package/src/composables/useBrowser.js +16 -16
- package/src/composables/useFootnotes.js +50 -50
- package/src/composables/usePagination.js +125 -125
- package/src/composables/useReaderSettings.js +174 -174
- package/src/composables/useReferences.js +67 -67
- package/src/composables/useStyles.js +60 -60
- package/src/composables/useTextContent.js +113 -113
- package/src/main.js +19 -19
- package/tailwind.config.js +16 -16
- package/vite.config.js +36 -36
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { defineProps, onMounted, ref } from 'vue'
|
|
3
|
-
|
|
4
|
-
import useTextContent from '../composables/useTextContent'
|
|
5
|
-
const { content, initContent } = useTextContent
|
|
6
|
-
|
|
7
|
-
const props = defineProps({
|
|
8
|
-
bookContent: String
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
const contentWrapper = ref(null)
|
|
12
|
-
|
|
13
|
-
onMounted(() => {
|
|
14
|
-
initContent(props.bookContent, contentWrapper)
|
|
15
|
-
})
|
|
16
|
-
</script>
|
|
17
|
-
|
|
18
|
-
<template>
|
|
19
|
-
<div ref="contentWrapper">
|
|
20
|
-
<div v-if="content" v-html="content"></div>
|
|
21
|
-
<slot v-else name="content"></slot>
|
|
22
|
-
</div>
|
|
23
|
-
</template>
|
|
1
|
+
<script setup>
|
|
2
|
+
import { defineProps, onMounted, ref } from 'vue'
|
|
3
|
+
|
|
4
|
+
import useTextContent from '../composables/useTextContent'
|
|
5
|
+
const { content, initContent } = useTextContent
|
|
6
|
+
|
|
7
|
+
const props = defineProps({
|
|
8
|
+
bookContent: String
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const contentWrapper = ref(null)
|
|
12
|
+
|
|
13
|
+
onMounted(() => {
|
|
14
|
+
initContent(props.bookContent, contentWrapper)
|
|
15
|
+
})
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div ref="contentWrapper">
|
|
20
|
+
<div v-if="content" v-html="content"></div>
|
|
21
|
+
<slot v-else name="content"></slot>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { ref } from 'vue'
|
|
3
|
-
import Slider from '@vueform/slider'
|
|
4
|
-
|
|
5
|
-
import usePagination from '../composables/usePagination';
|
|
6
|
-
const { totalPages, currentPage, set } = usePagination
|
|
7
|
-
|
|
8
|
-
function format() {
|
|
9
|
-
return `${currentPage.value} de ${totalPages.value}`
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<template>
|
|
15
|
-
<div class="py-2 px-10 text-gray-700 dark:text-white">
|
|
16
|
-
<slot name="footer">
|
|
17
|
-
<p> </p>
|
|
18
|
-
</slot>
|
|
19
|
-
|
|
20
|
-
<Slider
|
|
21
|
-
:modelValue="currentPage"
|
|
22
|
-
@update:modelValue="set(Math.round($event))"
|
|
23
|
-
:min="1"
|
|
24
|
-
:max="totalPages"
|
|
25
|
-
:step="-1"
|
|
26
|
-
showTooltip="drag"
|
|
27
|
-
:format="format"
|
|
28
|
-
:lazy="false"
|
|
29
|
-
class="w-full"
|
|
30
|
-
/>
|
|
31
|
-
</div>
|
|
32
|
-
</template>
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import Slider from '@vueform/slider'
|
|
4
|
+
|
|
5
|
+
import usePagination from '../composables/usePagination';
|
|
6
|
+
const { totalPages, currentPage, set } = usePagination
|
|
7
|
+
|
|
8
|
+
function format() {
|
|
9
|
+
return `${currentPage.value} de ${totalPages.value}`
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<div class="py-2 px-10 text-gray-700 dark:text-white">
|
|
16
|
+
<slot name="footer">
|
|
17
|
+
<p> </p>
|
|
18
|
+
</slot>
|
|
19
|
+
|
|
20
|
+
<Slider
|
|
21
|
+
:modelValue="currentPage"
|
|
22
|
+
@update:modelValue="set(Math.round($event))"
|
|
23
|
+
:min="1"
|
|
24
|
+
:max="totalPages"
|
|
25
|
+
:step="-1"
|
|
26
|
+
showTooltip="drag"
|
|
27
|
+
:format="format"
|
|
28
|
+
:lazy="false"
|
|
29
|
+
class="w-full"
|
|
30
|
+
/>
|
|
31
|
+
</div>
|
|
32
|
+
</template>
|
|
@@ -1,123 +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
|
-
p-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>
|
|
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
|
+
p-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>
|
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import SummaryButton from './SummaryButton/SummaryButton.vue';
|
|
3
|
-
import OptionsButton from './OptionsButton/OptionsButton.vue';
|
|
4
|
-
</script>
|
|
5
|
-
|
|
6
|
-
<template>
|
|
7
|
-
<header id="component-header" class="bg-primary flex justify-between items-center p-4">
|
|
8
|
-
<summary-button>
|
|
9
|
-
<template #summaryTop>
|
|
10
|
-
<slot name="summaryTop" />
|
|
11
|
-
</template>
|
|
12
|
-
<template #summaryBottom>
|
|
13
|
-
<slot name="summaryBottom" />
|
|
14
|
-
</template>
|
|
15
|
-
</summary-button>
|
|
16
|
-
|
|
17
|
-
<div id="header-titles">
|
|
18
|
-
<slot name="header" />
|
|
19
|
-
</div>
|
|
20
|
-
|
|
21
|
-
<options-button>
|
|
22
|
-
<template #optionsTop>
|
|
23
|
-
<slot name="optionsTop" />
|
|
24
|
-
</template>
|
|
25
|
-
<template #optionsBottom>
|
|
26
|
-
<slot name="optionsBottom" />
|
|
27
|
-
</template>
|
|
28
|
-
</options-button>
|
|
29
|
-
</header>
|
|
30
|
-
</template>
|
|
1
|
+
<script setup>
|
|
2
|
+
import SummaryButton from './SummaryButton/SummaryButton.vue';
|
|
3
|
+
import OptionsButton from './OptionsButton/OptionsButton.vue';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<header id="component-header" class="bg-primary flex justify-between items-center p-4">
|
|
8
|
+
<summary-button>
|
|
9
|
+
<template #summaryTop>
|
|
10
|
+
<slot name="summaryTop" />
|
|
11
|
+
</template>
|
|
12
|
+
<template #summaryBottom>
|
|
13
|
+
<slot name="summaryBottom" />
|
|
14
|
+
</template>
|
|
15
|
+
</summary-button>
|
|
16
|
+
|
|
17
|
+
<div id="header-titles">
|
|
18
|
+
<slot name="header" />
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<options-button>
|
|
22
|
+
<template #optionsTop>
|
|
23
|
+
<slot name="optionsTop" />
|
|
24
|
+
</template>
|
|
25
|
+
<template #optionsBottom>
|
|
26
|
+
<slot name="optionsBottom" />
|
|
27
|
+
</template>
|
|
28
|
+
</options-button>
|
|
29
|
+
</header>
|
|
30
|
+
</template>
|
|
@@ -1,67 +1,67 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import { ref } from 'vue'
|
|
3
|
-
import { onClickOutside, onKeyStroke, useFullscreen } from '@vueuse/core'
|
|
4
|
-
|
|
5
|
-
import useReaderSettings from '../../../composables/useReaderSettings'
|
|
6
|
-
|
|
7
|
-
import IconThreeDots from '../../icons/ThreeDots.vue'
|
|
8
|
-
import IconClose from '../../icons/Close.vue'
|
|
9
|
-
import IconExpand from '../../icons/Expand.vue'
|
|
10
|
-
import OptionsDropdown from './OptionsDropdown.vue'
|
|
11
|
-
|
|
12
|
-
const show = ref(false)
|
|
13
|
-
const button = ref(null)
|
|
14
|
-
|
|
15
|
-
const toggleSummary = () => show.value = !show.value
|
|
16
|
-
const hide = () => {
|
|
17
|
-
if (!useReaderSettings.blocked.value) {
|
|
18
|
-
show.value = false
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
onClickOutside(button, () => hide())
|
|
23
|
-
onKeyStroke('Escape', () => hide())
|
|
24
|
-
|
|
25
|
-
const { toggle: toggleFullScreen } = useFullscreen()
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
|
-
<template>
|
|
29
|
-
<div id="options-menu" ref="button" class="relative">
|
|
30
|
-
<div class="flex">
|
|
31
|
-
<button @click.prevent="toggleSummary()"
|
|
32
|
-
class="border p-3 shadow flex items-center border-white text-white"
|
|
33
|
-
id="options-button" aria-haspopup="true" :aria-expanded="show"
|
|
34
|
-
>
|
|
35
|
-
<span class="block mr-3">
|
|
36
|
-
Opções
|
|
37
|
-
</span>
|
|
38
|
-
|
|
39
|
-
<IconClose v-if="show" class="w-6 h-6" />
|
|
40
|
-
<IconThreeDots v-else class="w-6 h-6" />
|
|
41
|
-
</button>
|
|
42
|
-
|
|
43
|
-
<button @click.prevent="toggleFullScreen()"
|
|
44
|
-
class="hidden md:flex items-center border p-3 shadow ml-3 border-white text-white"
|
|
45
|
-
>
|
|
46
|
-
<IconExpand class="w-6 h-6" />
|
|
47
|
-
</button>
|
|
48
|
-
</div>
|
|
49
|
-
|
|
50
|
-
<transition enter-active-class="transition ease-out duration-100 transform" enter-class="opacity-0 scale-95"
|
|
51
|
-
enter-to-class="opacity-100 scale-100" leave-active-class="transition ease-in duration-75 transform"
|
|
52
|
-
leave-class="opacity-100 scale-100" leave-to-class="opacity-0 scale-95"
|
|
53
|
-
>
|
|
54
|
-
<OptionsDropdown v-show="show">
|
|
55
|
-
<template #optionsTop>
|
|
56
|
-
<slot name="optionsTop"/>
|
|
57
|
-
</template>
|
|
58
|
-
<template #optionsBottom>
|
|
59
|
-
<slot name="optionsBottom"/>
|
|
60
|
-
</template>
|
|
61
|
-
</OptionsDropdown>
|
|
62
|
-
</transition>
|
|
63
|
-
</div>
|
|
64
|
-
</template>
|
|
65
|
-
|
|
66
|
-
<style>
|
|
67
|
-
</style>
|
|
1
|
+
<script setup>
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import { onClickOutside, onKeyStroke, useFullscreen } from '@vueuse/core'
|
|
4
|
+
|
|
5
|
+
import useReaderSettings from '../../../composables/useReaderSettings'
|
|
6
|
+
|
|
7
|
+
import IconThreeDots from '../../icons/ThreeDots.vue'
|
|
8
|
+
import IconClose from '../../icons/Close.vue'
|
|
9
|
+
import IconExpand from '../../icons/Expand.vue'
|
|
10
|
+
import OptionsDropdown from './OptionsDropdown.vue'
|
|
11
|
+
|
|
12
|
+
const show = ref(false)
|
|
13
|
+
const button = ref(null)
|
|
14
|
+
|
|
15
|
+
const toggleSummary = () => show.value = !show.value
|
|
16
|
+
const hide = () => {
|
|
17
|
+
if (!useReaderSettings.blocked.value) {
|
|
18
|
+
show.value = false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onClickOutside(button, () => hide())
|
|
23
|
+
onKeyStroke('Escape', () => hide())
|
|
24
|
+
|
|
25
|
+
const { toggle: toggleFullScreen } = useFullscreen()
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<div id="options-menu" ref="button" class="relative">
|
|
30
|
+
<div class="flex">
|
|
31
|
+
<button @click.prevent="toggleSummary()"
|
|
32
|
+
class="border p-3 shadow flex items-center border-white text-white"
|
|
33
|
+
id="options-button" aria-haspopup="true" :aria-expanded="show"
|
|
34
|
+
>
|
|
35
|
+
<span class="block mr-3">
|
|
36
|
+
Opções
|
|
37
|
+
</span>
|
|
38
|
+
|
|
39
|
+
<IconClose v-if="show" class="w-6 h-6" />
|
|
40
|
+
<IconThreeDots v-else class="w-6 h-6" />
|
|
41
|
+
</button>
|
|
42
|
+
|
|
43
|
+
<button @click.prevent="toggleFullScreen()"
|
|
44
|
+
class="hidden md:flex items-center border p-3 shadow ml-3 border-white text-white"
|
|
45
|
+
>
|
|
46
|
+
<IconExpand class="w-6 h-6" />
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<transition enter-active-class="transition ease-out duration-100 transform" enter-class="opacity-0 scale-95"
|
|
51
|
+
enter-to-class="opacity-100 scale-100" leave-active-class="transition ease-in duration-75 transform"
|
|
52
|
+
leave-class="opacity-100 scale-100" leave-to-class="opacity-0 scale-95"
|
|
53
|
+
>
|
|
54
|
+
<OptionsDropdown v-show="show">
|
|
55
|
+
<template #optionsTop>
|
|
56
|
+
<slot name="optionsTop"/>
|
|
57
|
+
</template>
|
|
58
|
+
<template #optionsBottom>
|
|
59
|
+
<slot name="optionsBottom"/>
|
|
60
|
+
</template>
|
|
61
|
+
</OptionsDropdown>
|
|
62
|
+
</transition>
|
|
63
|
+
</div>
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<style>
|
|
67
|
+
</style>
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import IconSun from '../../icons/Sun.vue'
|
|
3
|
-
import IconMoon from '../../icons/Moon.vue'
|
|
4
|
-
|
|
5
|
-
import useReaderSettings from '../../../composables/useReaderSettings'
|
|
6
|
-
const { mode, setMode } = useReaderSettings
|
|
7
|
-
|
|
8
|
-
</script>
|
|
9
|
-
|
|
10
|
-
<template>
|
|
11
|
-
<button id="lightmode-button" @click.prevent="setMode('light')"
|
|
12
|
-
title="Leitura diurna"
|
|
13
|
-
class="font-light text-base border w-full h-10 flex justify-center items-center"
|
|
14
|
-
:class="{
|
|
15
|
-
'bg-primary-extralight text-primary border-2 border-primary': mode === 'light'
|
|
16
|
-
}">
|
|
17
|
-
<IconSun class="w-5 h-5" />
|
|
18
|
-
</button>
|
|
19
|
-
|
|
20
|
-
<button id="darkmode-button" @click.prevent="setMode('dark')"
|
|
21
|
-
title="Leitura noturna"
|
|
22
|
-
class="font-light text-base border w-full h-10 flex justify-center items-center"
|
|
23
|
-
:class="{
|
|
24
|
-
'bg-primary-extralight text-primary border-2 border-primary': mode === 'dark'
|
|
25
|
-
}">
|
|
26
|
-
<IconMoon class="w-5 h-5" />
|
|
27
|
-
</button>
|
|
28
|
-
</template>
|
|
1
|
+
<script setup>
|
|
2
|
+
import IconSun from '../../icons/Sun.vue'
|
|
3
|
+
import IconMoon from '../../icons/Moon.vue'
|
|
4
|
+
|
|
5
|
+
import useReaderSettings from '../../../composables/useReaderSettings'
|
|
6
|
+
const { mode, setMode } = useReaderSettings
|
|
7
|
+
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<button id="lightmode-button" @click.prevent="setMode('light')"
|
|
12
|
+
title="Leitura diurna"
|
|
13
|
+
class="font-light text-base border w-full h-10 flex justify-center items-center"
|
|
14
|
+
:class="{
|
|
15
|
+
'bg-primary-extralight text-primary border-2 border-primary': mode === 'light'
|
|
16
|
+
}">
|
|
17
|
+
<IconSun class="w-5 h-5" />
|
|
18
|
+
</button>
|
|
19
|
+
|
|
20
|
+
<button id="darkmode-button" @click.prevent="setMode('dark')"
|
|
21
|
+
title="Leitura noturna"
|
|
22
|
+
class="font-light text-base border w-full h-10 flex justify-center items-center"
|
|
23
|
+
:class="{
|
|
24
|
+
'bg-primary-extralight text-primary border-2 border-primary': mode === 'dark'
|
|
25
|
+
}">
|
|
26
|
+
<IconMoon class="w-5 h-5" />
|
|
27
|
+
</button>
|
|
28
|
+
</template>
|