-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathtracker.js
More file actions
135 lines (106 loc) · 4.63 KB
/
Copy pathtracker.js
File metadata and controls
135 lines (106 loc) · 4.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// for use in Scriptable in iOS to create a countdown widget with progress dots and a background image.
// =====================================================================================================
// USER CONFIGURATION
// =====================================================================================================
// STEP 1: Enter your event name
const EVENT_NAME = "SR";
// STEP 2: Set your start and end dates (Format: YYYY, MM-1, DD)
// IMPORTANT: Months are 0-indexed, meaning January=0, February=1, etc.
// Example: December 25, 2024 would be (2024, 11, 25)
const START_DATE = new Date(2026, 1, 19); // February 19, 2026
const END_DATE = new Date(2026, 4, 20); // May 20, 2026
// STEP 3: Add your background image URL
// Replace with your own image URL or leave blank for no image
const BG_IMAGE_URL = "";
// STEP 4: Customize the appearance (optional)
// Background overlay color and opacity
const BG_COLOR = "#406260"; // Overlay color in hex format
const BG_OVERLAY_OPACITY = 0.5; // Overlay opacity (0-1)
// Color settings for dots
const COLOR_FILLED = new Color("#ffffff"); // Color for completed days
const COLOR_UNFILLED = new Color("#ffffff", 0.4); // Color for remaining days
// STEP 5: Layout settings
// These are optimized for iPhone 16 Pro. You may need to adjust for different devices.
// Increase values for larger screens, decrease for smaller screens.
const PADDING = 8; // Space around the edges of the widget
const CIRCLE_SIZE = 6; // Size of the progress dots
const CIRCLE_SPACING = 4; // Space between dots
const TEXT_SPACING = 8; // Space between dot grid and text
const DOT_SHIFT_LEFT = 2;
const YEAR_OFFSET = DOT_SHIFT_LEFT - 2;
const DAYS_LEFT_OFFSET = 0;
// ==================================================================================================
// ADVANCED CONFIGURATION
// ==================================================================================================
const NOW = new Date();
const MS_PER_DAY = 86400000;
const DAYS_TOTAL = Math.round((END_DATE - START_DATE) / MS_PER_DAY) + 1;
const DAYS_SINCE_START = Math.max(0, Math.round((NOW - START_DATE) / MS_PER_DAY));
const DAYS_UNTIL_END = Math.max(0, Math.round((END_DATE - NOW) / MS_PER_DAY));
const widget = new ListWidget();
let bgImage = null;
try {
const req = new Request(BG_IMAGE_URL);
bgImage = await req.loadImage();
} catch (e) {
console.log("Couldn't load background image");
}
if (bgImage) {
widget.backgroundImage = bgImage;
}
const overlay = new LinearGradient();
overlay.locations = [0, 1];
overlay.colors = [
new Color(BG_COLOR, BG_OVERLAY_OPACITY),
new Color(BG_COLOR, BG_OVERLAY_OPACITY)
];
widget.backgroundGradient = overlay;
const WIDGET_WIDTH = 320;
const AVAILABLE_WIDTH = WIDGET_WIDTH - (2 * PADDING);
const TOTAL_CIRCLE_WIDTH = CIRCLE_SIZE + CIRCLE_SPACING;
const COLUMNS = Math.floor(AVAILABLE_WIDTH / TOTAL_CIRCLE_WIDTH);
const ROWS = Math.ceil(DAYS_TOTAL / COLUMNS);
const MENLO_REGULAR = new Font("Menlo", 12);
const MENLO_BOLD = new Font("Menlo-Bold", 12);
widget.setPadding(12, PADDING, 12, PADDING);
const gridContainer = widget.addStack();
gridContainer.layoutVertically();
const gridStack = gridContainer.addStack();
gridStack.layoutVertically();
gridStack.spacing = CIRCLE_SPACING;
for (let row = 0; row < ROWS; row++) {
const rowStack = gridStack.addStack();
rowStack.layoutHorizontally();
rowStack.addSpacer(DOT_SHIFT_LEFT);
for (let col = 0; col < COLUMNS; col++) {
const day = row * COLUMNS + col + 1;
if (day > DAYS_TOTAL) continue;
const circle = rowStack.addText("●");
circle.font = Font.systemFont(CIRCLE_SIZE);
circle.textColor = day <= DAYS_SINCE_START ? COLOR_FILLED : COLOR_UNFILLED;
if (col < COLUMNS - 1) rowStack.addSpacer(CIRCLE_SPACING);
}
}
widget.addSpacer(TEXT_SPACING);
const footer = widget.addStack();
footer.layoutHorizontally();
const eventStack = footer.addStack();
eventStack.addSpacer(YEAR_OFFSET);
const eventText = eventStack.addText(EVENT_NAME);
eventText.font = MENLO_BOLD;
eventText.textColor = COLOR_FILLED;
const daysText = `${DAYS_UNTIL_END} days left`;
const textWidth = daysText.length * 7.5;
const availableSpace = WIDGET_WIDTH - (PADDING * 2) - YEAR_OFFSET - (eventText.text.length * 7.5);
const spacerLength = availableSpace - textWidth + DAYS_LEFT_OFFSET;
footer.addSpacer(spacerLength);
const daysTextStack = footer.addStack();
const daysLeft = daysTextStack.addText(daysText);
daysLeft.font = MENLO_REGULAR;
daysLeft.textColor = COLOR_UNFILLED;
if (config.runsInWidget) {
Script.setWidget(widget);
} else {
widget.presentMedium();
}
Script.complete();