-
-
Save yeonsh/f8563430e7abd03014a0e210784c46bb to your computer and use it in GitHub Desktop.
Date Progress - Progress bar widget for days, weeks, months and years
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Date Progress - Progress bar widget for days, weeks, months and years | |
* - This widget run by Scriptable(https://scriptable.app). | |
* - This widget is optimized for 4x2 size. | |
* - Author: SDuck (https://twitter.com/sduck4) | |
* - Source: https://gist.github.com/SDuck4/a655230ec214083e432566a84e24c5f8 | |
* | |
* Parameters: | |
* - Each parameter is separated by `|`(vertical bar) and must be entered in the following order. | |
* - If you do not use the parameters, you can skip them. | |
* | |
* 1. Colors: Set colors of progress bars | |
* - Enter the color you want to set in hexcode format. | |
* - Each color is separated by `,`(comma). | |
* - You can enter 1~4 colors. | |
* - If the number of colors is smaller than 4, repeat the colors. | |
* - Ex 1. #3B82F6,#10B981,#FBBF24,#EF4444 | |
* - Ex 2. #34D399 | |
* | |
* 2. Labels: Set text for progress bar labels | |
* - Each label is separated by `,`(comma). | |
* - You can use the template string below. | |
* - ${dayOfMonth}: the day of the month. Ex. 1 | |
* - ${dayOfMonthWithZero}: the day of the month with zero. Ex. 01 | |
* - ${dayEn}: the days of the week in English. Ex. Sun, Mon, Tue, ... | |
* - ${dayKo}: the days of the week in Korean. Ex. 일, 월, 화, ... | |
* - ${weekOfYear}: the week number of the year. Ex. 42 | |
* - ${weekOfYearWithZero}: the week number of the year with zero. Ex. 04 | |
* - ${monthNum}: the month number. Ex. 11 | |
* - ${monthNumWithZero}: the month number with zero. Ex. 06 | |
* - ${monthEn}: the month name in English. Ex. Jan, Fab, Mar, ... | |
* - ${year}: the year number. Ex. 2021 | |
* - Ex. ${dayEn},W${weekOfYearWithZero},${monthEn},${year} | |
* | |
* 3. The week starts on Sunday: Set the day of the week starts | |
* - If `true`, the week starts on Sunnday. | |
* - If `false`, the week starts on Monday. | |
* - Default value is `false`. | |
*/ | |
const FONT_SIZE = 16; | |
const LINE_HEIGHT = 24; | |
const LABEL_WIDTH = 100; | |
const SPACER_SIZE = 10; | |
const BAR_WIDTH = 180; | |
const BAR_HEIGHT = 12; | |
const COLOR_LIGHT_GRAY = new Color('#E5E7EB', 1); | |
const COLOR_DARK_GRAY = new Color('#374151', 1); | |
const COLOR_BAR_BACKGROUND = Color.dynamic(COLOR_LIGHT_GRAY, COLOR_DARK_GRAY); | |
const COLOR_BAR_DEFAULT = new Color('#3B82F6', 1); | |
// Process parameters | |
const params = (args.widgetParameter + '').split('|'); | |
// Parameter: Colors | |
let colors = []; | |
if (params[0] !== '' && params[0] !== 'null') { | |
colors = params[0].split(',').map(color => color.trim()); | |
colors = colors.map(color => new Color(color, 1)); | |
} else { | |
colors.push(COLOR_BAR_DEFAULT); | |
} | |
function getColors(index) { | |
return colors[index % colors.length]; | |
} | |
// Parameter: Labels | |
const now = new Date(); | |
const labels = ['Day', 'Week', 'Month', 'Year']; | |
const calcWeekOfYear = (date) => { | |
const firstDayOfYear = new Date(date.getFullYear(), 0, 1); | |
const dayOfFirstDay = firstDayOfYear.getDay(); | |
const firstWeekStart = new Date(date.getFullYear(), 0, firstDayOfYear.getDay() > 3 ? 8 - dayOfFirstDay : 1 - dayOfFirstDay); | |
const weekNum = Math.floor((date.valueOf() - firstWeekStart.valueOf()) / 86400000 / 7) + 1; | |
return weekNum; | |
}; | |
const labelsTemplate = { | |
dayOfMonth: date => { | |
return date.getDate(); | |
}, | |
dayOfMonthWithZero: date => { | |
const dayNum = date.getDate(); | |
return dayNum < 10 ? '0' + dayNum : dayNum; | |
}, | |
dayEn: date => { | |
return ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()]; | |
}, | |
dayKo: date => { | |
return ['일', '월', '화', '수', '목', '금', '토'][date.getDay()]; | |
}, | |
weekOfYear: date => { | |
let weekNum = calcWeekOfYear(date); | |
if (weekNum === 0) { | |
weekNum = calcWeekOfYear(new Date(date.getFullYear(), 0, 0)); | |
} | |
return weekNum; | |
}, | |
weekOfYearWithZero: date => { | |
let weekNum = calcWeekOfYear(date); | |
if (weekNum === 0) { | |
weekNum = calcWeekOfYear(new Date(date.getFullYear(), 0, 0)); | |
} | |
return weekNum < 10 ? '0' + weekNum : weekNum; | |
}, | |
monthNum: date => { | |
return date.getMonth() + 1; | |
}, | |
monthNumWithZero: date => { | |
const monthNum = date.getMonth() + 1; | |
return monthNum < 10 ? '0' + monthNum : monthNum; | |
}, | |
monthEn: date => { | |
return ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][date.getMonth()]; | |
}, | |
year: date => { | |
return date.getFullYear(); | |
}, | |
}; | |
if (params.length > 1 && params[1] !== '') { | |
const paramLabels = params[1].split(',').map(label => label.trim()); | |
const templateRegExp = /(\${[^{}]+})/; | |
for (let i = 0; i < paramLabels.length; i++) { | |
while (paramLabels[i].match(templateRegExp)) { | |
const template = paramLabels[i].match(templateRegExp)[0]; | |
const templateKey = template.replace('${', '').replace('}', ''); | |
const templateValue = labelsTemplate[templateKey](now); | |
paramLabels[i] = paramLabels[i].replace(template, templateValue); | |
} | |
labels[i] = paramLabels[i]; | |
} | |
} | |
// Parameter: The week starts on Sunday | |
let isWeekStartsOnSunday = false; | |
if (params.length > 2 && params[2].toLowerCase() === 'true') { | |
isWeekStartsOnSunday = true; | |
} | |
// Calculate date progress | |
function calcProgress(start, end, progress) { | |
return (progress - start) / (end - start); | |
} | |
const dayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate()); | |
const dayEnd = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1); | |
const dayProgress = calcProgress(dayStart, dayEnd, now); | |
let weekDay = now.getDay() === 0 ? 6 : now.getDay() - 1; | |
if (isWeekStartsOnSunday) { | |
weekDay = now.getDay(); | |
} | |
const weekStart = new Date(now.getFullYear(), now.getMonth(), now.getDate() - weekDay); | |
const weekEnd = new Date(weekStart.getFullYear(), weekStart.getMonth(), weekStart.getDate() + 7); | |
const weekProgress = calcProgress(weekStart, weekEnd, now); | |
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1); | |
const monthEnd = new Date(now.getFullYear(), now.getMonth() + 1, 1); | |
const monthProgress = calcProgress(monthStart, monthEnd, now); | |
const yearStart = new Date(now.getFullYear(), 0, 1); | |
const yearEnd = new Date(now.getFullYear() + 1, 0, 1); | |
const yearProgress = calcProgress(yearStart, yearEnd, now); | |
// Create Widget | |
const font = Font.systemFont(FONT_SIZE); | |
const widget = new ListWidget(); | |
widget.spacing = SPACER_SIZE; | |
function addProgress(name, progress, color) { | |
const percent = Math.round(progress * 100); | |
const line = widget.addStack(); | |
line.centerAlignContent(); | |
const label = line.addStack(); | |
label.size = new Size(LABEL_WIDTH, LINE_HEIGHT); | |
label.centerAlignContent(); | |
const labelName = label.addText(name); | |
labelName.font = font; | |
label.addSpacer(); | |
const labelPercent = label.addText(percent + '%'); | |
labelPercent.font = font; | |
line.addSpacer(SPACER_SIZE); | |
const barBackground = line.addStack(); | |
barBackground.size = new Size(BAR_WIDTH, BAR_HEIGHT); | |
barBackground.backgroundColor = COLOR_BAR_BACKGROUND; | |
barBackground.cornerRadius = BAR_HEIGHT / 2; | |
barBackground.topAlignContent(); | |
barBackground.layoutVertically(); | |
const barProgressWidth = BAR_WIDTH * progress; | |
const barProgress = barBackground.addStack(); | |
barProgress.size = new Size(barProgressWidth, BAR_HEIGHT); | |
barProgress.backgroundColor = color; | |
barProgress.cornerRadius = BAR_HEIGHT / 2; | |
} | |
addProgress(labels[0], dayProgress, getColors(0)); | |
addProgress(labels[1], weekProgress, getColors(1)); | |
addProgress(labels[2], monthProgress, getColors(2)); | |
addProgress(labels[3], yearProgress, getColors(3)); | |
widget.presentMedium(); | |
Script.setWidget(widget); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment