paginar 0.1.0

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.
Files changed (54) hide show
  1. package/.editorconfig +13 -0
  2. package/.env +1 -0
  3. package/.vscode/extensions.json +3 -0
  4. package/README.md +14 -0
  5. package/demo/slot/slot-chapter1.html +142 -0
  6. package/demo/slot/slot-chapter2.html +359 -0
  7. package/demo/slot/slot-chapter3.html +259 -0
  8. package/demo/summary/_content/1chapter.html +97 -0
  9. package/demo/summary/_content/2chapter.html +311 -0
  10. package/demo/summary/_content/3chapter.html +211 -0
  11. package/demo/summary/index.html +99 -0
  12. package/dist/favicon.ico +0 -0
  13. package/dist/index.es.js +10224 -0
  14. package/dist/index.es.js.map +1 -0
  15. package/dist/style.css +975 -0
  16. package/index.html +18 -0
  17. package/package.json +35 -0
  18. package/postcss.config.js +7 -0
  19. package/public/favicon.ico +0 -0
  20. package/src/App.ce.vue +104 -0
  21. package/src/assets/main.css +100 -0
  22. package/src/components/EngineWrapper.vue +23 -0
  23. package/src/components/FileContent.ce.vue +20 -0
  24. package/src/components/FooterSlot.ce.vue +22 -0
  25. package/src/components/HeaderSlot/HeaderSlot.ce.vue +37 -0
  26. package/src/components/HeaderSlot/OptionsButton/OptionsButton.ce.vue +63 -0
  27. package/src/components/HeaderSlot/OptionsButton/OptionsColor.vue +28 -0
  28. package/src/components/HeaderSlot/OptionsButton/OptionsColumns.vue +41 -0
  29. package/src/components/HeaderSlot/OptionsButton/OptionsDropdown.vue +40 -0
  30. package/src/components/HeaderSlot/OptionsButton/OptionsFontFamily.vue +17 -0
  31. package/src/components/HeaderSlot/OptionsButton/OptionsFontSize.vue +17 -0
  32. package/src/components/HeaderSlot/SummaryButton/SummaryButton.ce.vue +64 -0
  33. package/src/components/HeaderSlot/SummaryButton/SummaryDropdown.vue +29 -0
  34. package/src/components/NavigationButton.ce.vue +34 -0
  35. package/src/components/ReaderWrapper.vue +16 -0
  36. package/src/components/icons/Close.vue +6 -0
  37. package/src/components/icons/DoubleColumn.vue +15 -0
  38. package/src/components/icons/Expand.vue +7 -0
  39. package/src/components/icons/Eye.vue +9 -0
  40. package/src/components/icons/Home.vue +6 -0
  41. package/src/components/icons/Moon.vue +5 -0
  42. package/src/components/icons/SingleColumn.vue +3 -0
  43. package/src/components/icons/Summary.vue +10 -0
  44. package/src/components/icons/Sun.vue +5 -0
  45. package/src/components/icons/ThreeDots.vue +8 -0
  46. package/src/composables/useEstimatePages.js +28 -0
  47. package/src/composables/usePagination.js +57 -0
  48. package/src/composables/useReaderSettings.js +125 -0
  49. package/src/composables/useStyles.js +38 -0
  50. package/src/composables/useTextContent.js +40 -0
  51. package/src/main.js +21 -0
  52. package/src/tailwind.css +975 -0
  53. package/tailwind.config.js +12 -0
  54. package/vite.config.js +32 -0
