uview-plus 3.8.55 → 3.8.106

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 (229) hide show
  1. package/changelog.md +2147 -1828
  2. package/components/u-action-sheet/props.js +3 -1
  3. package/components/u-action-sheet/u-action-sheet.vue +22 -2
  4. package/components/u-album/props.js +3 -1
  5. package/components/u-alert/props.js +4 -2
  6. package/components/u-avatar/props.js +4 -1
  7. package/components/u-avatar-group/props.js +4 -1
  8. package/components/u-back-top/props.js +4 -1
  9. package/components/u-badge/props.js +4 -1
  10. package/components/u-barcode/u-barcode.vue +44 -15
  11. package/components/u-box/props.js +5 -2
  12. package/components/u-button/props.js +4 -1
  13. package/components/u-button/u-button.vue +2 -5
  14. package/components/u-button/vue.scss +3 -3
  15. package/components/u-calendar/calendar.js +8 -0
  16. package/components/u-calendar/props.js +43 -1
  17. package/components/u-calendar/u-calendar.vue +16 -0
  18. package/components/u-calendar-strip/props.js +3 -1
  19. package/components/u-canvas/u-canvas.vue +1028 -423
  20. package/components/u-car-keyboard/props.js +3 -1
  21. package/components/u-card/props.js +3 -1
  22. package/components/u-cell/props.js +4 -1
  23. package/components/u-cell/u-cell.vue +9 -1
  24. package/components/u-cell-group/props.js +4 -1
  25. package/components/u-checkbox/props.js +4 -1
  26. package/components/u-checkbox/u-checkbox.vue +7 -3
  27. package/components/u-checkbox-group/props.js +3 -1
  28. package/components/u-circle-progress/props.js +4 -1
  29. package/components/u-code/props.js +4 -1
  30. package/components/u-code-input/props.js +4 -1
  31. package/components/u-col/props.js +4 -1
  32. package/components/u-collapse/props.js +4 -1
  33. package/components/u-collapse-item/props.js +4 -1
  34. package/components/u-color-picker/u-color-picker.vue +1 -0
  35. package/components/u-column-notice/props.js +4 -1
  36. package/components/u-count-down/props.js +4 -1
  37. package/components/u-count-to/props.js +4 -1
  38. package/components/u-cropper/u-cropper.vue +95 -51
  39. package/components/u-datetime-picker/props.js +4 -1
  40. package/components/u-datetime-picker/u-datetime-picker.vue +53 -4
  41. package/components/u-divider/props.js +4 -1
  42. package/components/u-dragsort/u-dragsort.vue +57 -32
  43. package/components/u-dropdown/props.js +3 -1
  44. package/components/u-dropdown-item/props.js +3 -1
  45. package/components/u-empty/props.js +4 -1
  46. package/components/u-form/props.js +4 -1
  47. package/components/u-form-item/props.js +4 -1
  48. package/components/u-gap/props.js +4 -1
  49. package/components/u-grid/props.js +4 -1
  50. package/components/u-grid-item/props.js +4 -1
  51. package/components/u-guide/props.js +3 -1
  52. package/components/u-icon/props.js +4 -1
  53. package/components/u-icon/u-icon.vue +11 -2
  54. package/components/u-icon/upicon.ttf +0 -0
  55. package/components/u-icon/util.js +103 -10
  56. package/components/u-image/props.js +4 -1
  57. package/components/u-image/u-image.vue +280 -267
  58. package/components/u-index-anchor/props.js +4 -1
  59. package/components/u-index-item/props.js +2 -1
  60. package/components/u-index-item/u-index-item.vue +1 -1
  61. package/components/u-index-list/props.js +4 -1
  62. package/components/u-index-list/u-index-list.vue +1 -1
  63. package/components/u-input/props.js +3 -1
  64. package/components/u-keyboard/props.js +4 -1
  65. package/components/u-line/props.js +4 -1
  66. package/components/u-line-progress/props.js +6 -3
  67. package/components/u-link/props.js +4 -1
  68. package/components/u-list/props.js +4 -1
  69. package/components/u-list-item/props.js +4 -1
  70. package/components/u-loading-icon/props.js +4 -1
  71. package/components/u-loading-page/props.js +3 -1
  72. package/components/u-loadmore/props.js +4 -1
  73. package/components/u-markdown/u-markdown.vue +45 -3
  74. package/components/u-modal/props.js +4 -1
  75. package/components/u-navbar/props.js +4 -2
  76. package/components/u-navbar/u-navbar.vue +15 -9
  77. package/components/u-no-network/props.js +4 -1
  78. package/components/u-notice-bar/props.js +4 -1
  79. package/components/u-notify/props.js +4 -1
  80. package/components/u-novel-reader/content-normalizer.js +80 -0
  81. package/components/u-novel-reader/layout-engine.js +225 -0
  82. package/components/u-novel-reader/measure-adapter.js +69 -0
  83. package/components/u-novel-reader/novelReader.js +35 -0
  84. package/components/u-novel-reader/persistence.js +144 -0
  85. package/components/u-novel-reader/props.js +100 -0
  86. package/components/u-novel-reader/reader-catalog.vue +234 -0
  87. package/components/u-novel-reader/reader-content.vue +226 -0
  88. package/components/u-novel-reader/reader-core.js +151 -0
  89. package/components/u-novel-reader/reader-settings.vue +325 -0
  90. package/components/u-novel-reader/reader-toolbar.vue +313 -0
  91. package/components/u-novel-reader/theme-vars.scss +49 -0
  92. package/components/u-novel-reader/u-novel-reader.vue +836 -0
  93. package/components/u-number-box/props.js +4 -1
  94. package/components/u-number-box/u-number-box.vue +2 -2
  95. package/components/u-number-keyboard/props.js +4 -1
  96. package/components/u-overlay/props.js +4 -1
  97. package/components/u-pagination/u-pagination.vue +60 -39
  98. package/components/u-parse/props.js +4 -1
  99. package/components/u-picker/props.js +4 -1
  100. package/components/u-picker-column/props.js +3 -1
  101. package/components/u-popover/props.js +2 -1
  102. package/components/u-popup/props.js +4 -1
  103. package/components/u-poster/u-poster.vue +246 -214
  104. package/components/u-qrcode/qrcode.js +105 -97
  105. package/components/u-qrcode/u-qrcode.vue +242 -289
  106. package/components/u-radio/props.js +4 -1
  107. package/components/u-radio/u-radio.vue +7 -3
  108. package/components/u-radio-group/props.js +4 -1
  109. package/components/u-rate/props.js +4 -1
  110. package/components/u-read-more/props.js +4 -1
  111. package/components/u-row/props.js +4 -1
  112. package/components/u-row-notice/props.js +4 -1
  113. package/components/u-safe-bottom/props.js +2 -1
  114. package/components/u-scroll-list/props.js +4 -1
  115. package/components/u-scroll-list/scrollWxs.wxs +1 -1
  116. package/components/u-search/props.js +3 -1
  117. package/components/u-skeleton/props.js +4 -1
  118. package/components/u-slider/props.js +3 -1
  119. package/components/u-slider/u-slider.vue +71 -29
  120. package/components/u-status-bar/props.js +4 -1
  121. package/components/u-steps/props.js +4 -1
  122. package/components/u-steps-item/props.js +4 -1
  123. package/components/u-sticky/props.js +4 -1
  124. package/components/u-sticky/u-sticky.vue +11 -0
  125. package/components/u-subsection/props.js +3 -1
  126. package/components/u-swipe-action/props.js +4 -1
  127. package/components/u-swipe-action-item/index.wxs +43 -25
  128. package/components/u-swipe-action-item/nvue.js +9 -0
  129. package/components/u-swipe-action-item/other.js +32 -21
  130. package/components/u-swipe-action-item/props.js +9 -1
  131. package/components/u-swipe-action-item/swipeActionItem.js +1 -0
  132. package/components/u-swipe-action-item/u-swipe-action-item.vue +42 -4
  133. package/components/u-swiper/props.js +9 -1
  134. package/components/u-swiper/swiper.js +1 -0
  135. package/components/u-swiper/u-swiper.vue +2 -0
  136. package/components/u-swiper-indicator/props.js +4 -1
  137. package/components/u-switch/props.js +4 -1
  138. package/components/u-switch/u-switch.vue +1 -1
  139. package/components/u-tabbar/props.js +3 -1
  140. package/components/u-tabbar/u-tabbar.vue +2 -1
  141. package/components/u-tabbar-item/props.js +4 -1
  142. package/components/u-tabbar-item/u-tabbar-item.vue +64 -21
  143. package/components/u-table/props.js +3 -1
  144. package/components/u-table2/tableRow.vue +155 -69
  145. package/components/u-table2/u-table2.vue +327 -137
  146. package/components/u-tabs/props.js +4 -1
  147. package/components/u-tabs/u-tabs.vue +11 -8
  148. package/components/u-tabs-item/props.js +3 -1
  149. package/components/u-tabs-pro/u-tabs-pro.vue +212 -0
  150. package/components/u-tag/props.js +4 -1
  151. package/components/u-td/props.js +3 -1
  152. package/components/u-text/props.js +4 -1
  153. package/components/u-text/text.js +1 -1
  154. package/components/u-text/u-text.vue +18 -6
  155. package/components/u-textarea/props.js +3 -1
  156. package/components/u-textarea/u-textarea.vue +16 -5
  157. package/components/u-th/props.js +3 -1
  158. package/components/u-toolbar/props.js +4 -1
  159. package/components/u-tooltip/props.js +10 -2
  160. package/components/u-tooltip/tooltip.js +2 -1
  161. package/components/u-tooltip/u-tooltip.vue +31 -3
  162. package/components/u-tr/props.js +3 -1
  163. package/components/u-transition/nvue-ani-map.js +75 -68
  164. package/components/u-transition/props.js +4 -1
  165. package/components/u-transition/transitionMixin.js +164 -163
  166. package/components/u-upload/props.js +4 -1
  167. package/components/u-upload/u-upload.vue +48 -41
  168. package/components/u-waterfall/u-waterfall.vue +162 -110
  169. package/index.js +65 -8
  170. package/libs/config/config.js +1 -1
  171. package/libs/config/props.js +180 -204
  172. package/libs/css/components.scss +3 -0
  173. package/libs/function/index.js +66 -0
  174. package/libs/function/uni-api-shims.js +29 -0
  175. package/libs/i18n/index.js +71 -36
  176. package/libs/i18n/locale-packs.js +11 -0
  177. package/libs/i18n/locales/all.js +23 -0
  178. package/libs/i18n/locales/{de.json → de.js} +1 -1
  179. package/libs/i18n/locales/{en.json → en.js} +2 -2
  180. package/libs/i18n/locales/{es.json → es.js} +1 -1
  181. package/libs/i18n/locales/{fr.json → fr.js} +2 -2
  182. package/libs/i18n/locales/{ja.json → ja.js} +1 -1
  183. package/libs/i18n/locales/{ko.json → ko.js} +1 -1
  184. package/libs/i18n/locales/{ru.json → ru.js} +1 -1
  185. package/libs/i18n/locales/{th.json → th.js} +1 -1
  186. package/libs/i18n/locales/{zh-Hans.json → zh-Hans.js} +1 -1
  187. package/libs/i18n/locales/{zh-Hant.json → zh-Hant.js} +1 -1
  188. package/libs/mixin/mixin.js +18 -54
  189. package/libs/root/index.js +78 -5
  190. package/libs/root/page.js +7 -7
  191. package/libs/root/root.js +73 -3
  192. package/libs/util/app-nvue-webview-canvas.js +486 -0
  193. package/libs/util/gcanvas/bridge/bridge-weex.js +10 -7
  194. package/libs/util/gcanvas/context-2d/FillStyleLinearGradient.js +0 -0
  195. package/libs/util/gcanvas/context-2d/FillStylePattern.js +0 -0
  196. package/libs/util/gcanvas/context-2d/FillStyleRadialGradient.js +0 -0
  197. package/libs/util/gcanvas/context-2d/RenderingContext.js +0 -0
  198. package/libs/util/gcanvas/context-webgl/ActiveInfo.js +0 -0
  199. package/libs/util/gcanvas/context-webgl/Buffer.js +0 -0
  200. package/libs/util/gcanvas/context-webgl/Framebuffer.js +0 -0
  201. package/libs/util/gcanvas/context-webgl/GLenum.js +0 -0
  202. package/libs/util/gcanvas/context-webgl/GLmethod.js +0 -0
  203. package/libs/util/gcanvas/context-webgl/GLtype.js +0 -0
  204. package/libs/util/gcanvas/context-webgl/Program.js +0 -0
  205. package/libs/util/gcanvas/context-webgl/Renderbuffer.js +0 -0
  206. package/libs/util/gcanvas/context-webgl/RenderingContext.js +0 -0
  207. package/libs/util/gcanvas/context-webgl/Shader.js +0 -0
  208. package/libs/util/gcanvas/context-webgl/ShaderPrecisionFormat.js +0 -0
  209. package/libs/util/gcanvas/context-webgl/Texture.js +0 -0
  210. package/libs/util/gcanvas/context-webgl/UniformLocation.js +0 -0
  211. package/libs/util/gcanvas/context-webgl/classUtils.js +0 -0
  212. package/libs/util/gcanvas/env/canvas.js +0 -0
  213. package/libs/util/gcanvas/env/image.js +0 -0
  214. package/libs/util/gcanvas/env/tool.js +0 -0
  215. package/libs/util/gcanvas/index.js +3 -3
  216. package/package.json +4 -5
  217. package/tsconfig.json +18 -0
  218. package/types/comps/calendar.d.ts +38 -0
  219. package/types/comps/checkbox.d.ts +12 -0
  220. package/types/comps/lineProgress.d.ts +5 -0
  221. package/types/comps/navbar.d.ts +3 -3
  222. package/types/comps/swipeActionItem.d.ts +13 -0
  223. package/types/comps/swiper.d.ts +5 -0
  224. package/types/comps/tabs.d.ts +2 -1
  225. package/types/comps/text.d.ts +1 -1
  226. package/types/comps/tooltip.d.ts +36 -1
  227. package/types/func.d.ts +23 -0
  228. package/types/index.d.ts +1 -0
  229. /package/components/u-markdown/{marked.esm.js → marked.esm.mjs} +0 -0
