Skip to content

Commit 0a426c1

Browse files
committed
Improve UI
1 parent 48abe47 commit 0a426c1

File tree

24 files changed

+479
-217
lines changed

24 files changed

+479
-217
lines changed

.codebeatignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
src/**/*.tsx
1+
src/**/*.tsx
2+
src/**/*Wrapper.ts

src/app/components/About/Description.tsx

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
import { t } from "@app/locale"
2-
import { CHROME_HOMEPAGE, EDGE_HOMEPAGE, FEEDBACK_QUESTIONNAIRE, FIREFOX_HOMEPAGE, getHomepageWithLocale, GITHUB_ISSUE_ADD, HOMEPAGE, REVIEW_PAGE, SOURCE_CODE_PAGE } from "@util/constant/url"
2+
import {
3+
HOMEPAGE, CHROME_HOMEPAGE, EDGE_HOMEPAGE, FIREFOX_HOMEPAGE,
4+
FEEDBACK_QUESTIONNAIRE, GITHUB_ISSUE_ADD, REVIEW_PAGE,
5+
LICENSE_PAGE, PRIVACY_PAGE, SOURCE_CODE_PAGE, CHANGE_LOG_PAGE,
6+
getHomepageWithLocale,
7+
} from "@util/constant/url"
38
import { ElCard, ElDescriptions, ElDescriptionsItem, ElDivider, ElSpace, ElText } from "element-plus"
49
import { defineComponent, StyleValue } from "vue"
510
import InstallationLink from "./InstallationLink"
6-
import packageInfo from "@src/package"
11+
import packageInfo, { AUTHOR_EMAIL } from "@src/package"
712
import { locale } from "@i18n"
813
import "./description.sass"
914
import metaService from "@service/meta-service"
@@ -33,8 +38,8 @@ const _default = defineComponent(() => {
3338
</DescLink>
3439
</ElDescriptionsItem>
3540
<ElDescriptionsItem label={t(msg => msg.about.label.privacy)} labelAlign="right">
36-
<DescLink href="https://www.wfhg.cc/en/privacy.html">
37-
https://www.wfhg.cc/en/privacy.html
41+
<DescLink href={PRIVACY_PAGE}>
42+
{PRIVACY_PAGE}
3843
</DescLink>
3944
</ElDescriptionsItem>
4045
<ElDescriptionsItem label={t(msg => msg.about.label.sourceCode)} labelAlign="right">
@@ -43,10 +48,18 @@ const _default = defineComponent(() => {
4348
</DescLink>
4449
</ElDescriptionsItem>
4550
<ElDescriptionsItem label={t(msg => msg.about.label.license)} labelAlign="right">
46-
<DescLink href="https://github.com/sheepzh/timer/blob/main/LICENSE">
51+
<DescLink href={LICENSE_PAGE}>
4752
MIT License
4853
</DescLink>
4954
</ElDescriptionsItem>
55+
<ElDescriptionsItem label={t(msg => msg.base.changeLog)} labelAlign="right">
56+
<DescLink href={CHANGE_LOG_PAGE} icon="github">
57+
{CHANGE_LOG_PAGE}
58+
</DescLink>
59+
</ElDescriptionsItem>
60+
<ElDescriptionsItem label={t(msg => msg.about.label.support)} labelAlign="right">
61+
{AUTHOR_EMAIL}
62+
</ElDescriptionsItem>
5063
<ElDescriptionsItem label={t(msg => msg.about.label.installation)} labelAlign="right">
5164
<div style={INSTALLATION_STYLE}>
5265
<InstallationLink href={CHROME_HOMEPAGE} name="Chrome" source="chrome" />

src/app/components/About/index.tsx

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,11 @@ import ContentContainer from "../common/ContentContainer"
33
import Description from "./Description"
44

55
const _default = defineComponent({
6-
setup() {
7-
return () => (
8-
<ContentContainer>
9-
<Description />
10-
</ContentContainer>
11-
)
12-
}
6+
render: () => (
7+
<ContentContainer>
8+
<Description />
9+
</ContentContainer>
10+
)
1311
})
1412

1513
export default _default

src/app/components/Analysis/components/Summary/CalendarChart.tsx renamed to src/app/components/Analysis/components/Summary/Calendar/Wrapper.ts

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
1-
import { EchartsWrapper, useEcharts } from "@hooks"
2-
import { computed, defineComponent } from "vue"
3-
import { useAnalysisRows, useAnalysisTimeFormat } from "../../context"
1+
/**
2+
* Copyright (c) 2023 Hengyang Zhang
3+
*
4+
* This software is released under the MIT License.
5+
* https://opensource.org/licenses/MIT
6+
*/
7+
import { EchartsWrapper } from "@hooks"
48
import {
59
ComposeOption,
610
GridComponentOption,
@@ -142,12 +146,12 @@ function optionOf(data: _Value[], weekDays: string[], format: timer.app.TimeForm
142146
}
143147
}
144148

145-
type BizOption = {
149+
export type BizOption = {
146150
rows: timer.stat.Row[]
147151
timeFormat: timer.app.TimeFormat
148152
}
149153

150-
class ChartWrapper extends EchartsWrapper<BizOption, EcOption> {
154+
class Wrapper extends EchartsWrapper<BizOption, EcOption> {
151155
protected generateOption({ rows = [], timeFormat }: BizOption): EcOption | Promise<EcOption> {
152156
const endTime = new Date()
153157
const startTime = getWeeksAgo(endTime, locale === "zh_CN", WEEK_NUM)
@@ -171,12 +175,4 @@ class ChartWrapper extends EchartsWrapper<BizOption, EcOption> {
171175
}
172176
}
173177

174-
const _default = defineComponent(() => {
175-
const rows = useAnalysisRows()
176-
const timeFormat = useAnalysisTimeFormat()
177-
const bizOption = computed<BizOption>(() => ({ rows: rows.value, timeFormat: timeFormat.value }))
178-
const { elRef } = useEcharts(ChartWrapper, bizOption, { manual: false })
179-
return () => <div class="analysis-calendar-chart" ref={elRef} />
180-
})
181-
182-
export default _default
178+
export default Wrapper
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* Copyright (c) 2023 Hengyang Zhang
3+
*
4+
* This software is released under the MIT License.
5+
* https://opensource.org/licenses/MIT
6+
*/
7+
import { useEcharts } from "@hooks"
8+
import { computed, defineComponent } from "vue"
9+
import { useAnalysisRows, useAnalysisTimeFormat } from "../../../context"
10+
import Wrapper, { BizOption } from "./Wrapper"
11+
12+
const _default = defineComponent(() => {
13+
const rows = useAnalysisRows()
14+
const timeFormat = useAnalysisTimeFormat()
15+
const bizOption = computed<BizOption>(() => ({ rows: rows.value, timeFormat: timeFormat.value }))
16+
const { elRef } = useEcharts(Wrapper, bizOption, { manual: false })
17+
return () => <div class="analysis-calendar-chart" ref={elRef} />
18+
})
19+
20+
export default _default

src/app/components/Analysis/components/Summary/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { ElCol, ElRow } from "element-plus"
1212
import { t } from "@app/locale"
1313
import { cvt2LocaleTime, periodFormatter } from "@app/util/time"
1414
import { useAnalysisRows, useAnalysisSite, useAnalysisTimeFormat } from "../../context"
15-
import CalendarChart from "./CalendarChart"
15+
import Calendar from "./Calendar"
1616

1717
type Summary = {
1818
focus: number
@@ -74,7 +74,7 @@ const _default = defineComponent(() => {
7474
</KanbanIndicatorRow>
7575
</ElCol>
7676
<ElCol span={12}>
77-
<CalendarChart />
77+
<Calendar />
7878
</ElCol>
7979
</ElRow>
8080
</KanbanCard>

src/app/components/Analysis/components/Trend/Dimension/Chart.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import type { PropType } from "vue"
99
import type { DimensionEntry, ValueFormatter } from "@app/components/Analysis/util"
1010

1111
import { defineComponent, watch } from "vue"
12-
import ChartWrapper from "./wrapper"
12+
import Wrapper from "./Wrapper"
1313
import { useEcharts } from "@hooks"
1414

1515
const _default = defineComponent({
@@ -20,7 +20,7 @@ const _default = defineComponent({
2020
valueFormatter: Function as PropType<ValueFormatter>
2121
},
2222
setup(props) {
23-
const { elRef, refresh } = useEcharts(ChartWrapper, () => ({
23+
const { elRef, refresh } = useEcharts(Wrapper, () => ({
2424
entries: props.data,
2525
preEntries: props.previous,
2626
title: props.title,
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/**
2+
* Copyright (c) 2022 Hengyang Zhang
3+
*
4+
* This software is released under the MIT License.
5+
* https://opensource.org/licenses/MIT
6+
*/
7+
8+
import type { DimensionEntry } from "../../../util"
9+
import type { ComposeOption } from "echarts/core"
10+
import type { LineSeriesOption } from "echarts/charts"
11+
import type {
12+
TitleComponentOption,
13+
TooltipComponentOption,
14+
GridComponentOption,
15+
} from "echarts/components"
16+
17+
import { use } from "echarts/core"
18+
import { LineChart } from "echarts/charts"
19+
import { SVGRenderer } from "echarts/renderers"
20+
import { TitleComponent, TooltipComponent, GridComponent } from "echarts/components"
21+
22+
import { ValueFormatter } from "@app/components/Analysis/util"
23+
import { getSecondaryTextColor } from "@util/style"
24+
import { EchartsWrapper } from "@hooks"
25+
import { ZRColor } from "echarts/types/dist/shared"
26+
27+
use([
28+
LineChart,
29+
TitleComponent,
30+
TooltipComponent,
31+
GridComponent,
32+
SVGRenderer,
33+
])
34+
35+
type EcOption = ComposeOption<
36+
| LineSeriesOption
37+
| TitleComponentOption
38+
| TooltipComponentOption
39+
| GridComponentOption
40+
>
41+
42+
type BizOption = {
43+
entries: DimensionEntry[]
44+
preEntries: DimensionEntry[]
45+
title: string
46+
valueFormatter: ValueFormatter
47+
}
48+
49+
type ValueItem = LineSeriesOption["data"][0] & {
50+
_data: DimensionEntry
51+
}
52+
53+
const THIS_COLOR: ZRColor = {
54+
type: "linear",
55+
x: 0, y: 0,
56+
x2: 0, y2: 1,
57+
colorStops: [
58+
{ offset: 0, color: 'rgb(55, 162, 255)' },
59+
{ offset: 1, color: 'rgb(116, 21, 219)' },
60+
],
61+
}
62+
const PREV_COLOR: ZRColor = {
63+
type: "linear",
64+
x: 0, y: 0,
65+
x2: 0, y2: 1,
66+
colorStops: [
67+
{ offset: 0, color: 'rgb(255, 0, 135)' },
68+
{ offset: 1, color: 'rgb(135, 0, 157)' },
69+
],
70+
}
71+
72+
const createTooltipLine = (param: any, valueFormatter: ValueFormatter) => {
73+
const data = param.data as ValueItem
74+
const { _data: { value, date } } = data
75+
const color = param.color as string
76+
const p = document.createElement('p')
77+
p.style.margin = "0"
78+
p.style.padding = "0"
79+
p.style.alignItems = "center"
80+
p.style.display = "flex"
81+
82+
const dotEl = document.createElement('div')
83+
dotEl.style.width = '8px'
84+
dotEl.style.height = '8px'
85+
dotEl.style.display = 'inline-flex'
86+
dotEl.style.borderRadius = '4px'
87+
dotEl.style.backgroundColor = color
88+
dotEl.style.marginRight = '7px'
89+
p.append(dotEl)
90+
91+
const dateEl = document.createElement('span')
92+
dateEl.innerText = date
93+
dateEl.style.marginRight = "7px"
94+
p.appendChild(dateEl)
95+
96+
const valStr = valueFormatter?.(value) || value?.toString() || "NaN"
97+
const valEL = document.createElement('span')
98+
valEL.innerText = valStr
99+
valEL.style.fontWeight = "500"
100+
p.appendChild(valEL)
101+
return p
102+
}
103+
104+
const formatTooltip = (params: any[], valueFormatter: ValueFormatter) => {
105+
const container = document.createElement('div')
106+
container.style.height = "50px"
107+
container.style.display = "flex"
108+
container.style.flexDirection = "column"
109+
container.style.justifyContent = "space-around"
110+
111+
const lines = params.map(param => createTooltipLine(param, valueFormatter))
112+
lines.forEach(l => container.append(l))
113+
return container
114+
}
115+
116+
const generateOption = ({ entries, preEntries, title, valueFormatter }: BizOption) => {
117+
const thisExistData = entries?.some(e => !!e.value)
118+
const prevExistData = preEntries?.some(e => !!e.value)
119+
const thisPeriod: ValueItem[] = entries?.map(r => ({ name: r.date, value: r.value, _data: r }))
120+
const prevPeriod: ValueItem[] = preEntries?.map(r => ({ name: r.date, value: r.value, _data: r }))
121+
122+
const secondaryTextColor = getSecondaryTextColor()
123+
const option: EcOption = {
124+
backgroundColor: 'rgba(0,0,0,0)',
125+
title: {
126+
text: title,
127+
textStyle: {
128+
color: secondaryTextColor,
129+
fontSize: '14px',
130+
fontWeight: 'normal',
131+
},
132+
left: 'center',
133+
top: '9%',
134+
},
135+
grid: {
136+
top: '30%',
137+
bottom: '10px',
138+
left: '5%',
139+
right: '5%',
140+
},
141+
tooltip: {
142+
trigger: 'axis',
143+
axisPointer: { type: "line" },
144+
formatter: (params: any[]) => formatTooltip(params, valueFormatter),
145+
},
146+
xAxis: {
147+
type: 'category',
148+
data: entries?.map((_, idx) => ({ value: idx, textStyle: { width: 0, opacity: 0 } })),
149+
show: false,
150+
},
151+
yAxis: {
152+
type: 'value',
153+
axisLabel: { show: false },
154+
axisTick: { show: false },
155+
splitLine: { show: false },
156+
},
157+
series: [{
158+
data: prevPeriod,
159+
type: 'line',
160+
showSymbol: false,
161+
smooth: true,
162+
lineStyle: { width: prevExistData ? 0 : 1 },
163+
color: PREV_COLOR.colorStops[0].color,
164+
areaStyle: { opacity: .5, color: PREV_COLOR },
165+
emphasis: { focus: "self" },
166+
}, {
167+
data: thisPeriod,
168+
type: 'line',
169+
showSymbol: false,
170+
smooth: true,
171+
lineStyle: { width: thisExistData ? 0 : 1 },
172+
color: THIS_COLOR.colorStops[0].color,
173+
areaStyle: { color: THIS_COLOR },
174+
emphasis: { focus: "series" },
175+
}]
176+
}
177+
return option
178+
}
179+
180+
export default class Wrapper extends EchartsWrapper<BizOption, EcOption> {
181+
generateOption = generateOption
182+
}

0 commit comments

Comments
 (0)