Skip to content

Commit df91ef6

Browse files
committed
Support chart decals (#302)
1 parent 01afbfd commit df91ef6

File tree

11 files changed

+156
-42
lines changed

11 files changed

+156
-42
lines changed

src/app/components/Option/Tabs.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import { t } from "@app/locale"
22
import { Refresh } from "@element-plus/icons-vue"
3+
import { useShadow } from "@hooks/useShadow"
34
import { ElIcon, ElMessage, ElTabPane, ElTabs } from "element-plus"
45
import { defineComponent, h, ref } from "vue"
56
import { useRouter } from "vue-router"
6-
import { changeQuery, OptionCategory, parseQuery } from "./common"
7-
import { useShadow } from "@hooks/useShadow"
87
import ContentContainer from "../common/ContentContainer"
8+
import { changeQuery, OptionCategory, parseQuery } from "./common"
99

1010
const resetButtonName = "reset"
1111

@@ -66,6 +66,12 @@ const _default = defineComponent({
6666
{h(ctx.slots.dailyLimit)}
6767
</ElTabPane>
6868
)}
69+
<ElTabPane
70+
name={"accessibility" satisfies OptionCategory}
71+
label={t(msg => msg.option.accessibility.title)}
72+
>
73+
{h(ctx.slots.accessibility)}
74+
</ElTabPane>
6975
<ElTabPane
7076
name={"backup" satisfies OptionCategory}
7177
label={t(msg => msg.option.backup.title)}

src/app/components/Option/common.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import { Router, useRoute } from "vue-router"
99

10-
export const ALL_CATEGORIES = ["appearance", "statistics", "popup", 'dailyLimit', 'backup'] as const
10+
export const ALL_CATEGORIES = ["appearance", "statistics", "popup", 'dailyLimit', 'accessibility', 'backup'] as const
1111
export type OptionCategory = typeof ALL_CATEGORIES[number]
1212

1313
export type OptionInstance = {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { t } from "@app/locale"
2+
import optionService from "@service/option-service"
3+
import { defaultAccessibility } from "@util/constant/option"
4+
import { ElSwitch } from "element-plus"
5+
import { defineComponent, reactive, unref, watch } from "vue"
6+
import { OptionInstance } from "../common"
7+
import OptionItem from "./OptionItem"
8+
9+
function copy(target: timer.option.AccessibilityOption, source: timer.option.AccessibilityOption) {
10+
target.chartDecal = source.chartDecal
11+
}
12+
13+
const _default = defineComponent((_, ctx) => {
14+
const option = reactive(defaultAccessibility())
15+
optionService.getAllOption()
16+
.then(currentVal => {
17+
copy(option, currentVal)
18+
watch(option, () => optionService.setAccessibilityOption(unref(option)))
19+
})
20+
ctx.expose({
21+
reset: () => copy(option, defaultAccessibility())
22+
} satisfies OptionInstance)
23+
return () => <>
24+
<OptionItem
25+
label={msg => msg.option.accessibility.chartDecal}
26+
defaultValue={t(msg => msg.option.no)}
27+
hideDivider
28+
v-slots={{
29+
default: () => <ElSwitch
30+
modelValue={option.chartDecal}
31+
onChange={(val: boolean) => option.chartDecal = val}
32+
/>
33+
}}
34+
/>
35+
</>
36+
})
37+
38+
export default _default

src/app/components/Option/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { MediaSize } from "@hooks/useMediaSize"
99
import { defineComponent, ref, type Ref } from "vue"
1010
import { JSX } from "vue/jsx-runtime"
1111
import { OptionCategory, OptionInstance } from "./common"
12+
import AccessibilityOption from "./components/AccessibilityOption"
1213
import AppearanceOption from "./components/AppearanceOption"
1314
import BackupOption from './components/BackupOption'
1415
import LimitOption from './components/LimitOption'
@@ -25,6 +26,7 @@ const _default = defineComponent(() => {
2526
popup: ref(),
2627
backup: ref(),
2728
dailyLimit: ref(),
29+
accessibility: ref(),
2830
}
2931

3032
const mediaSize = useMediaSize()
@@ -34,6 +36,7 @@ const _default = defineComponent(() => {
3436
statistics: () => <StatisticsOption ref={paneRefMap.statistics} />,
3537
popup: () => <PopupOption ref={paneRefMap.popup} />,
3638
dailyLimit: () => <LimitOption ref={paneRefMap.dailyLimit} />,
39+
accessibility: () => <AccessibilityOption ref={paneRefMap.accessibility} />,
3740
backup: () => <BackupOption ref={paneRefMap.backup} />,
3841
}
3942

src/hooks/useEcharts.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,57 @@
88

99
import { ElLoading } from "element-plus"
1010
import { type Ref, onMounted, ref, isRef, watch } from "vue"
11-
import { init, type ECharts } from "echarts"
11+
import { AriaComponentOption, ComposeOption, init, ECharts } from "echarts"
1212
import { useWindowSize } from "@vueuse/core"
13+
import accessibilityHelper from "@service/components/accessibility-helper"
14+
15+
type BaseEchartsOption = ComposeOption<AriaComponentOption>
16+
17+
export const generateAriaOption = async (): Promise<AriaComponentOption> => {
18+
const { chartDecal } = await accessibilityHelper.getOption() || {}
19+
if (!chartDecal) {
20+
return { enabled: false }
21+
}
22+
const color = "rgba(0, 0, 0, 0.2)"
23+
return {
24+
enabled: true,
25+
decal: {
26+
show: true,
27+
decals: [{
28+
color,
29+
dashArrayX: [1, 0],
30+
dashArrayY: [2, 5],
31+
rotation: .5235987755982988,
32+
}, {
33+
color,
34+
symbol: 'circle',
35+
dashArrayX: [[8, 8], [0, 8, 8, 0]],
36+
dashArrayY: [6, 0],
37+
symbolSize: .8,
38+
}, {
39+
color,
40+
dashArrayX: [1, 0],
41+
dashArrayY: [4, 3],
42+
rotation: -.7853981633974483
43+
}, {
44+
color,
45+
dashArrayX: [[6, 6], [0, 6, 6, 0]],
46+
dashArrayY: [6, 0],
47+
}, {
48+
color,
49+
dashArrayX: [[1, 0], [1, 6]],
50+
dashArrayY: [1, 0, 6, 0],
51+
rotation: .7853981633974483,
52+
}, {
53+
color,
54+
symbol: 'triangle',
55+
dashArrayX: [[9, 9], [0, 9, 9, 0]],
56+
dashArrayY: [7, 2],
57+
symbolSize: .75,
58+
}]
59+
}
60+
}
61+
}
1362

1463
export abstract class EchartsWrapper<BizOption, EchartsOption> {
1564
protected instance: ECharts
@@ -32,8 +81,10 @@ export abstract class EchartsWrapper<BizOption, EchartsOption> {
3281

3382
private async innerRender() {
3483
const biz = this.lastBizOption
35-
const option = await this.generateOption(biz)
84+
const option = await this.generateOption(biz) as (EchartsOption & BaseEchartsOption)
3685
if (!option) return
86+
const aria = await generateAriaOption()
87+
option.aria = aria
3788
this.instance.setOption(option, { notMerge: false })
3889
}
3990

src/i18n/message/app/option-resource.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@
121121
"interval": "每 {input} 分钟备份一次"
122122
}
123123
},
124+
"accessibility": {
125+
"title": "无障碍功能",
126+
"chartDecal": "{input} 是否显示图表的贴花图案"
127+
},
124128
"resetButton": "恢复默认",
125129
"resetSuccess": "成功重置为默认值",
126130
"defaultValue": "默认值: {default}"
@@ -369,6 +373,10 @@
369373
"interval": "and run every {input} minutes"
370374
}
371375
},
376+
"accessibility": {
377+
"title": "Accessibility",
378+
"chartDecal": "{input} Whether to display the chart decal"
379+
},
372380
"resetButton": "Reset",
373381
"resetSuccess": "Reset to default successfully!",
374382
"defaultValue": "Default: {default}"

src/i18n/message/app/option.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,10 @@ export type OptionMessage = {
116116
interval: string
117117
}
118118
}
119+
accessibility: {
120+
title: string
121+
chartDecal: string
122+
}
119123
resetButton: string
120124
resetSuccess: string
121125
defaultValue: string
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import optionService from "@service/option-service"
2+
3+
class AccessibilityHelper {
4+
private option: timer.option.AccessibilityOption = null
5+
6+
public async getOption(): Promise<timer.option.AccessibilityOption> {
7+
if (this.option == null) {
8+
this.option = await optionService.getAllOption()
9+
optionService.addOptionChangeListener(val => this.option = val)
10+
}
11+
return this.option
12+
}
13+
}
14+
15+
export default new AccessibilityHelper()

src/service/option-service.ts

Lines changed: 6 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,48 +6,17 @@
66
*/
77

88
import OptionDatabase from "@db/option-database"
9-
import {
10-
defaultAppearance,
11-
defaultPopup,
12-
defaultStatistics,
13-
defaultBackup,
14-
defaultDailyLimit,
15-
} from "@util/constant/option"
9+
import { defaultOption } from "@util/constant/option"
1610

1711
const db = new OptionDatabase(chrome.storage.local)
1812

19-
const defaultOption = () => ({
20-
...defaultAppearance(),
21-
...defaultPopup(),
22-
...defaultStatistics(),
23-
...defaultDailyLimit(),
24-
...defaultBackup(),
25-
})
26-
2713
async function getAllOption(): Promise<timer.option.AllOption> {
2814
const exist: Partial<timer.option.AllOption> = await db.getOption()
2915
const result: timer.option.AllOption = defaultOption()
3016
Object.entries(exist).forEach(([key, val]) => result[key] = val)
3117
return result
3218
}
3319

34-
async function setPopupOption(option: timer.option.PopupOption): Promise<void> {
35-
await setOption(option)
36-
}
37-
38-
async function setAppearanceOption(option: timer.option.AppearanceOption): Promise<void> {
39-
await setOption(option)
40-
}
41-
42-
async function setStatisticsOption(option: timer.option.StatisticsOption): Promise<void> {
43-
await setOption(option)
44-
}
45-
46-
async function setDailyLimitOption(option: timer.option.DailyLimitOption): Promise<void> {
47-
// Rewrite password
48-
await setOption(option)
49-
}
50-
5120
async function setBackupOption(option: Partial<timer.option.BackupOption>): Promise<void> {
5221
// Rewrite auths
5322
const existOption = await getAllOption()
@@ -105,13 +74,14 @@ async function isDarkMode(targetVal?: timer.option.AppearanceOption): Promise<bo
10574

10675
class OptionService {
10776
getAllOption = getAllOption
108-
setPopupOption = setPopupOption
109-
setAppearanceOption = setAppearanceOption
110-
setStatisticsOption = setStatisticsOption
77+
setPopupOption = setOption
78+
setAppearanceOption = setOption
79+
setAccessibilityOption = setOption
80+
setStatisticsOption = setOption
11181
/**
11282
* @since 1.9.0
11383
*/
114-
setDailyLimitOption = setDailyLimitOption
84+
setDailyLimitOption = setOption
11585
/**
11686
* @since 1.2.0
11787
*/

src/util/constant/option.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,19 @@ export function defaultBackup(): timer.option.BackupOption {
6464
}
6565
}
6666

67+
export function defaultAccessibility(): timer.option.AccessibilityOption {
68+
return {
69+
chartDecal: false,
70+
}
71+
}
72+
6773
export function defaultOption(): timer.option.AllOption {
6874
return {
6975
...defaultPopup(),
7076
...defaultAppearance(),
7177
...defaultStatistics(),
7278
...defaultBackup(),
7379
...defaultDailyLimit(),
80+
...defaultAccessibility(),
7481
}
7582
}

0 commit comments

Comments
 (0)