Dashify 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dashify-0.1.0/LICENSE +21 -0
- dashify-0.1.0/PKG-INFO +251 -0
- dashify-0.1.0/README.md +228 -0
- dashify-0.1.0/defaults/dashify.toml +55 -0
- dashify-0.1.0/pyproject.toml +54 -0
- dashify-0.1.0/src/main.py +13 -0
- dashify-0.1.0/src/modules/__init__.py +0 -0
- dashify-0.1.0/src/modules/app.py +47 -0
- dashify-0.1.0/src/modules/composer.py +87 -0
- dashify-0.1.0/src/modules/conf.py +62 -0
- dashify-0.1.0/src/modules/custom.py +85 -0
- dashify-0.1.0/src/modules/elements.py +671 -0
- dashify-0.1.0/src/modules/parser.py +38 -0
- dashify-0.1.0/src/modules/todo.py +376 -0
- dashify-0.1.0/src/modules/todo_store.py +128 -0
- dashify-0.1.0/src/modules/weather.py +108 -0
- dashify-0.1.0/src/modules/weather_service.py +87 -0
dashify-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Icecreambobcat
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
dashify-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: Dashify
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A configurable terminal dashboard built with Textual.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: dashboard,terminal,textual,tui
|
|
8
|
+
Author: Icecreambobcat
|
|
9
|
+
Author-email: icekingrex123@gmail.com
|
|
10
|
+
Requires-Python: >=3.14,<3.16
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Topic :: Utilities
|
|
15
|
+
Requires-Dist: psutil (>=7.2.2,<8.0.0)
|
|
16
|
+
Requires-Dist: pydantic (>=2.13.4,<3.0.0)
|
|
17
|
+
Requires-Dist: textual (>=7.5.0,<8.0.0)
|
|
18
|
+
Requires-Dist: tomlkit (>=0.15.0,<0.16.0)
|
|
19
|
+
Project-URL: Issues, https://github.com/Icecreambobcat/dashify/issues
|
|
20
|
+
Project-URL: Repository, https://github.com/Icecreambobcat/dashify
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# Dashify
|
|
24
|
+
|
|
25
|
+
Dashify is a configurable terminal dashboard built with
|
|
26
|
+
[Textual](https://textual.textualize.io/). It arranges clocks, timers, todos,
|
|
27
|
+
weather, and system information into nested horizontal and vertical tiles.
|
|
28
|
+
|
|
29
|
+
## Requirements
|
|
30
|
+
|
|
31
|
+
- Python 3.14 or 3.15
|
|
32
|
+
- A terminal with mouse support and Unicode glyphs
|
|
33
|
+
- Internet access for the Weather widget
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
Install [uv](https://docs.astral.sh/uv/getting-started/installation/), then
|
|
38
|
+
install Dashify as an isolated command-line tool. uv will obtain a compatible
|
|
39
|
+
Python interpreter when one is not already available:
|
|
40
|
+
|
|
41
|
+
```console
|
|
42
|
+
uv tool install --python 3.14 dashify
|
|
43
|
+
dashify
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
If `dashify` is not found after installation, add uv's executable directory to
|
|
47
|
+
your shell path and restart the shell:
|
|
48
|
+
|
|
49
|
+
```console
|
|
50
|
+
uv tool update-shell
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
To install directly from a source checkout instead:
|
|
54
|
+
|
|
55
|
+
```console
|
|
56
|
+
git clone https://github.com/Icecreambobcat/dashify.git
|
|
57
|
+
cd dashify
|
|
58
|
+
uv tool install --python 3.14 .
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Upgrade or remove Dashify with:
|
|
62
|
+
|
|
63
|
+
```console
|
|
64
|
+
uv tool upgrade dashify
|
|
65
|
+
uv tool uninstall dashify
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Dashify loads `~/.config/dashify/dashify.toml` when that file exists. Otherwise,
|
|
69
|
+
it uses its packaged default configuration. From a source checkout, copy the
|
|
70
|
+
documented default before customising your dashboard:
|
|
71
|
+
|
|
72
|
+
```console
|
|
73
|
+
mkdir -p ~/.config/dashify
|
|
74
|
+
cp defaults/dashify.toml ~/.config/dashify/dashify.toml
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Users who installed from PyPI can download the same versioned default:
|
|
78
|
+
|
|
79
|
+
```console
|
|
80
|
+
mkdir -p ~/.config/dashify
|
|
81
|
+
curl -L https://raw.githubusercontent.com/Icecreambobcat/dashify/v0.1.0/defaults/dashify.toml \
|
|
82
|
+
-o ~/.config/dashify/dashify.toml
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Press <kbd>Ctrl</kbd>+<kbd>Q</kbd> to quit.
|
|
86
|
+
|
|
87
|
+
## Configuration
|
|
88
|
+
|
|
89
|
+
The dashboard is a tree rooted at the `[widgets]` table. Every widget table
|
|
90
|
+
requires a `kind`. `HBox` divides its space equally from left to right, while
|
|
91
|
+
`VBox` divides its space equally from top to bottom. Any other nested table name
|
|
92
|
+
is simply a readable identifier for a child.
|
|
93
|
+
|
|
94
|
+
```toml
|
|
95
|
+
[widgets]
|
|
96
|
+
kind = "HBox"
|
|
97
|
+
|
|
98
|
+
[widgets.left]
|
|
99
|
+
kind = "VBox"
|
|
100
|
+
|
|
101
|
+
[widgets.left.clock]
|
|
102
|
+
kind = "Clock"
|
|
103
|
+
opts = { timezone = "Australia/Sydney" }
|
|
104
|
+
|
|
105
|
+
[widgets.left.timer]
|
|
106
|
+
kind = "Timer"
|
|
107
|
+
|
|
108
|
+
[widgets.right]
|
|
109
|
+
kind = "VBox"
|
|
110
|
+
|
|
111
|
+
[widgets.right.weather]
|
|
112
|
+
kind = "Weather"
|
|
113
|
+
opts = { location = "Melbourne", units = "metric", refresh_minutes = 15 }
|
|
114
|
+
|
|
115
|
+
[widgets.right.todos]
|
|
116
|
+
kind = "Todo"
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Only `HBox` and `VBox` treat named nested tables as children. Child tables on
|
|
120
|
+
ordinary widgets are ignored. The optional `opts` value must be a TOML table;
|
|
121
|
+
inline tables are preferred because they visually distinguish widget options
|
|
122
|
+
from layout children.
|
|
123
|
+
|
|
124
|
+
Malformed roots produce a centred warning screen. An invalid child or invalid
|
|
125
|
+
`opts` value produces a warning in that child's tile so that the rest of the
|
|
126
|
+
dashboard remains usable.
|
|
127
|
+
|
|
128
|
+
The widget snippets below are child tables intended to be added beneath an
|
|
129
|
+
`HBox` or `VBox` root such as the one in the complete example above.
|
|
130
|
+
|
|
131
|
+
## Built-in widgets
|
|
132
|
+
|
|
133
|
+
### Clock
|
|
134
|
+
|
|
135
|
+
`Clock` displays a 24-hour clock. It uses the local timezone by default.
|
|
136
|
+
`timezone` accepts `local`, `UTC`, a UTC offset, or an IANA timezone name.
|
|
137
|
+
|
|
138
|
+
```toml
|
|
139
|
+
[widgets.clock]
|
|
140
|
+
kind = "Clock"
|
|
141
|
+
opts = { timezone = "Europe/London" }
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Timer
|
|
145
|
+
|
|
146
|
+
`Timer` is a countdown with one Start/Stop/Reset button. While stopped, click
|
|
147
|
+
the digits, enter up to six digits in `HHMMSS` order, and press Enter. Input is
|
|
148
|
+
right-aligned, so `130` becomes `00:01:30`. Invalid minutes and seconds are
|
|
149
|
+
rejected. The border flashes yellow when the countdown finishes.
|
|
150
|
+
|
|
151
|
+
```toml
|
|
152
|
+
[widgets.timer]
|
|
153
|
+
kind = "Timer"
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Stopwatch
|
|
157
|
+
|
|
158
|
+
`Stopwatch` provides Start, Stop, and Reset controls. Reset remains visible but
|
|
159
|
+
is disabled while the stopwatch is running.
|
|
160
|
+
|
|
161
|
+
```toml
|
|
162
|
+
[widgets.stopwatch]
|
|
163
|
+
kind = "Stopwatch"
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### System monitor
|
|
167
|
+
|
|
168
|
+
`SystemMonitor` samples total CPU utilisation once per second. Its 38-sample
|
|
169
|
+
history graph uses green, yellow, and red threshold colours.
|
|
170
|
+
|
|
171
|
+
```toml
|
|
172
|
+
[widgets.system_monitor]
|
|
173
|
+
kind = "SystemMonitor"
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Weather
|
|
177
|
+
|
|
178
|
+
`Weather` uses Open-Meteo to display current conditions. No API key is needed.
|
|
179
|
+
The default location is Sydney, units are metric, and the refresh interval is
|
|
180
|
+
15 minutes. `units` accepts `metric` or `imperial`; the Refresh button requests
|
|
181
|
+
an immediate update.
|
|
182
|
+
|
|
183
|
+
```toml
|
|
184
|
+
[widgets.weather]
|
|
185
|
+
kind = "Weather"
|
|
186
|
+
opts = { location = "Perth", units = "metric", refresh_minutes = 10 }
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The configured location is sent to Open-Meteo's geocoding and forecast APIs.
|
|
190
|
+
Network and response errors are shown inside the widget without stopping the
|
|
191
|
+
dashboard.
|
|
192
|
+
|
|
193
|
+
### Todo
|
|
194
|
+
|
|
195
|
+
`Todo` stores a title, optional notes, and an optional ISO-format due date in a
|
|
196
|
+
local SQLite database at `~/.local/state/dashify/todo.db`. Todos remain in
|
|
197
|
+
insertion order.
|
|
198
|
+
|
|
199
|
+
Select **Manage todos** to enter the widget's interaction context. Menus support
|
|
200
|
+
the arrow keys and these Vim-inspired bindings:
|
|
201
|
+
|
|
202
|
+
- `j` / `k`: move down / up
|
|
203
|
+
- `g` / `G`: move to the first / last option
|
|
204
|
+
- `l` or `Enter`: select
|
|
205
|
+
- `Esc`: go back
|
|
206
|
+
|
|
207
|
+
Dashify asks before creating the database. Todo deletion and database deletion
|
|
208
|
+
are permanent; deleting the database requires a separate warning screen.
|
|
209
|
+
|
|
210
|
+
```toml
|
|
211
|
+
[widgets.todos]
|
|
212
|
+
kind = "Todo"
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Custom
|
|
216
|
+
|
|
217
|
+
`Custom` is a single-layer vertical arrangement. Its Boolean switches enable
|
|
218
|
+
available elements in a fixed order; `text` adds a short heading and `timezone`
|
|
219
|
+
configures an enabled clock. Each enabled widget otherwise retains its built-in
|
|
220
|
+
defaults.
|
|
221
|
+
|
|
222
|
+
```toml
|
|
223
|
+
[widgets.focus]
|
|
224
|
+
kind = "Custom"
|
|
225
|
+
opts = { text = "Focus", clock = true, timezone = "UTC", timer = true, weather = true }
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Available switches are `clock`, `timer`, `stopwatch`, `system_monitor`, `todo`,
|
|
229
|
+
and `weather`. Horizontal custom layouts are intentionally unsupported; use an
|
|
230
|
+
`HBox` in the main widget tree instead.
|
|
231
|
+
|
|
232
|
+
## Development
|
|
233
|
+
|
|
234
|
+
Install the development dependencies and run all release checks with:
|
|
235
|
+
|
|
236
|
+
```console
|
|
237
|
+
poetry install
|
|
238
|
+
poetry run black --check src tests
|
|
239
|
+
poetry run pyright
|
|
240
|
+
poetry run pytest
|
|
241
|
+
poetry check
|
|
242
|
+
poetry build
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Source files live in `src`, tests in `tests`, and the documented default layout
|
|
246
|
+
in `defaults/dashify.toml`.
|
|
247
|
+
|
|
248
|
+
## Licence
|
|
249
|
+
|
|
250
|
+
Dashify is released under the MIT Licence. See `LICENSE`.
|
|
251
|
+
|
dashify-0.1.0/README.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Dashify
|
|
2
|
+
|
|
3
|
+
Dashify is a configurable terminal dashboard built with
|
|
4
|
+
[Textual](https://textual.textualize.io/). It arranges clocks, timers, todos,
|
|
5
|
+
weather, and system information into nested horizontal and vertical tiles.
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Python 3.14 or 3.15
|
|
10
|
+
- A terminal with mouse support and Unicode glyphs
|
|
11
|
+
- Internet access for the Weather widget
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
Install [uv](https://docs.astral.sh/uv/getting-started/installation/), then
|
|
16
|
+
install Dashify as an isolated command-line tool. uv will obtain a compatible
|
|
17
|
+
Python interpreter when one is not already available:
|
|
18
|
+
|
|
19
|
+
```console
|
|
20
|
+
uv tool install --python 3.14 dashify
|
|
21
|
+
dashify
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If `dashify` is not found after installation, add uv's executable directory to
|
|
25
|
+
your shell path and restart the shell:
|
|
26
|
+
|
|
27
|
+
```console
|
|
28
|
+
uv tool update-shell
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
To install directly from a source checkout instead:
|
|
32
|
+
|
|
33
|
+
```console
|
|
34
|
+
git clone https://github.com/Icecreambobcat/dashify.git
|
|
35
|
+
cd dashify
|
|
36
|
+
uv tool install --python 3.14 .
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Upgrade or remove Dashify with:
|
|
40
|
+
|
|
41
|
+
```console
|
|
42
|
+
uv tool upgrade dashify
|
|
43
|
+
uv tool uninstall dashify
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Dashify loads `~/.config/dashify/dashify.toml` when that file exists. Otherwise,
|
|
47
|
+
it uses its packaged default configuration. From a source checkout, copy the
|
|
48
|
+
documented default before customising your dashboard:
|
|
49
|
+
|
|
50
|
+
```console
|
|
51
|
+
mkdir -p ~/.config/dashify
|
|
52
|
+
cp defaults/dashify.toml ~/.config/dashify/dashify.toml
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Users who installed from PyPI can download the same versioned default:
|
|
56
|
+
|
|
57
|
+
```console
|
|
58
|
+
mkdir -p ~/.config/dashify
|
|
59
|
+
curl -L https://raw.githubusercontent.com/Icecreambobcat/dashify/v0.1.0/defaults/dashify.toml \
|
|
60
|
+
-o ~/.config/dashify/dashify.toml
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Press <kbd>Ctrl</kbd>+<kbd>Q</kbd> to quit.
|
|
64
|
+
|
|
65
|
+
## Configuration
|
|
66
|
+
|
|
67
|
+
The dashboard is a tree rooted at the `[widgets]` table. Every widget table
|
|
68
|
+
requires a `kind`. `HBox` divides its space equally from left to right, while
|
|
69
|
+
`VBox` divides its space equally from top to bottom. Any other nested table name
|
|
70
|
+
is simply a readable identifier for a child.
|
|
71
|
+
|
|
72
|
+
```toml
|
|
73
|
+
[widgets]
|
|
74
|
+
kind = "HBox"
|
|
75
|
+
|
|
76
|
+
[widgets.left]
|
|
77
|
+
kind = "VBox"
|
|
78
|
+
|
|
79
|
+
[widgets.left.clock]
|
|
80
|
+
kind = "Clock"
|
|
81
|
+
opts = { timezone = "Australia/Sydney" }
|
|
82
|
+
|
|
83
|
+
[widgets.left.timer]
|
|
84
|
+
kind = "Timer"
|
|
85
|
+
|
|
86
|
+
[widgets.right]
|
|
87
|
+
kind = "VBox"
|
|
88
|
+
|
|
89
|
+
[widgets.right.weather]
|
|
90
|
+
kind = "Weather"
|
|
91
|
+
opts = { location = "Melbourne", units = "metric", refresh_minutes = 15 }
|
|
92
|
+
|
|
93
|
+
[widgets.right.todos]
|
|
94
|
+
kind = "Todo"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Only `HBox` and `VBox` treat named nested tables as children. Child tables on
|
|
98
|
+
ordinary widgets are ignored. The optional `opts` value must be a TOML table;
|
|
99
|
+
inline tables are preferred because they visually distinguish widget options
|
|
100
|
+
from layout children.
|
|
101
|
+
|
|
102
|
+
Malformed roots produce a centred warning screen. An invalid child or invalid
|
|
103
|
+
`opts` value produces a warning in that child's tile so that the rest of the
|
|
104
|
+
dashboard remains usable.
|
|
105
|
+
|
|
106
|
+
The widget snippets below are child tables intended to be added beneath an
|
|
107
|
+
`HBox` or `VBox` root such as the one in the complete example above.
|
|
108
|
+
|
|
109
|
+
## Built-in widgets
|
|
110
|
+
|
|
111
|
+
### Clock
|
|
112
|
+
|
|
113
|
+
`Clock` displays a 24-hour clock. It uses the local timezone by default.
|
|
114
|
+
`timezone` accepts `local`, `UTC`, a UTC offset, or an IANA timezone name.
|
|
115
|
+
|
|
116
|
+
```toml
|
|
117
|
+
[widgets.clock]
|
|
118
|
+
kind = "Clock"
|
|
119
|
+
opts = { timezone = "Europe/London" }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Timer
|
|
123
|
+
|
|
124
|
+
`Timer` is a countdown with one Start/Stop/Reset button. While stopped, click
|
|
125
|
+
the digits, enter up to six digits in `HHMMSS` order, and press Enter. Input is
|
|
126
|
+
right-aligned, so `130` becomes `00:01:30`. Invalid minutes and seconds are
|
|
127
|
+
rejected. The border flashes yellow when the countdown finishes.
|
|
128
|
+
|
|
129
|
+
```toml
|
|
130
|
+
[widgets.timer]
|
|
131
|
+
kind = "Timer"
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Stopwatch
|
|
135
|
+
|
|
136
|
+
`Stopwatch` provides Start, Stop, and Reset controls. Reset remains visible but
|
|
137
|
+
is disabled while the stopwatch is running.
|
|
138
|
+
|
|
139
|
+
```toml
|
|
140
|
+
[widgets.stopwatch]
|
|
141
|
+
kind = "Stopwatch"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### System monitor
|
|
145
|
+
|
|
146
|
+
`SystemMonitor` samples total CPU utilisation once per second. Its 38-sample
|
|
147
|
+
history graph uses green, yellow, and red threshold colours.
|
|
148
|
+
|
|
149
|
+
```toml
|
|
150
|
+
[widgets.system_monitor]
|
|
151
|
+
kind = "SystemMonitor"
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Weather
|
|
155
|
+
|
|
156
|
+
`Weather` uses Open-Meteo to display current conditions. No API key is needed.
|
|
157
|
+
The default location is Sydney, units are metric, and the refresh interval is
|
|
158
|
+
15 minutes. `units` accepts `metric` or `imperial`; the Refresh button requests
|
|
159
|
+
an immediate update.
|
|
160
|
+
|
|
161
|
+
```toml
|
|
162
|
+
[widgets.weather]
|
|
163
|
+
kind = "Weather"
|
|
164
|
+
opts = { location = "Perth", units = "metric", refresh_minutes = 10 }
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
The configured location is sent to Open-Meteo's geocoding and forecast APIs.
|
|
168
|
+
Network and response errors are shown inside the widget without stopping the
|
|
169
|
+
dashboard.
|
|
170
|
+
|
|
171
|
+
### Todo
|
|
172
|
+
|
|
173
|
+
`Todo` stores a title, optional notes, and an optional ISO-format due date in a
|
|
174
|
+
local SQLite database at `~/.local/state/dashify/todo.db`. Todos remain in
|
|
175
|
+
insertion order.
|
|
176
|
+
|
|
177
|
+
Select **Manage todos** to enter the widget's interaction context. Menus support
|
|
178
|
+
the arrow keys and these Vim-inspired bindings:
|
|
179
|
+
|
|
180
|
+
- `j` / `k`: move down / up
|
|
181
|
+
- `g` / `G`: move to the first / last option
|
|
182
|
+
- `l` or `Enter`: select
|
|
183
|
+
- `Esc`: go back
|
|
184
|
+
|
|
185
|
+
Dashify asks before creating the database. Todo deletion and database deletion
|
|
186
|
+
are permanent; deleting the database requires a separate warning screen.
|
|
187
|
+
|
|
188
|
+
```toml
|
|
189
|
+
[widgets.todos]
|
|
190
|
+
kind = "Todo"
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Custom
|
|
194
|
+
|
|
195
|
+
`Custom` is a single-layer vertical arrangement. Its Boolean switches enable
|
|
196
|
+
available elements in a fixed order; `text` adds a short heading and `timezone`
|
|
197
|
+
configures an enabled clock. Each enabled widget otherwise retains its built-in
|
|
198
|
+
defaults.
|
|
199
|
+
|
|
200
|
+
```toml
|
|
201
|
+
[widgets.focus]
|
|
202
|
+
kind = "Custom"
|
|
203
|
+
opts = { text = "Focus", clock = true, timezone = "UTC", timer = true, weather = true }
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Available switches are `clock`, `timer`, `stopwatch`, `system_monitor`, `todo`,
|
|
207
|
+
and `weather`. Horizontal custom layouts are intentionally unsupported; use an
|
|
208
|
+
`HBox` in the main widget tree instead.
|
|
209
|
+
|
|
210
|
+
## Development
|
|
211
|
+
|
|
212
|
+
Install the development dependencies and run all release checks with:
|
|
213
|
+
|
|
214
|
+
```console
|
|
215
|
+
poetry install
|
|
216
|
+
poetry run black --check src tests
|
|
217
|
+
poetry run pyright
|
|
218
|
+
poetry run pytest
|
|
219
|
+
poetry check
|
|
220
|
+
poetry build
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Source files live in `src`, tests in `tests`, and the documented default layout
|
|
224
|
+
in `defaults/dashify.toml`.
|
|
225
|
+
|
|
226
|
+
## Licence
|
|
227
|
+
|
|
228
|
+
Dashify is released under the MIT Licence. See `LICENSE`.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# The root layout has a timer and todos on the left. The right column nests a
|
|
2
|
+
# clock and system monitor beside a stopwatch, above the weather widget.
|
|
3
|
+
[widgets]
|
|
4
|
+
kind = "Hbox"
|
|
5
|
+
|
|
6
|
+
[widgets.left]
|
|
7
|
+
kind = "Vbox"
|
|
8
|
+
|
|
9
|
+
[widgets.right]
|
|
10
|
+
kind = "Vbox"
|
|
11
|
+
|
|
12
|
+
# A countdown timer. Click the digits while stopped, enter up to six digits in
|
|
13
|
+
# HHMMSS order, then press Enter to confirm the duration.
|
|
14
|
+
[widgets.left.timer]
|
|
15
|
+
kind = "Timer"
|
|
16
|
+
|
|
17
|
+
# Persistent local todos. Select Manage todos in the widget to create and use
|
|
18
|
+
# the SQLite database at ~/.local/state/dashify/todo.db.
|
|
19
|
+
[widgets.left.todo]
|
|
20
|
+
kind = "Todo"
|
|
21
|
+
|
|
22
|
+
# A vertical custom arrangement. Widget defaults remain in the app; uncomment
|
|
23
|
+
# switches and text below to enable them in this one-layer custom widget.
|
|
24
|
+
# [widgets.left.custom]
|
|
25
|
+
# kind = "Custom"
|
|
26
|
+
# opts = { text = "Focus time", clock = true, timezone = "Australia/Sydney", timer = true, stopwatch = true, system_monitor = true, todo = true, weather = true }
|
|
27
|
+
|
|
28
|
+
# The right column's top tile places the clock and system monitor in one
|
|
29
|
+
# vertical tile beside the stopwatch.
|
|
30
|
+
[widgets.right.top]
|
|
31
|
+
kind = "Hbox"
|
|
32
|
+
|
|
33
|
+
# Widget defaults are supplied by the app. Uncomment opts below to override the
|
|
34
|
+
# Clock's local timezone with "UTC", a UTC offset, or an IANA timezone name.
|
|
35
|
+
[widgets.right.top.status]
|
|
36
|
+
kind = "Vbox"
|
|
37
|
+
|
|
38
|
+
[widgets.right.top.status.clock]
|
|
39
|
+
kind = "Clock"
|
|
40
|
+
# opts = { timezone = "UTC+0" }
|
|
41
|
+
|
|
42
|
+
# A live CPU utilisation monitor. The graph retains the latest 38 samples,
|
|
43
|
+
# updates once per second, and marks low, medium, and high load in green,
|
|
44
|
+
# yellow, and red respectively.
|
|
45
|
+
[widgets.right.top.status.system_monitor]
|
|
46
|
+
kind = "SystemMonitor"
|
|
47
|
+
|
|
48
|
+
# A stopwatch with Start, Stop, and Reset controls. It has no options yet.
|
|
49
|
+
[widgets.right.top.stopwatch]
|
|
50
|
+
kind = "Stopwatch"
|
|
51
|
+
|
|
52
|
+
# Current weather for the app-supplied default location. Use inline opts to
|
|
53
|
+
# override location, units (metric or imperial), or refresh_minutes.
|
|
54
|
+
[widgets.right.weather]
|
|
55
|
+
kind = "Weather"
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "Dashify"
|
|
3
|
+
description = "A configurable terminal dashboard built with Textual."
|
|
4
|
+
version = "0.1.0"
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "Icecreambobcat",email = "icekingrex123@gmail.com"}
|
|
7
|
+
]
|
|
8
|
+
license = "MIT"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.14,<3.16"
|
|
11
|
+
keywords = ["dashboard", "terminal", "textual", "tui"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Environment :: Console",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Topic :: Utilities",
|
|
17
|
+
]
|
|
18
|
+
dependencies = [
|
|
19
|
+
"textual (>=7.5.0,<8.0.0)",
|
|
20
|
+
"tomlkit (>=0.15.0,<0.16.0)",
|
|
21
|
+
"pydantic (>=2.13.4,<3.0.0)",
|
|
22
|
+
"psutil (>=7.2.2,<8.0.0)"
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
[project.urls]
|
|
26
|
+
Repository = "https://github.com/Icecreambobcat/dashify"
|
|
27
|
+
Issues = "https://github.com/Icecreambobcat/dashify/issues"
|
|
28
|
+
|
|
29
|
+
[build-system]
|
|
30
|
+
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
|
31
|
+
build-backend = "poetry.core.masonry.api"
|
|
32
|
+
|
|
33
|
+
[dependency-groups]
|
|
34
|
+
dev = [
|
|
35
|
+
"pytest (>=9.1.1,<10.0.0)",
|
|
36
|
+
"pyinstaller (>=6.22.2,<7.0.0)",
|
|
37
|
+
"pyright (>=1.1.411,<2.0.0)",
|
|
38
|
+
"black (>=26.5.1,<27.0.0)"
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
[project.scripts]
|
|
42
|
+
dashify = "main:main"
|
|
43
|
+
|
|
44
|
+
[tool.poetry]
|
|
45
|
+
packages = [
|
|
46
|
+
{ include = "main.py", from = "src" },
|
|
47
|
+
{ include = "modules", from = "src" },
|
|
48
|
+
]
|
|
49
|
+
include = [
|
|
50
|
+
{ path = "defaults/dashify.toml", format = ["sdist", "wheel"] },
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[tool.black]
|
|
54
|
+
target-version = ["py314"]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
from modules.app import Dashify
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def main() -> int:
|
|
7
|
+
"""Run Dashify and return a process-compatible exit code."""
|
|
8
|
+
exit_code = Dashify().run()
|
|
9
|
+
return int(exit_code) if exit_code is not None else 0
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
if __name__ == "__main__":
|
|
13
|
+
sys.exit(main())
|
|
File without changes
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from textual.app import App, ComposeResult
|
|
2
|
+
from textual.binding import Binding
|
|
3
|
+
from textual.containers import Container
|
|
4
|
+
from textual.widgets import Footer, Header, Static
|
|
5
|
+
|
|
6
|
+
from modules.composer import compose_from_config
|
|
7
|
+
from modules.conf import make_config
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class Dashify(App):
|
|
11
|
+
"""Compose and run the configured terminal dashboard."""
|
|
12
|
+
|
|
13
|
+
TITLE = "Dashify"
|
|
14
|
+
BINDINGS = [Binding("ctrl+q", "quit", "Quit", key_display="^q")]
|
|
15
|
+
|
|
16
|
+
DEFAULT_CSS = """
|
|
17
|
+
#config-warning-screen {
|
|
18
|
+
width: 1fr;
|
|
19
|
+
height: 1fr;
|
|
20
|
+
align: center middle;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#config-warning {
|
|
24
|
+
width: 50;
|
|
25
|
+
height: 5;
|
|
26
|
+
border: round $warning;
|
|
27
|
+
padding: 1;
|
|
28
|
+
color: $warning;
|
|
29
|
+
content-align: center middle;
|
|
30
|
+
text-align: center;
|
|
31
|
+
}
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
def compose(self) -> ComposeResult:
|
|
35
|
+
"""Compose the configured layout or a recoverable warning screen."""
|
|
36
|
+
yield Header()
|
|
37
|
+
config = make_config()
|
|
38
|
+
if config is not None and (layout := compose_from_config(config)) is not None:
|
|
39
|
+
yield layout
|
|
40
|
+
else:
|
|
41
|
+
with Container(id="config-warning-screen"):
|
|
42
|
+
yield Static(
|
|
43
|
+
"Configuration could not be loaded.\n"
|
|
44
|
+
"Check dashify.toml and restart.",
|
|
45
|
+
id="config-warning",
|
|
46
|
+
)
|
|
47
|
+
yield Footer()
|