@@ -0,0 +1,35 @@
1
+ export default {
2
+ novelReader: {
3
+ chapters: [],
4
+ currentChapter: null,
5
+ loading: false,
6
+ error: null,
7
+ bookId: '',
8
+ storageKey: '',
9
+ persist: true,
10
+ initialProgress: null,
11
+ progress: null,
12
+ initialBookmarks: [],
13
+ bookmarks: null,
14
+ defaultSettings: {
15
+ theme: 'day',
16
+ fontSize: 18,
17
+ lineHeight: 1.8,
18
+ paragraphSpacing: 16,
19
+ contentWidth: '92%',
20
+ fontFamily: 'system',
21
+ fontWeight: 400,
22
+ animation: true
23
+ },
24
+ settings: null,
25
+ mode: 'scroll',
26
+ showBack: true,
27
+ autoBack: false,
28
+ backIcon: 'arrow-left',
29
+ safeAreaInsetTop: true,
30
+ safeAreaInsetBottom: true,
31
+ preloadThreshold: 2,
32
+ pageAnimation: true,
33
+ controlsAutoHide: 0
34
+ }
35
+ }
@@ -0,0 +1,144 @@
1
+ export const STORAGE_VERSION = 1
2
+ export const DEFAULT_STORAGE_PREFIX = 'uview-plus:novel-reader:'
3
+
4
+ function isObject(value) {
5
+ return value !== null && typeof value === 'object' && !Array.isArray(value)
6
+ }
7
+
8
+ function getStorageValue(key) {
9
+ if (!key || typeof uni === 'undefined' || typeof uni.getStorageSync !== 'function') {
10
+ return null
11
+ }
12
+ return uni.getStorageSync(key)
13
+ }
14
+
15
+ function normalizeProgress(value) {
16
+ if (value == null) return null
17
+ if (!isObject(value)) return null
18
+ const numericFields = ['chapterIndex', 'pageIndex', 'pageCount', 'charOffset', 'scrollTop']
19
+ for (const field of numericFields) {
20
+ if (value[field] !== undefined && (
21
+ !Number.isFinite(Number(value[field])) ||
22
+ Number(value[field]) < 0
23
+ )) {
24
+ return null
25
+ }
26
+ }
27
+ for (const field of ['chapterProgress', 'totalProgress']) {
28
+ if (value[field] !== undefined && (
29
+ !Number.isFinite(Number(value[field])) ||
30
+ Number(value[field]) < 0 ||
31
+ Number(value[field]) > 1
32
+ )) {
33
+ return null
34
+ }
35
+ }
36
+ return {
37
+ ...value,
38
+ pageIndex: Math.max(0, Number(value.pageIndex) || 0),
39
+ pageCount: Math.max(0, Number(value.pageCount) || 0),
40
+ charOffset: Math.max(0, Number(value.charOffset) || 0),
41
+ scrollTop: Math.max(0, Number(value.scrollTop) || 0)
42
+ }
43
+ }
44
+
45
+ function normalizeSettings(value) {
46
+ if (!isObject(value)) return {}
47
+ return { ...value }
48
+ }
49
+
50
+ function normalizeBookmarks(value) {
51
+ if (!Array.isArray(value)) return []
52
+ return value.filter((bookmark) => (
53
+ isObject(bookmark) &&
54
+ bookmark.id != null &&
55
+ bookmark.chapterId != null &&
56
+ Number.isFinite(Number(bookmark.charOffset)) &&
57
+ Number(bookmark.charOffset) >= 0
58
+ ))
59
+ }
60
+
61
+ export function createStorageKey({ storageKey = '', bookId = '' } = {}) {
62
+ if (storageKey) return String(storageKey)
63
+ if (bookId === '' || bookId == null) return ''
64
+ return `${DEFAULT_STORAGE_PREFIX}${bookId}`
65
+ }
66
+
67
+ export function normalizePersistedState(value) {
68
+ if (!isObject(value) || value.version !== STORAGE_VERSION) return null
69
+ const progress = normalizeProgress(value.progress)
70
+ const readingTime = Number(value.readingTime)
71
+ const updatedAt = Number(value.updatedAt)
72
+ if (
73
+ !Number.isFinite(readingTime) ||
74
+ readingTime < 0 ||
75
+ !Number.isFinite(updatedAt) ||
76
+ updatedAt < 0
77
+ ) {
78
+ return null
79
+ }
80
+ return {
81
+ version: STORAGE_VERSION,
82
+ progress,
83
+ settings: normalizeSettings(value.settings),
84
+ bookmarks: normalizeBookmarks(value.bookmarks),
85
+ readingTime,
86
+ updatedAt
87
+ }
88
+ }
89
+
90
+ export function readPersistedState(key) {
91
+ if (!key) return null
92
+ try {
93
+ const value = getStorageValue(key)
94
+ const parsed = typeof value === 'string' ? JSON.parse(value) : value
95
+ const normalized = normalizePersistedState(parsed)
96
+ if (
97
+ parsed != null &&
98
+ normalized == null &&
99
+ typeof uni !== 'undefined' &&
100
+ typeof uni.removeStorageSync === 'function'
101
+ ) {
102
+ uni.removeStorageSync(key)
103
+ }
104
+ return normalized
105
+ } catch (error) {
106
+ try {
107
+ if (typeof uni !== 'undefined' && typeof uni.removeStorageSync === 'function') {
108
+ uni.removeStorageSync(key)
109
+ }
110
+ } catch (removeError) {
111
+ return null
112
+ }
113
+ return null
114
+ }
115
+ }
116
+
117
+ export function writePersistedState(key, state) {
118
+ if (!key || typeof uni === 'undefined' || typeof uni.setStorageSync !== 'function') {
119
+ return false
120
+ }
121
+ const payload = {
122
+ version: STORAGE_VERSION,
123
+ progress: isObject(state && state.progress) ? state.progress : null,
124
+ settings: isObject(state && state.settings) ? state.settings : {},
125
+ bookmarks: Array.isArray(state && state.bookmarks) ? state.bookmarks : [],
126
+ readingTime: Math.max(0, Number(state && state.readingTime) || 0),
127
+ updatedAt: Date.now()
128
+ }
129
+ try {
130
+ uni.setStorageSync(key, payload)
131
+ return true
132
+ } catch (error) {
133
+ return false
134
+ }
135
+ }
136
+
137
+ export default {
138
+ STORAGE_VERSION,
139
+ DEFAULT_STORAGE_PREFIX,
140
+ createStorageKey,
141
+ normalizePersistedState,
142
+ readPersistedState,
143
+ writePersistedState
144
+ }
@@ -0,0 +1,100 @@
1
+ import { defineMixin } from '../../libs/vue'
2
+ import { registerComponentProps } from '../../libs/config/props.js'
3
+ import NovelReaderDefaultProps from './novelReader'
4
+
5
+ const defProps = registerComponentProps(NovelReaderDefaultProps)
6
+
7
+ export const props = defineMixin({
8
+ props: {
9
+ chapters: {
10
+ type: Array,
11
+ default: () => defProps.novelReader.chapters
12
+ },
13
+ currentChapter: {
14
+ type: Object,
15
+ default: () => defProps.novelReader.currentChapter
16
+ },
17
+ loading: {
18
+ type: Boolean,
19
+ default: () => defProps.novelReader.loading
20
+ },
21
+ error: {
22
+ type: Object,
23
+ default: () => defProps.novelReader.error
24
+ },
25
+ bookId: {
26
+ type: [String, Number],
27
+ default: () => defProps.novelReader.bookId
28
+ },
29
+ storageKey: {
30
+ type: String,
31
+ default: () => defProps.novelReader.storageKey
32
+ },
33
+ persist: {
34
+ type: Boolean,
35
+ default: () => defProps.novelReader.persist
36
+ },
37
+ initialProgress: {
38
+ type: Object,
39
+ default: () => defProps.novelReader.initialProgress
40
+ },
41
+ progress: {
42
+ type: Object,
43
+ default: () => defProps.novelReader.progress
44
+ },
45
+ initialBookmarks: {
46
+ type: Array,
47
+ default: () => defProps.novelReader.initialBookmarks
48
+ },
49
+ bookmarks: {
50
+ type: Array,
51
+ default: () => defProps.novelReader.bookmarks
52
+ },
53
+ defaultSettings: {
54
+ type: Object,
55
+ default: () => ({ ...defProps.novelReader.defaultSettings })
56
+ },
57
+ settings: {
58
+ type: Object,
59
+ default: () => defProps.novelReader.settings
60
+ },
61
+ mode: {
62
+ type: String,
63
+ default: () => defProps.novelReader.mode
64
+ },
65
+ showBack: {
66
+ type: Boolean,
67
+ default: () => defProps.novelReader.showBack
68
+ },
69
+ autoBack: {
70
+ type: Boolean,
71
+ default: () => defProps.novelReader.autoBack
72
+ },
73
+ backIcon: {
74
+ type: String,
75
+ default: () => defProps.novelReader.backIcon
76
+ },
77
+ safeAreaInsetTop: {
78
+ type: Boolean,
79
+ default: () => defProps.novelReader.safeAreaInsetTop
80
+ },
81
+ safeAreaInsetBottom: {
82
+ type: Boolean,
83
+ default: () => defProps.novelReader.safeAreaInsetBottom
84
+ },
85
+ preloadThreshold: {
86
+ type: Number,
87
+ default: () => defProps.novelReader.preloadThreshold
88
+ },
89
+ pageAnimation: {
90
+ type: Boolean,
91
+ default: () => defProps.novelReader.pageAnimation
92
+ },
93
+ controlsAutoHide: {
94
+ type: Number,
95
+ default: () => defProps.novelReader.controlsAutoHide
96
+ }
97
+ }
98
+ })
99
+
100
+ export default props
@@ -0,0 +1,234 @@
1
+ <template>
2
+ <view class="up-novel-reader__catalog" :style="catalogStyle">
3
+ <view class="up-novel-reader__catalog-header">
4
+ <text class="up-novel-reader__catalog-title">目录</text>
5
+ <text class="up-novel-reader__catalog-count">{{ chapters.length }} 章</text>
6
+ </view>
7
+ <slot v-if="$slots.default"></slot>
8
+ <scroll-view v-else class="up-novel-reader__catalog-scroll" scroll-y>
9
+ <view
10
+ v-for="chapter in chapters"
11
+ :key="chapter.id || chapter.index"
12
+ class="up-novel-reader__catalog-item"
13
+ :class="{
14
+ 'is-current': isCurrent(chapter),
15
+ 'is-locked': chapter.isLocked
16
+ }"
17
+ :aria-disabled="chapter.isLocked ? 'true' : 'false'"
18
+ @tap="selectChapter(chapter)"
19
+ >
20
+ <view class="up-novel-reader__catalog-index">
21
+ <u-icon
22
+ v-if="chapter.isLocked"
23
+ name="lock"
24
+ size="14"
25
+ :color="mutedColor"
26
+ ></u-icon>
27
+ <text v-else>{{ displayIndex(chapter) }}</text>
28
+ </view>
29
+ <text class="up-novel-reader__catalog-item-title">{{ chapter.title || `第${displayIndex(chapter)}章` }}</text>
30
+ <u-icon
31
+ v-if="isCurrent(chapter)"
32
+ name="checkmark"
33
+ size="16"
34
+ :color="activeColor"
35
+ ></u-icon>
36
+ </view>
37
+ <view v-if="!chapters.length" class="up-novel-reader__catalog-empty">暂无目录</view>
38
+ <view v-if="bookmarks.length" class="up-novel-reader__bookmark-section">
39
+ <view class="up-novel-reader__bookmark-heading">
40
+ <u-icon name="bookmark" size="15" :color="activeColor"></u-icon>
41
+ <text>书签</text>
42
+ </view>
43
+ <view
44
+ v-for="bookmark in bookmarks"
45
+ :key="bookmark.id"
46
+ class="up-novel-reader__bookmark-item"
47
+ @tap="selectBookmark(bookmark)"
48
+ >
49
+ <text class="up-novel-reader__bookmark-excerpt">{{ bookmark.excerpt || '书签位置' }}</text>
50
+ <text class="up-novel-reader__bookmark-progress">{{ bookmark.chapterIndex + 1 }} 章</text>
51
+ </view>
52
+ </view>
53
+ </scroll-view>
54
+ </view>
55
+ </template>
56
+
57
+ <script>
58
+ export default {
59
+ name: 'NovelReaderCatalog',
60
+ props: {
61
+ chapters: {
62
+ type: Array,
63
+ default: () => []
64
+ },
65
+ currentChapter: {
66
+ type: Object,
67
+ default: null
68
+ },
69
+ bookmarks: {
70
+ type: Array,
71
+ default: () => []
72
+ },
73
+ progress: {
74
+ type: Object,
75
+ default: () => ({})
76
+ },
77
+ themeTokens: {
78
+ type: Object,
79
+ default: () => ({})
80
+ },
81
+ },
82
+ emits: ['chapter-select', 'bookmark-select'],
83
+ computed: {
84
+ catalogStyle() {
85
+ return {
86
+ color: this.themeTokens.text || '#303133',
87
+ backgroundColor: this.themeTokens.background || '#ffffff'
88
+ }
89
+ },
90
+ activeColor() {
91
+ return this.themeTokens.active || '#2979ff'
92
+ },
93
+ mutedColor() {
94
+ return this.themeTokens.muted || '#909399'
95
+ }
96
+ },
97
+ methods: {
98
+ displayIndex(chapter) {
99
+ const index = Number(chapter && chapter.index)
100
+ return Number.isFinite(index) ? index + 1 : ''
101
+ },
102
+ isCurrent(chapter) {
103
+ return Boolean(
104
+ chapter &&
105
+ this.currentChapter &&
106
+ chapter.id === this.currentChapter.id
107
+ )
108
+ },
109
+ selectChapter(chapter) {
110
+ if (!chapter || chapter.isLocked) return
111
+ this.$emit('chapter-select', chapter)
112
+ },
113
+ selectBookmark(bookmark) {
114
+ if (!bookmark) return
115
+ this.$emit('bookmark-select', bookmark)
116
+ }
117
+ }
118
+ }
119
+ </script>
120
+
121
+ <style lang="scss" scoped>
122
+ .up-novel-reader__catalog {
123
+ display: flex;
124
+ flex-direction: column;
125
+ width: 82vw;
126
+ max-width: 360px;
127
+ height: 100%;
128
+ box-sizing: border-box;
129
+ }
130
+
131
+ .up-novel-reader__catalog-header {
132
+ display: flex;
133
+ flex-direction: row;
134
+ align-items: flex-end;
135
+ justify-content: space-between;
136
+ padding: 20px 18px 14px;
137
+ border-bottom: 1px solid var(--up-novel-reader-border, rgba(48, 49, 51, 0.12));
138
+ }
139
+
140
+ .up-novel-reader__catalog-title {
141
+ font-size: 20px;
142
+ font-weight: 600;
143
+ }
144
+
145
+ .up-novel-reader__catalog-count {
146
+ color: var(--up-novel-reader-muted, #909399);
147
+ font-size: 12px;
148
+ }
149
+
150
+ .up-novel-reader__catalog-scroll {
151
+ flex: 1;
152
+ min-height: 0;
153
+ }
154
+
155
+ .up-novel-reader__catalog-item {
156
+ display: flex;
157
+ flex-direction: row;
158
+ align-items: center;
159
+ min-height: 48px;
160
+ padding: 0 18px;
161
+ gap: 10px;
162
+ }
163
+
164
+ .up-novel-reader__catalog-item.is-current {
165
+ color: var(--up-novel-reader-active, #2979ff);
166
+ background-color: rgba(41, 121, 255, 0.08);
167
+ }
168
+
169
+ .up-novel-reader__catalog-item.is-locked {
170
+ opacity: 0.45;
171
+ }
172
+
173
+ .up-novel-reader__catalog-index {
174
+ display: flex;
175
+ flex-direction: row;
176
+ align-items: center;
177
+ justify-content: center;
178
+ width: 24px;
179
+ color: var(--up-novel-reader-muted, #909399);
180
+ font-size: 12px;
181
+ }
182
+
183
+ .up-novel-reader__catalog-item-title {
184
+ flex: 1;
185
+ overflow: hidden;
186
+ font-size: 14px;
187
+ text-overflow: ellipsis;
188
+ white-space: nowrap;
189
+ }
190
+
191
+ .up-novel-reader__catalog-empty {
192
+ padding: 36px 18px;
193
+ color: var(--up-novel-reader-muted, #909399);
194
+ text-align: center;
195
+ font-size: 14px;
196
+ }
197
+
198
+ .up-novel-reader__bookmark-section {
199
+ margin-top: 10px;
200
+ padding: 16px 18px 24px;
201
+ border-top: 1px solid var(--up-novel-reader-border, rgba(48, 49, 51, 0.12));
202
+ }
203
+
204
+ .up-novel-reader__bookmark-heading {
205
+ display: flex;
206
+ flex-direction: row;
207
+ align-items: center;
208
+ margin-bottom: 10px;
209
+ gap: 6px;
210
+ color: var(--up-novel-reader-muted, #909399);
211
+ font-size: 13px;
212
+ }
213
+
214
+ .up-novel-reader__bookmark-item {
215
+ display: flex;
216
+ flex-direction: row;
217
+ justify-content: space-between;
218
+ padding: 8px 0;
219
+ gap: 12px;
220
+ }
221
+
222
+ .up-novel-reader__bookmark-excerpt {
223
+ flex: 1;
224
+ overflow: hidden;
225
+ font-size: 13px;
226
+ text-overflow: ellipsis;
227
+ white-space: nowrap;
228
+ }
229
+
230
+ .up-novel-reader__bookmark-progress {
231
+ color: var(--up-novel-reader-muted, #909399);
232
+ font-size: 11px;
233
+ }
234
+ </style>