@@ -0,0 +1,34 @@
1
+ <script>
2
+ export default {
3
+ name: "NavPrev",
4
+
5
+ props: {
6
+ target: String,
7
+ },
8
+
9
+ computed: {
10
+ type() {
11
+ return 'chapter'
12
+ },
13
+ }
14
+ };
15
+ </script>
16
+
17
+ <template>
18
+ <button @click.prevent="$emit('clicked')" class="[ viewer-nav ]"
19
+ :class="type === 'cover' ? 'text-white' : 'text-gray-dark'">
20
+
21
+ <svg v-if="target === 'prev'" viewBox="0 0 20 20" fill="currentColor" class="[ viewer-nav-icon nav-prev ] arrow-narrow-left">
22
+ <path fill-rule="evenodd"
23
+ d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
24
+ clip-rule="evenodd"></path>
25
+ </svg>
26
+
27
+ <svg v-if="target === 'next'" data-v-ef9c31bc="" viewBox="0 0 20 20" fill="currentColor"
28
+ class="[ viewer-nav-icon nav-next ] right-0 arrow-narrow-right">
29
+ <path fill-rule="evenodd"
30
+ d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
31
+ clip-rule="evenodd"></path>
32
+ </svg>
33
+ </button>
34
+ </template>
@@ -0,0 +1,16 @@
1
+ <script setup>
2
+ import usePagination from '../composables/usePagination'
3
+ import useReaderSettings from '../composables/useReaderSettings'
4
+
5
+ const { columns } = useReaderSettings
6
+ const { currentPage } = usePagination
7
+ </script>
8
+
9
+ <template>
10
+ <div :class="columns" :style="`margin-left: -${100 * (currentPage - 1)}%`">
11
+ <div class="[ typeArea ] h-full relative
12
+ transition-opacity duration-100 opacity-100 px-24">
13
+ <slot></slot>
14
+ </div>
15
+ </div>
16
+ </template>
@@ -0,0 +1,6 @@
1
+ <script setup></script>
2
+ <template>
3
+ <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
4
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
5
+ </svg>
6
+ </template>
@@ -0,0 +1,15 @@
1
+ <template>
2
+ <svg viewBox="0 0 653 441.2" fill="currentColor">
3
+ <rect x="73.2" y="143.7" width="195.2" height="20"></rect>
4
+ <rect x="73.2" y="82.7" width="195.2" height="20"></rect>
5
+ <rect x="73.2" y="203.7" width="195.2" height="20"></rect>
6
+ <rect x="73.2" y="263.7" width="195.2" height="20"></rect>
7
+ <rect x="73.2" y="319" width="195.2" height="20"></rect>
8
+ <rect x="384.7" y="143.7" width="195.2" height="20"></rect>
9
+ <rect x="384.7" y="82.7" width="195.2" height="20"></rect>
10
+ <rect x="384.7" y="203.7" width="195.2" height="20"></rect>
11
+ <rect x="384.7" y="263.7" width="195.2" height="20"></rect>
12
+ <rect x="384.7" y="319" width="195.2" height="20"></rect>
13
+ <path d="M0-0.6v7.5v7.5v411.8v14.4v0.6h653v-5v-10V14.4V2.5v-3.1H0z M638,426.2H15V14.4h623V426.2z"></path>
14
+ </svg>
15
+ </template>
@@ -0,0 +1,7 @@
1
+ <script setup></script>
2
+ <template>
3
+ <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
4
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
5
+ d="M4 8V4m0 0h4M4 4l5 5m11-1V4m0 0h-4m4 0l-5 5M4 16v4m0 0h4m-4 0l5-5m11 5l-5-5m5 5v-4m0 4h-4"></path>
6
+ </svg>
7
+ </template>
@@ -0,0 +1,9 @@
1
+ <script setup></script>
2
+ <template>
3
+ <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
4
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
5
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
6
+ d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z">
7
+ </path>
8
+ </svg>
9
+ </template>
@@ -0,0 +1,6 @@
1
+ <template>
2
+ <svg fill="none" stroke="currentColor" viewBox="0 0 20 22" xmlns="http://www.w3.org/2000/svg">
3
+ <path d="M1 8L10 1L19 8V19C19 19.5304 18.7893 20.0391 18.4142 20.4142C18.0391 20.7893 17.5304 21 17 21H3C2.46957 21 1.96086 20.7893 1.58579 20.4142C1.21071 20.0391 1 19.5304 1 19V8Z" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
4
+ <path d="M7 21V11H13V21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
5
+ </svg>
6
+ </template>
@@ -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="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>
4
+ </svg>
5
+ </template>
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <svg viewBox="0 0 341.5 441.2" fill="currentColor"><rect data-v-acadaaca="" x="73.2" y="143.7" width="195.2" height="20"></rect><rect data-v-acadaaca="" x="73.2" y="82.7" width="195.2" height="20"></rect><rect data-v-acadaaca="" x="73.2" y="203.7" width="195.2" height="20"></rect><rect data-v-acadaaca="" x="73.2" y="263.7" width="195.2" height="20"></rect><rect data-v-acadaaca="" x="73.2" y="319" width="195.2" height="20"></rect><rect data-v-acadaaca="" x="0" y="-0.6" width="332.3" height="15"></rect><rect data-v-acadaaca="" x="0" y="426.2" width="332.3" height="15"></rect><rect data-v-acadaaca="" x="-209.4" y="216.2" transform="matrix(6.123234e-17 -1 1 6.123234e-17 -216.2339 231.2339)" width="433.7" height="15"></rect><rect data-v-acadaaca="" x="108" y="211.9" transform="matrix(6.123234e-17 -1 1 6.123234e-17 105.4808 544.1859)" width="433.7" height="15"></rect></svg>
3
+ </template>
@@ -0,0 +1,10 @@
1
+ <template>
2
+ <svg width="24" height="19" viewBox="0 0 24 19" fill="none" stroke="currentColor" xmlns="http://www.w3.org/2000/svg">
3
+ <line x1="5" y1="1.08447" x2="1" y2="1.08447" stroke-width="2" stroke-linecap="round"/>
4
+ <line x1="23" y1="1.04248" x2="11" y2="1.04248" stroke-width="2" stroke-linecap="round"/>
5
+ <line x1="23" y1="9.08447" x2="14" y2="9.08447" stroke-width="2" stroke-linecap="round"/>
6
+ <line x1="8" y1="9.14905" x2="4" y2="9.14905" stroke-width="2" stroke-linecap="round"/>
7
+ <line x1="23" y1="17.149" x2="10.9993" y2="17.149" stroke-width="2" stroke-linecap="round"/>
8
+ <line x1="5" y1="17.2429" x2="1" y2="17.2429" stroke-width="2" stroke-linecap="round"/>
9
+ </svg>
10
+ </template>
@@ -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="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path>
4
+ </svg>
5
+ </template>
@@ -0,0 +1,8 @@
1
+ <script setup></script>
2
+ <template>
3
+ <svg fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
4
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
5
+ d="M5 12h.01M12 12h.01M19 12h.01M6 12a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0zm7 0a1 1 0 11-2 0 1 1 0 012 0z">
6
+ </path>
7
+ </svg>
8
+ </template>
@@ -0,0 +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
+ }
@@ -0,0 +1,57 @@
1
+ import { reactive, computed, watch } from 'vue'
2
+ import { onKeyStroke } from '@vueuse/core'
3
+ import useEstimatePages from './useEstimatePages'
4
+
5
+ const state = reactive({
6
+ currentPage: 1
7
+ })
8
+
9
+ const currentPage = computed(() => state.currentPage)
10
+ const totalPages = computed(() => useEstimatePages.totalPages.value)
11
+
12
+ function init(viewport, content) {
13
+ useEstimatePages.estimate(viewport, content)
14
+ }
15
+
16
+ // when resizing the viewport, totalPages change
17
+ // this watch is to currentPage inside totalPages range
18
+ watch(totalPages, () => {
19
+ if (totalPages.value < currentPage.value) {
20
+ set(totalPages.value)
21
+ }
22
+ })
23
+
24
+ // navigate by increase/decrease value
25
+ function next() {
26
+ if ((state.currentPage + 1) <= totalPages.value) {
27
+ state.currentPage = state.currentPage + 1
28
+ }
29
+ }
30
+ onKeyStroke('ArrowRight', (e) => {
31
+ e.preventDefault()
32
+ next()
33
+ })
34
+
35
+ function prev() {
36
+ if ((state.currentPage - 1) > 0) {
37
+ state.currentPage = state.currentPage - 1
38
+ }
39
+ }
40
+ onKeyStroke('ArrowLeft', (e) => {
41
+ e.preventDefault()
42
+ prev()
43
+ })
44
+
45
+ // navigate to specific page
46
+ function set(val) {
47
+ state.currentPage = val
48
+ }
49
+
50
+ export default {
51
+ currentPage,
52
+ totalPages,
53
+ next,
54
+ prev,
55
+ init,
56
+ set
57
+ }
@@ -0,0 +1,125 @@
1
+ import { reactive, computed, watch } from 'vue'
2
+ import useStyles from './useStyles'
3
+
4
+ const state = reactive({
5
+ baseFont: 'Arial, sans-serif',
6
+ textFont: 'Times New Roman, serif',
7
+ fontsOptions: [
8
+ { name: 'Times New Roman, serif' },
9
+ { name: 'Georgia, serif' },
10
+ { name: 'Arial, sans-serif' },
11
+ { name: 'Verdana, sans-serif' },
12
+ ],
13
+ fontSize: 16,
14
+ columns: 'singleColumns',
15
+ mode: 'light'
16
+ })
17
+
18
+ const baseFont = computed(() => state.baseFont)
19
+ const textFont = computed(() => state.textFont)
20
+ const fontSize = computed(() => state.fontSize)
21
+ const fontsOptions = computed(() => state.fontsOptions)
22
+ const columns = computed(() => state.columns)
23
+ const mode = computed(() => state.mode)
24
+
25
+ watch(
26
+ [baseFont, textFont, fontSize, columns, mode],
27
+ () => saveSettings()
28
+ )
29
+
30
+ async function initSettings(settingsString) {
31
+ const settings = settingsString
32
+ ? JSON.parse(settingsString)
33
+ : null
34
+
35
+ if (settings?.baseFont)
36
+ state.baseFont = settings.baseFont
37
+
38
+ if (settings?.textFont)
39
+ state.textFont = settings.textFont
40
+
41
+ if (settings?.fontSize)
42
+ state.fontSize = Number(settings.fontSize)
43
+
44
+ if (settings?.fontsOptions) {
45
+ state.fontsOptions = settings.fontsOptions
46
+ useStyles.fontLoader(settings.fontsOptions)
47
+
48
+ // baseFont
49
+ const defaultBaseFont = settings.fontsOptions.find(
50
+ item => item.defaultBaseFont
51
+ )
52
+ if (defaultBaseFont)
53
+ state.baseFont = defaultBaseFont.name
54
+
55
+ // textFont
56
+ const defaultTextFont = settings.fontsOptions.find(
57
+ item => item.defaultTextFont
58
+ )
59
+ if (defaultTextFont)
60
+ state.textFont = defaultTextFont.name
61
+ }
62
+
63
+ loadSavedSettings(settings)
64
+ }
65
+
66
+ function loadSavedSettings(settings) {
67
+ const hasSettings = localStorage.getItem('readerSettings')
68
+
69
+ if (hasSettings) {
70
+ const savedSettings = JSON.parse(hasSettings)
71
+
72
+ state.fontSize = savedSettings.fontSize
73
+ state.columns = savedSettings.columns
74
+ state.mode = savedSettings.mode
75
+
76
+ if (settings?.fontsOptions &&
77
+ settings?.fontsOptions?.find(item => item.name === savedSettings.textFont)
78
+ ) {
79
+ state.textFont = savedSettings.textFont
80
+ }
81
+ }
82
+ }
83
+
84
+ function setColumns(value) {
85
+ state.columns = value
86
+ }
87
+
88
+ function setTextFont(value) {
89
+ state.textFont = value
90
+ }
91
+
92
+ function setFontSize(value) {
93
+ state.fontSize = value
94
+ }
95
+
96
+ function setMode(value) {
97
+ state.mode = value
98
+ }
99
+
100
+ function saveSettings() {
101
+ localStorage.setItem(
102
+ 'readerSettings',
103
+ JSON.stringify({
104
+ textFont: textFont.value,
105
+ fontSize: fontSize.value,
106
+ columns: columns.value,
107
+ mode: mode.value
108
+ })
109
+ )
110
+ }
111
+
112
+ export default {
113
+ baseFont,
114
+ textFont,
115
+ fontSize,
116
+ fontsOptions,
117
+ columns,
118
+ initSettings,
119
+ setColumns,
120
+ setTextFont,
121
+ setFontSize,
122
+ mode,
123
+ setMode,
124
+ saveSettings
125
+ }
@@ -0,0 +1,38 @@
1
+ function fontLoader(fontsOptions) {
2
+ const fontsToLoad = fontsOptions.filter(item => item.link)
3
+
4
+ if (fontsToLoad.length > 0) {
5
+ const style = document.createElement('style')
6
+ const head = document.head || document.getElementsByTagName('head')[0]
7
+ head.appendChild(style)
8
+
9
+ style.type = 'text/css'
10
+ let css = ''
11
+ fontsToLoad.forEach(
12
+ item => css = css + `@import url(${item.link}); \n`
13
+ )
14
+ style.appendChild(document.createTextNode(css))
15
+ }
16
+ }
17
+
18
+ async function stylesheetLoader(stylesheet, ref) {
19
+ if (stylesheet) {
20
+ try {
21
+ const dataRef = await fetch(stylesheet)
22
+ const cssText = await dataRef.text()
23
+
24
+ const style = document.createElement('style')
25
+ ref.value.appendChild(style)
26
+ style.type = 'text/css'
27
+ style.appendChild(document.createTextNode(cssText))
28
+
29
+ } catch (err) {
30
+ console.log({ err })
31
+ }
32
+ }
33
+ }
34
+
35
+ export default {
36
+ fontLoader,
37
+ stylesheetLoader
38
+ }
@@ -0,0 +1,40 @@
1
+ import { computed, reactive } from 'vue'
2
+
3
+ const state = reactive({
4
+ summary: null,
5
+ content: null
6
+ })
7
+
8
+ const content = computed(() => state.content)
9
+ const summary = computed(() => state.summary)
10
+
11
+ async function initContent(contentString) {
12
+ const content = contentString
13
+ ? JSON.parse(contentString)
14
+ : null
15
+
16
+ if (content?.summary)
17
+ state.summary = content.summary
18
+
19
+ if (content?.summary?.[0]?.file) {
20
+ getContent(content.summary?.[0]?.file)
21
+ }
22
+ }
23
+
24
+ async function getContent(location) {
25
+ try {
26
+ const dataRef = await fetch(location)
27
+ const text = await dataRef.text()
28
+ state.content = text
29
+ } catch (err) {
30
+ console.log({ err })
31
+ state.content = 'Ops, não foi possível carregar o arquivo solicitado.'
32
+ }
33
+ }
34
+
35
+ export default {
36
+ content,
37
+ summary,
38
+ initContent,
39
+ getContent
40
+ }
package/src/main.js ADDED
@@ -0,0 +1,21 @@
1
+ // https://maximomussini.com/posts/vue-custom-elements
2
+ import { defineCustomElement } from 'vue'
3
+
4
+ import App from './App.ce.vue'
5
+ import HeaderSlot from './components/HeaderSlot/HeaderSlot.ce.vue'
6
+
7
+ import tailwindStyles from './tailwind.css'
8
+
9
+ const styles = [
10
+ ...[tailwindStyles],
11
+ ...App.styles,
12
+ ...HeaderSlot.styles
13
+ ]
14
+
15
+ customElements.define(
16
+ 'paginate-content',
17
+ defineCustomElement({
18
+ ...App,
19
+ styles
20
+ })
21
+ )