Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ declare namespace Timer {
displaySiteName: boolean
}

type AppearanceOptionDarkMode =
// Always on
| "on"
// Always off
| "off"
// Timed on
| "timed"
type AppearanceOption = {
/**
* Whether to display the whitelist button in the context menu
Expand All @@ -58,6 +65,20 @@ declare namespace Timer {
* @since 0.8.6
*/
printInConsole: boolean
/**
* The state of dark mode
*
* @since 1.1.0
*/
darkMode: AppearanceOptionDarkMode

/**
* The range of seconds to turn on dark mode. Required if {@param darkMode} is 'timed'
*
* @since 1.1.0
*/
darkModeTimeStart?: number
darkModeTimeEnd?: number
}

type StatisticsOption = {
Expand Down
8 changes: 6 additions & 2 deletions public/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,18 @@
<div id="type-select-container" class="el-select el-select--mini option-right">
<div class="select-trigger">
<div class="el-input el-input--mini el-input--suffix">
<input id="type-select-input" class="el-input__inner" type="text" readonly="" autocomplete="off" />
<div class="el-input__wrapper">
<input id="type-select-input" class="el-input__inner" type="text" readonly="" autocomplete="off" />
</div>
</div>
</div>
</div>
<div id="time-select-container" class="el-select el-select--mini option-right">
<div class="select-trigger">
<div class="el-input el-input--mini el-input--suffix">
<input id="time-select-input" class="el-input__inner" type="text" readonly="" autocomplete="off" />
<div class="el-input__wrapper">
<input id="time-select-input" class="el-input__inner" type="text" readonly="" autocomplete="off" />
</div>
</div>
</div>
</div>
Expand Down
21 changes: 16 additions & 5 deletions src/app/components/dashboard/components/calendar-heat-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { ElLoading } from "element-plus"
import { defineComponent, h, onMounted, ref, Ref } from "vue"
import { groupBy, rotate } from "@util/array"
import { BASE_TITLE_OPTION } from "../common"
import { getPrimaryTextColor } from "@util/style"

const WEEK_NUM = 53

Expand Down Expand Up @@ -110,14 +111,18 @@ function optionOf(data: _Value[], days: string[]): EcOption {
const totalMinutes = data.map(d => d[2] || 0).reduce((a, b) => a + b, 0)
const totalHours = Math.floor(totalMinutes / 60)
const xAxisLabelMap = getXAxisLabelMap(data)
const textColor = getPrimaryTextColor()
return {
title: {
...BASE_TITLE_OPTION,
text: t(msg => totalHours
? msg.dashboard.heatMap.title0
: msg.dashboard.heatMap.title1,
{ hour: totalHours }
)
),
textStyle: {
color: textColor
}
},
tooltip: {
position: 'top',
Expand All @@ -137,12 +142,16 @@ function optionOf(data: _Value[], days: string[]): EcOption {
formatter: (x: string) => xAxisLabelMap[x] || '',
interval: 0,
margin: 14,
color: textColor
},
},
yAxis: {
type: 'category',
data: days,
axisLabel: { padding: /* T R B L */[0, 12, 0, 0] },
axisLabel: {
padding: /* T R B L */[0, 12, 0, 0],
color: textColor
},
axisLine: { show: false },
axisTick: { show: false, alignWithLabel: true }
},
Expand All @@ -155,19 +164,21 @@ function optionOf(data: _Value[], days: string[]): EcOption {
orient: 'vertical',
right: '2%',
top: 'center',
dimension: 2
dimension: 2,
textStyle: {
color: textColor
}
}],
series: [{
name: 'Daily Focus',
type: 'heatmap',
data: data.map(d => {
let item = { value: d, itemStyle: undefined, label: undefined, emphasis: undefined, tooltip: undefined, silent: false }
const minutes = d[2]
const date = d[3]
if (minutes) {
} else {
item.itemStyle = {
color: '#fff',
color: 'transparent',
}
item.emphasis = {
disabled: true
Expand Down
12 changes: 9 additions & 3 deletions src/app/components/dashboard/components/top-k-visit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import type { ECharts, ComposeOption } from "echarts/core"
import type { PieSeriesOption } from "echarts/charts"
import type { TitleComponentOption, TooltipComponentOption } from "echarts/components"
import type { Ref } from "vue"
import type { TimerQueryParam } from "@service/timer-service"

import { init, use } from "@echarts/core"
import PieChart from "@echarts/chart/pie"
Expand All @@ -16,13 +18,14 @@ import TooltipComponent from "@echarts/component/tooltip"

use([PieChart, TitleComponent, TooltipComponent])

import timerService, { SortDirect, TimerQueryParam } from "@service/timer-service"
import timerService, { SortDirect } from "@service/timer-service"
import { MILL_PER_DAY } from "@util/time"
import { ElLoading } from "element-plus"
import { defineComponent, h, onMounted, ref, Ref } from "vue"
import { defineComponent, h, onMounted, ref } from "vue"
import DataItem from "@entity/dto/data-item"
import { BASE_TITLE_OPTION } from "../common"
import { t } from "@app/locale"
import { getPrimaryTextColor } from "@util/style"

const CONTAINER_ID = '__timer_dashboard_top_k_visit'
const TOP_NUM = 6
Expand All @@ -40,10 +43,12 @@ type _Value = {
}

function optionOf(data: _Value[]): EcOption {
const textColor = getPrimaryTextColor()
return {
title: {
...BASE_TITLE_OPTION,
text: t(msg => msg.dashboard.topK.title, { k: TOP_NUM, day: DAY_NUM })
text: t(msg => msg.dashboard.topK.title, { k: TOP_NUM, day: DAY_NUM }),
textStyle: { color: textColor }
},
tooltip: {
show: true,
Expand All @@ -64,6 +69,7 @@ function optionOf(data: _Value[]): EcOption {
itemStyle: {
borderRadius: 7
},
label: { color: textColor },
data: data
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/app/components/dashboard/components/week-on-week.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import DataItem from "@entity/dto/data-item"
import { groupBy, sum } from "@util/array"
import { BASE_TITLE_OPTION } from "../common"
import { t } from "@app/locale"
import { getPrimaryTextColor } from "@util/style"

type EcOption = ComposeOption<
| CandlestickSeriesOption
Expand All @@ -48,6 +49,7 @@ type _Value = {
}

function optionOf(lastPeriodItems: DataItem[], thisPeriodItems: DataItem[]): EcOption {
const textColor = getPrimaryTextColor()
const lastPeriodMap: { [host: string]: number } = groupBy(lastPeriodItems,
item => item.host,
grouped => Math.floor(sum(grouped.map(item => item.focus)) / 1000)
Expand Down Expand Up @@ -113,15 +115,18 @@ function optionOf(lastPeriodItems: DataItem[], thisPeriodItems: DataItem[]): EcO
},
xAxis: {
type: 'category',
name: 'Seconds',
splitLine: { show: false },
data: topK.map(a => a.host),
axisLabel: {
interval: 0
interval: 0,
color: textColor,
},
},
yAxis: {
type: 'value',
axisLabel: {
color: textColor,
}
},
series: [{
type: 'candlestick',
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/dashboard/feedback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const _default = defineComponent({
}, h(ElTooltip, {
placement: 'top',
content: t(msg => msg.dashboard.feedback.tooltip),
effect: Effect.LIGHT,
effect: Effect.DARK,
}, () => h(ElButton, {
type: "info",
size: 'small',
Expand Down
18 changes: 15 additions & 3 deletions src/app/components/habit/component/chart/wrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { PeriodKey, PERIODS_PER_DATE } from "@entity/dto/period-info"
import PeriodResult from "@entity/dto/period-result"
import { formatPeriodCommon, formatTime, MILL_PER_DAY } from "@util/time"
import { t } from "@app/locale"
import { getPrimaryTextColor, getSecondaryTextColor } from "@util/style"

type EcOption = ComposeOption<
| BarSeriesOption
Expand Down Expand Up @@ -89,9 +90,12 @@ function generateOptions(data: PeriodResult[], averageByDate: boolean, periodSiz
const xAxisMin = periodData[0].startTime.getTime()
const xAxisMax = periodData[periodData.length - 1].endTime.getTime()
const xAxisAxisLabelFormatter = averageByDate ? '{HH}:{mm}' : formatXAxis
const textColor = getPrimaryTextColor()
const secondaryTextColor = getSecondaryTextColor()
return {
title: {
text: TITLE,
textStyle: { color: textColor },
left: 'center'
},
tooltip: {
Expand All @@ -105,18 +109,26 @@ function generateOptions(data: PeriodResult[], averageByDate: boolean, periodSiz
title: t(msg => msg.habit.chart.saveAsImageTitle),
name: TITLE, // file name
excludeComponents: ['toolbox'],
pixelRatio: 1
pixelRatio: 1,
iconStyle: {
borderColor: secondaryTextColor
}
}
}
},
xAxis: {
axisLabel: { formatter: xAxisAxisLabelFormatter },
axisLabel: { formatter: xAxisAxisLabelFormatter, color: textColor },
type: 'time',
axisLine: { show: false },
min: xAxisMin,
max: xAxisMax
},
yAxis: { name: Y_AXIAS_NAME, type: 'value' },
yAxis: {
name: Y_AXIAS_NAME,
nameTextStyle: { color: textColor },
type: 'value',
axisLabel: { color: textColor },
},
series: [{
type: "bar",
large: true,
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/option/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function renderOptionItem(input: VNode | { [key: string]: VNode }, label:
* @param text text
*/
export function tagText(text: I18nKey): VNode {
return h('a', { style: { color: '#F56C6C' } }, t(text))
return h('a', { class: 'option-tag' }, t(text))
}

/**
Expand Down
98 changes: 98 additions & 0 deletions src/app/components/option/components/appearance/dark-mode-input.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* Copyright (c) 2022 Hengyang Zhang
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
import { Ref, PropType, ComputedRef, watch } from "vue"

import { ElOption, ElSelect, ElTimePicker } from "element-plus"
import { defineComponent, ref, h, computed } from "vue"
import { t } from "@app/locale"

function computeSecondToDate(secondOfDate: number): Date {
const now = new Date()
const hour = Math.floor(secondOfDate / 3600)
const minute = Math.floor((secondOfDate - hour * 3600) / 60)
const second = Math.floor(secondOfDate % 60)
now.setHours(hour)
now.setMinutes(minute)
now.setSeconds(second)
now.setMilliseconds(0)
return now
}

function computeDateToSecond(date: Date) {
const hour = date.getHours()
const minute = date.getMinutes()
const second = date.getSeconds()
return hour * 3600 + minute * 60 + second
}

const _default = defineComponent({
name: "DarkModeInput",
props: {
modelValue: String as PropType<Timer.AppearanceOptionDarkMode>,
startSecond: Number,
endSecond: Number
},
emits: ["change"],
setup(props, ctx) {
const darkMode: Ref<Timer.AppearanceOptionDarkMode> = ref(props.modelValue)
// @ts-ignore
const start: Ref<Date> = ref(computeSecondToDate(props.startSecond))
// @ts-ignore
const end: Ref<Date> = ref(computeSecondToDate(props.endSecond))
watch(() => props.modelValue, newVal => darkMode.value = newVal)
watch(() => props.startSecond, newVal => start.value = computeSecondToDate(newVal))
watch(() => props.endSecond, newVal => end.value = computeSecondToDate(newVal))
const startSecond: ComputedRef<number> = computed(() => computeDateToSecond(start.value))
const endSecond: ComputedRef<number> = computed(() => computeDateToSecond(end.value))

const handleChange = () => ctx.emit("change", darkMode.value, [startSecond.value, endSecond.value])

return () => {
const result = [h(ElSelect, {
modelValue: darkMode.value,
size: 'small',
style: { width: '120px', marginLeft: '10px' },
onChange: async (newVal: string) => {
const before = darkMode.value
darkMode.value = newVal as Timer.AppearanceOptionDarkMode
handleChange()
}
}, {
default: () => ["on", "off", "timed"].map(
value => h(ElOption, { value, label: t(msg => msg.option.appearance.darkMode.options[value]) })
)
})]
if (darkMode.value === "timed") {
result.push(
h(ElTimePicker, {
modelValue: start.value,
size: "small",
style: { marginLeft: '10px' },
"onUpdate:modelValue": (newVal) => {
start.value = newVal
handleChange()
},
clearable: false
}),
h('a', '-'),
h(ElTimePicker, {
modelValue: end.value,
size: "small",
"onUpdate:modelValue": (newVal) => {
end.value = newVal
handleChange()
},
clearable: false
})
)
}
return result
}
}
})

export default _default
Loading