qtimetrap 0.1.1

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.
Files changed (130) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +25 -0
  3. data/README.md +92 -0
  4. data/Rakefile +105 -0
  5. data/app/assets/icons/qtimetrap-icon-128.png +0 -0
  6. data/app/assets/icons/qtimetrap-icon-256.png +0 -0
  7. data/app/assets/icons/qtimetrap-icon-512.png +0 -0
  8. data/app/assets/icons/qtimetrap-icon.svg +123 -0
  9. data/app/components/entries/branch_hierarchy_helpers.rb +41 -0
  10. data/app/components/entries/leaf_archive_helpers.rb +23 -0
  11. data/app/components/entries/leaf_note_helpers.rb +118 -0
  12. data/app/components/entries/leaf_task_helpers.rb +81 -0
  13. data/app/components/entries/leaf_time_helpers.rb +105 -0
  14. data/app/components/entries/list_component.rb +118 -0
  15. data/app/components/entries/list_host_helpers.rb +27 -0
  16. data/app/components/entries/list_state_helpers.rb +59 -0
  17. data/app/components/entries/node_presentation_helpers.rb +29 -0
  18. data/app/components/entries/render_helpers.rb +25 -0
  19. data/app/components/entries/tree_helpers.rb +133 -0
  20. data/app/components/entries/tree_toolbar_helpers.rb +98 -0
  21. data/app/components/project_sidebar/archive_toggle_helpers.rb +22 -0
  22. data/app/components/project_sidebar/component.rb +125 -0
  23. data/app/components/project_sidebar/logo_helpers.rb +53 -0
  24. data/app/components/project_sidebar/project_button_helpers.rb +72 -0
  25. data/app/components/project_sidebar/project_selection_helpers.rb +94 -0
  26. data/app/components/project_sidebar/task_helpers.rb +94 -0
  27. data/app/components/project_sidebar/task_selection_helpers.rb +72 -0
  28. data/app/components/qt_ui_helpers.rb +27 -0
  29. data/app/components/tracker_controls/component.rb +80 -0
  30. data/app/components/tracker_controls/layout_builder.rb +100 -0
  31. data/app/components/tracker_controls/layout_helpers.rb +88 -0
  32. data/app/models/null_settings_store.rb +12 -0
  33. data/app/models/time_entry.rb +59 -0
  34. data/app/services/archived_entries_store.rb +71 -0
  35. data/app/services/formatters.rb +29 -0
  36. data/app/services/settings_store.rb +83 -0
  37. data/app/services/timetrap_gateway.rb +89 -0
  38. data/app/services/timetrap_gateway_logger.rb +54 -0
  39. data/app/services/timetrap_gateway_query_helpers.rb +102 -0
  40. data/app/services/timetrap_gateway_start_helpers.rb +28 -0
  41. data/app/services/timetrap_gateway_update_note_helpers.rb +48 -0
  42. data/app/services/timetrap_gateway_update_task_helpers.rb +47 -0
  43. data/app/services/timetrap_gateway_update_time_helpers.rb +50 -0
  44. data/app/styles/theme.rb +61 -0
  45. data/app/styles/themes/dark/application.qss +8 -0
  46. data/app/styles/themes/dark/entries_list.qss +235 -0
  47. data/app/styles/themes/dark/project_sidebar.qss +99 -0
  48. data/app/styles/themes/dark/snippets/app_background.qss +2 -0
  49. data/app/styles/themes/dark/snippets/button_ghost.qss +5 -0
  50. data/app/styles/themes/dark/snippets/button_start.qss +5 -0
  51. data/app/styles/themes/dark/snippets/button_stop.qss +5 -0
  52. data/app/styles/themes/dark/snippets/entries_host.qss +2 -0
  53. data/app/styles/themes/dark/snippets/entries_scroll.qss +16 -0
  54. data/app/styles/themes/dark/snippets/entry_row_day.qss +6 -0
  55. data/app/styles/themes/dark/snippets/entry_row_detail.qss +5 -0
  56. data/app/styles/themes/dark/snippets/entry_row_project.qss +6 -0
  57. data/app/styles/themes/dark/snippets/project_button.qss +5 -0
  58. data/app/styles/themes/dark/snippets/project_button_active.qss +5 -0
  59. data/app/styles/themes/dark/snippets/project_sidebar_heading.qss +2 -0
  60. data/app/styles/themes/dark/snippets/project_sidebar_logo.qss +3 -0
  61. data/app/styles/themes/dark/snippets/project_sidebar_panel.qss +2 -0
  62. data/app/styles/themes/dark/snippets/tracker_clock.qss +2 -0
  63. data/app/styles/themes/dark/snippets/tracker_input.qss +5 -0
  64. data/app/styles/themes/dark/snippets/tracker_project_label.qss +5 -0
  65. data/app/styles/themes/dark/snippets/tracker_row.qss +3 -0
  66. data/app/styles/themes/dark/snippets/tracker_summary.qss +3 -0
  67. data/app/styles/themes/dark/snippets/tracker_timer.qss +3 -0
  68. data/app/styles/themes/dark/snippets/tracker_title.qss +3 -0
  69. data/app/styles/themes/dark/snippets/tracker_topbar.qss +2 -0
  70. data/app/styles/themes/dark/tracker_controls.qss +84 -0
  71. data/app/styles/themes/light/application.qss +8 -0
  72. data/app/styles/themes/light/entries_list.qss +235 -0
  73. data/app/styles/themes/light/project_sidebar.qss +99 -0
  74. data/app/styles/themes/light/snippets/app_background.qss +2 -0
  75. data/app/styles/themes/light/snippets/button_ghost.qss +5 -0
  76. data/app/styles/themes/light/snippets/button_start.qss +5 -0
  77. data/app/styles/themes/light/snippets/button_stop.qss +5 -0
  78. data/app/styles/themes/light/snippets/entries_host.qss +2 -0
  79. data/app/styles/themes/light/snippets/entries_scroll.qss +16 -0
  80. data/app/styles/themes/light/snippets/entry_row_day.qss +6 -0
  81. data/app/styles/themes/light/snippets/entry_row_detail.qss +5 -0
  82. data/app/styles/themes/light/snippets/entry_row_project.qss +6 -0
  83. data/app/styles/themes/light/snippets/project_button.qss +5 -0
  84. data/app/styles/themes/light/snippets/project_button_active.qss +5 -0
  85. data/app/styles/themes/light/snippets/project_sidebar_heading.qss +2 -0
  86. data/app/styles/themes/light/snippets/project_sidebar_logo.qss +3 -0
  87. data/app/styles/themes/light/snippets/project_sidebar_panel.qss +2 -0
  88. data/app/styles/themes/light/snippets/tracker_clock.qss +2 -0
  89. data/app/styles/themes/light/snippets/tracker_input.qss +5 -0
  90. data/app/styles/themes/light/snippets/tracker_project_label.qss +5 -0
  91. data/app/styles/themes/light/snippets/tracker_row.qss +3 -0
  92. data/app/styles/themes/light/snippets/tracker_summary.qss +3 -0
  93. data/app/styles/themes/light/snippets/tracker_timer.qss +3 -0
  94. data/app/styles/themes/light/snippets/tracker_title.qss +3 -0
  95. data/app/styles/themes/light/snippets/tracker_topbar.qss +2 -0
  96. data/app/styles/themes/light/tracker_controls.qss +84 -0
  97. data/app/view_models/entry_nodes_builder.rb +109 -0
  98. data/app/view_models/main_view_model.rb +135 -0
  99. data/app/view_models/main_view_model_archive_mode_helpers.rb +102 -0
  100. data/app/view_models/main_view_model_entry_note_helpers.rb +30 -0
  101. data/app/view_models/main_view_model_entry_task_helpers.rb +39 -0
  102. data/app/view_models/main_view_model_entry_time_helpers.rb +45 -0
  103. data/app/view_models/main_view_model_sheet_helpers.rb +74 -0
  104. data/app/view_models/main_view_model_task_filter_helpers.rb +58 -0
  105. data/app/view_models/main_view_model_time_range_filter_helpers.rb +23 -0
  106. data/app/views/main_window.rb +126 -0
  107. data/app/views/main_window_layout_builder.rb +114 -0
  108. data/app/views/main_window_runtime.rb +123 -0
  109. data/app/views/main_window_runtime_archive_helpers.rb +26 -0
  110. data/app/views/main_window_runtime_entry_task_helpers.rb +21 -0
  111. data/app/views/main_window_runtime_entry_time_helpers.rb +17 -0
  112. data/app/views/main_window_runtime_key_helpers.rb +55 -0
  113. data/app/views/main_window_runtime_render_helpers.rb +50 -0
  114. data/app/views/main_window_splitter_toggle_bootstrap_helpers.rb +34 -0
  115. data/app/views/main_window_splitter_toggle_helpers.rb +103 -0
  116. data/app/views/main_window_splitter_toggle_hover_helpers.rb +71 -0
  117. data/app/views/main_window_splitter_toggle_layout_helpers.rb +24 -0
  118. data/app/views/main_window_ui_helpers.rb +45 -0
  119. data/app/views/window_icon_loader.rb +37 -0
  120. data/bin/qtimetrap +7 -0
  121. data/config/application.rb +87 -0
  122. data/config/environments/development.rb +5 -0
  123. data/config/environments/production.rb +5 -0
  124. data/config/initializers/theme.rb +5 -0
  125. data/config/initializers/timetrap.rb +5 -0
  126. data/lib/qtimetrap/configuration.rb +15 -0
  127. data/lib/qtimetrap/container.rb +57 -0
  128. data/lib/qtimetrap/version.rb +5 -0
  129. data/lib/qtimetrap.rb +25 -0
  130. metadata +207 -0
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QTimetrap
4
+ module Services
5
+ # Shared start workflow for Timetrap API/CLI adapters.
6
+ module TimetrapGatewayStartHelpers
7
+ private
8
+
9
+ def normalize_start_inputs(sheet, checkin_note)
10
+ [normalize_text(sheet).strip, normalize_text(checkin_note).strip]
11
+ end
12
+
13
+ def start_via_api(sheet, checkin_note)
14
+ Timetrap::Timer.current_sheet = sheet
15
+ Timetrap::Timer.start(checkin_note)
16
+ end
17
+
18
+ def start_via_cli(sheet, checkin_note)
19
+ sheet_ok, = run('sheet', sheet)
20
+ return unless sheet_ok
21
+
22
+ return run('in') if checkin_note.empty?
23
+
24
+ run('in', checkin_note)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QTimetrap
4
+ module Services
5
+ # Note update workflow for Timetrap API/CLI adapters.
6
+ module TimetrapGatewayUpdateNoteHelpers
7
+ def update_note(entry_id, note)
8
+ normalized_id = entry_id.to_i
9
+ normalized_note = normalize_text(note).strip
10
+ return if normalized_id.zero?
11
+
12
+ if api_available?
13
+ logger.log_api(
14
+ operation: 'update_note',
15
+ input: { entry_id: normalized_id, note: normalized_note },
16
+ output: 'requested'
17
+ )
18
+ result = update_note_via_api(normalized_id, normalized_note)
19
+ logger.log_api(operation: 'update_note', input: {}, output: result.to_s)
20
+ return result
21
+ end
22
+
23
+ update_note_via_cli(normalized_id, normalized_note)
24
+ end
25
+
26
+ private
27
+
28
+ def update_note_via_api(entry_id, note)
29
+ entry = resolve_entry_for_note_update(Timetrap::Entry[entry_id])
30
+ entry.note = note
31
+ entry.save
32
+ end
33
+
34
+ def update_note_via_cli(entry_id, note)
35
+ return run('edit', '--id', entry_id.to_s, '--clear') if note.empty?
36
+
37
+ run('edit', '--id', entry_id.to_s, note)
38
+ end
39
+
40
+ def resolve_entry_for_note_update(value)
41
+ entry = value
42
+ raise TypeError, "Unsupported entry lookup result: #{value.class}" unless entry
43
+
44
+ entry
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QTimetrap
4
+ module Services
5
+ # Task/sheet move workflow for Timetrap API/CLI adapters.
6
+ module TimetrapGatewayUpdateTaskHelpers
7
+ def update_task(entry_id, sheet)
8
+ normalized_id = entry_id.to_i
9
+ normalized_sheet = normalize_text(sheet).strip
10
+ return if normalized_id.zero?
11
+
12
+ validate_target_sheet!(normalized_sheet)
13
+ return update_task_via_api_logged(normalized_id, normalized_sheet) if api_available?
14
+
15
+ update_task_via_cli(normalized_id, normalized_sheet)
16
+ end
17
+
18
+ private
19
+
20
+ def validate_target_sheet!(sheet)
21
+ raise ArgumentError, 'Sheet is required' if sheet.empty?
22
+ end
23
+
24
+ def update_task_via_api_logged(entry_id, sheet)
25
+ logger.log_api(
26
+ operation: 'update_task',
27
+ input: { entry_id: entry_id, sheet: sheet },
28
+ output: 'requested'
29
+ )
30
+ result = update_task_via_api(entry_id, sheet)
31
+ logger.log_api(operation: 'update_task', input: {}, output: result.to_s)
32
+ result
33
+ end
34
+
35
+ def update_task_via_api(entry_id, sheet)
36
+ entry = resolve_entry_for_note_update(Timetrap::Entry[entry_id])
37
+ active_entry = Timetrap::Timer.active_entry
38
+ Timetrap::Timer.current_sheet = sheet if active_entry&.id.to_i == entry.id.to_i
39
+ entry.update(sheet: sheet)
40
+ end
41
+
42
+ def update_task_via_cli(entry_id, sheet)
43
+ run('edit', '--id', entry_id.to_s, '--move', sheet)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QTimetrap
4
+ module Services
5
+ # Time bounds update workflow for Timetrap API/CLI adapters.
6
+ module TimetrapGatewayUpdateTimeHelpers
7
+ def update_time(entry_id, start_time:, end_time:)
8
+ normalized_id = entry_id.to_i
9
+ return if normalized_id.zero?
10
+
11
+ if api_available?
12
+ logger.log_api(
13
+ operation: 'update_time',
14
+ input: {
15
+ entry_id: normalized_id,
16
+ start_time: start_time&.iso8601,
17
+ end_time: end_time&.iso8601
18
+ },
19
+ output: 'requested'
20
+ )
21
+ result = update_time_via_api(normalized_id, start_time: start_time, end_time: end_time)
22
+ logger.log_api(operation: 'update_time', input: {}, output: result.to_s)
23
+ return result
24
+ end
25
+
26
+ update_time_via_cli(normalized_id, start_time: start_time, end_time: end_time)
27
+ end
28
+
29
+ private
30
+
31
+ def update_time_via_api(entry_id, start_time:, end_time:)
32
+ entry = resolve_entry_for_note_update(Timetrap::Entry[entry_id])
33
+ entry.start = start_time if start_time
34
+ entry.end = end_time if end_time
35
+ entry.save
36
+ end
37
+
38
+ def update_time_via_cli(entry_id, start_time:, end_time:)
39
+ args = ['edit', '--id', entry_id.to_s]
40
+ args += ['--start', format_cli_timestamp(start_time)] if start_time
41
+ args += ['--end', format_cli_timestamp(end_time)] if end_time
42
+ run(*args)
43
+ end
44
+
45
+ def format_cli_timestamp(time)
46
+ time.strftime('%Y-%m-%d %H:%M:%S %z')
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QTimetrap
4
+ module Styles
5
+ # Loads and composes QSS theme assets for the application.
6
+ class Theme
7
+ FILES = %w[application project_sidebar tracker_controls entries_list].freeze
8
+ DEFAULT = 'light'
9
+ SUPPORTED = %w[light dark].freeze
10
+
11
+ def initialize(name:, root:)
12
+ @name = normalize_name(name)
13
+ @root = root
14
+ @cache = {}
15
+ end
16
+
17
+ attr_reader :name, :root
18
+
19
+ def application_stylesheet
20
+ FILES.map { |file| stylesheet(file) }.join("\n")
21
+ end
22
+
23
+ def with_name(next_name)
24
+ self.class.new(name: next_name, root: root)
25
+ end
26
+
27
+ def snippet(snippet_name)
28
+ File.read(path_for_snippet(snippet_name))
29
+ end
30
+
31
+ def stylesheet(file_name)
32
+ cache.fetch(file_name) do
33
+ cache[file_name] = File.read(path_for(file_name))
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :cache
40
+
41
+ def path_for(file_name)
42
+ path = File.join(root, 'app', 'styles', 'themes', name, "#{file_name}.qss")
43
+ return path if File.exist?(path)
44
+
45
+ File.join(root, 'app', 'styles', 'themes', DEFAULT, "#{file_name}.qss")
46
+ end
47
+
48
+ def path_for_snippet(snippet_name)
49
+ path = File.join(root, 'app', 'styles', 'themes', name, 'snippets', "#{snippet_name}.qss")
50
+ return path if File.exist?(path)
51
+
52
+ File.join(root, 'app', 'styles', 'themes', DEFAULT, 'snippets', "#{snippet_name}.qss")
53
+ end
54
+
55
+ def normalize_name(value)
56
+ candidate = value.to_s.strip.downcase
57
+ SUPPORTED.include?(candidate) ? candidate : DEFAULT
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,8 @@
1
+ QWidget#main_window {
2
+ background-color: #0f172a;
3
+ }
4
+
5
+ QLabel#app_background {
6
+ background-color: #0b1220;
7
+ border: 1px solid #243244;
8
+ }
@@ -0,0 +1,235 @@
1
+ QScrollArea#entries_scroll {
2
+ background-color: #111827;
3
+ border: 1px solid #2b3b4f;
4
+ border-radius: 10px;
5
+ }
6
+
7
+ QScrollArea#entries_scroll QScrollBar:vertical {
8
+ background: #0f172a;
9
+ width: 12px;
10
+ margin: 2px;
11
+ border: 1px solid #334155;
12
+ border-radius: 6px;
13
+ }
14
+
15
+ QScrollArea#entries_scroll QScrollBar::handle:vertical {
16
+ background: #475569;
17
+ min-height: 28px;
18
+ border-radius: 5px;
19
+ }
20
+
21
+ QWidget#entries_host {
22
+ background-color: #0f172a;
23
+ border: 0px;
24
+ }
25
+
26
+ QWidget#entries_toolbar {
27
+ background-color: #0f172a;
28
+ border: 0px;
29
+ }
30
+
31
+ QPushButton#entries_expand_all,
32
+ QPushButton#entries_collapse_all {
33
+ background-color: #111827;
34
+ border: 1px solid #334155;
35
+ border-radius: 8px;
36
+ color: #cbd5e1;
37
+ font-size: 12px;
38
+ font-weight: 700;
39
+ }
40
+
41
+ QCheckBox#entries_time_filter_from_toggle,
42
+ QCheckBox#entries_time_filter_to_toggle {
43
+ background-color: #111827;
44
+ border: 1px solid #334155;
45
+ border-radius: 8px;
46
+ color: #cbd5e1;
47
+ font-size: 12px;
48
+ font-weight: 700;
49
+ }
50
+
51
+ QCheckBox#entries_time_filter_from_toggle:checked,
52
+ QCheckBox#entries_time_filter_to_toggle:checked {
53
+ background-color: #1e3a8a;
54
+ border: 1px solid #2563eb;
55
+ }
56
+
57
+ QDateTimeEdit#entries_time_filter_from,
58
+ QDateTimeEdit#entries_time_filter_to {
59
+ background-color: #111827;
60
+ border: 1px solid #334155;
61
+ border-radius: 8px;
62
+ color: #cbd5e1;
63
+ font-size: 12px;
64
+ padding-left: 4px;
65
+ }
66
+
67
+ QPushButton#entry_node_week {
68
+ background-color: #21346A;
69
+ border: 1px solid #101A39;
70
+ border-radius: 8px;
71
+ color: #dbeafe;
72
+ font-size: 15px;
73
+ font-weight: 800;
74
+ text-align: left;
75
+ padding-left: 8px;
76
+ }
77
+
78
+ QPushButton#entry_node_week:hover {
79
+ background-color: #1e40af;
80
+ }
81
+
82
+ QPushButton#entry_node_week:pressed {
83
+ background-color: #1e3a8a;
84
+ }
85
+
86
+ QPushButton#entry_node_week:focus {
87
+ border: 2px solid #7dd3fc;
88
+ }
89
+
90
+ QPushButton#entry_node_day {
91
+ background-color: #1f2937;
92
+ border: 1px solid #334155;
93
+ border-radius: 8px;
94
+ color: #cbd5e1;
95
+ font-size: 14px;
96
+ font-weight: 700;
97
+ text-align: left;
98
+ padding-left: 8px;
99
+ }
100
+
101
+ QPushButton#entry_node_day:hover {
102
+ background-color: #243244;
103
+ }
104
+
105
+ QPushButton#entry_node_day:pressed {
106
+ background-color: #1e293b;
107
+ }
108
+
109
+ QPushButton#entry_node_day:focus {
110
+ border: 2px solid #7dd3fc;
111
+ }
112
+
113
+ QPushButton#entry_node_project {
114
+ background-color: #111827;
115
+ border: 1px solid #334155;
116
+ border-radius: 8px;
117
+ color: #e2e8f0;
118
+ font-size: 13px;
119
+ font-weight: 700;
120
+ text-align: left;
121
+ padding-left: 8px;
122
+ }
123
+
124
+ QPushButton#entry_node_project:hover {
125
+ background-color: #0b1220;
126
+ }
127
+
128
+ QPushButton#entry_node_project:pressed {
129
+ background-color: #020617;
130
+ }
131
+
132
+ QPushButton#entry_node_project:focus {
133
+ border: 2px solid #38bdf8;
134
+ }
135
+
136
+ QWidget#entry_node_entry_row {
137
+ background-color: #0b1220;
138
+ border: 1px solid #243244;
139
+ border-radius: 8px;
140
+ }
141
+
142
+ QLabel#entry_node_entry_prefix {
143
+ color: #94a3b8;
144
+ font-size: 12px;
145
+ }
146
+
147
+ QLabel#entry_node_entry_time_sep {
148
+ color: #94a3b8;
149
+ font-size: 12px;
150
+ }
151
+
152
+ QLineEdit#entry_node_entry_start,
153
+ QLineEdit#entry_node_entry_end {
154
+ color: #94a3b8;
155
+ font-size: 12px;
156
+ background: transparent;
157
+ border: 0px;
158
+ }
159
+
160
+ QLineEdit#entry_node_entry_start:read-only,
161
+ QLineEdit#entry_node_entry_end:read-only {
162
+ background: transparent;
163
+ border: 0px;
164
+ }
165
+
166
+ QLineEdit#entry_node_entry_start:focus,
167
+ QLineEdit#entry_node_entry_end:focus {
168
+ background-color: #111827;
169
+ border: 1px solid #334155;
170
+ border-radius: 6px;
171
+ }
172
+
173
+ QLineEdit#entry_node_entry_note {
174
+ color: #94a3b8;
175
+ font-size: 12px;
176
+ background: transparent;
177
+ border: 0px;
178
+ padding-left: 2px;
179
+ }
180
+
181
+ QLineEdit#entry_node_entry_note:read-only {
182
+ background: transparent;
183
+ border: 0px;
184
+ }
185
+
186
+ QLineEdit#entry_node_entry_note:focus {
187
+ background-color: #111827;
188
+ border: 1px solid #334155;
189
+ border-radius: 6px;
190
+ padding-left: 6px;
191
+ }
192
+
193
+ QComboBox#entry_node_entry_task {
194
+ color: #94a3b8;
195
+ font-size: 12px;
196
+ background: transparent;
197
+ border: 0px;
198
+ padding-left: 2px;
199
+ }
200
+
201
+ QComboBox#entry_node_entry_task:focus {
202
+ background-color: #111827;
203
+ border: 1px solid #334155;
204
+ border-radius: 6px;
205
+ }
206
+
207
+ QComboBox#entry_node_entry_task QAbstractItemView {
208
+ background-color: #111827;
209
+ color: #e2e8f0;
210
+ border: 1px solid #334155;
211
+ selection-background-color: #1d4ed8;
212
+ selection-color: #f8fafc;
213
+ }
214
+
215
+ QPushButton#entry_node_entry_archive {
216
+ background-color: #111827;
217
+ border: 1px solid #334155;
218
+ border-radius: 6px;
219
+ color: #94a3b8;
220
+ font-size: 12px;
221
+ font-weight: 700;
222
+ }
223
+
224
+ QPushButton#entry_node_entry_archive:hover {
225
+ background-color: #0b1220;
226
+ }
227
+
228
+ QLabel#entry_node_empty {
229
+ background-color: #0f172a;
230
+ border: 1px solid #243244;
231
+ border-radius: 8px;
232
+ color: #94a3b8;
233
+ font-size: 12px;
234
+ padding-left: 8px;
235
+ }
@@ -0,0 +1,99 @@
1
+ QWidget#sidebar_panel {
2
+ background-color: #111827;
3
+ border-right: 1px solid #2b3b4f;
4
+ border-top-right-radius: 10px;
5
+ border-bottom-right-radius: 10px;
6
+ }
7
+
8
+ QWidget#sidebar_logo {
9
+ background-color: transparent;
10
+ }
11
+
12
+ QLabel#sidebar_logo_text {
13
+ color: #e5e7eb;
14
+ font-size: 18px;
15
+ font-weight: 800;
16
+ }
17
+
18
+ QLabel#sidebar_heading {
19
+ color: #9ca3af;
20
+ font-size: 12px;
21
+ }
22
+
23
+ QLabel#sidebar_tasks_heading {
24
+ color: #94a3b8;
25
+ font-size: 11px;
26
+ margin-top: 8px;
27
+ }
28
+
29
+ QPushButton#project_button {
30
+ background-color: #0f172a;
31
+ border: 1px solid #334155;
32
+ border-radius: 8px;
33
+ color: #cbd5e1;
34
+ font-size: 12px;
35
+ font-weight: 700;
36
+ text-align: left;
37
+ padding-left: 10px;
38
+ }
39
+
40
+ QPushButton#project_button:checked {
41
+ background-color: #1e293b;
42
+ border: 2px solid #38bdf8;
43
+ color: #f8fafc;
44
+ font-weight: 800;
45
+ }
46
+
47
+ QPushButton#project_button:disabled {
48
+ color: #64748b;
49
+ }
50
+
51
+ QPushButton#task_button {
52
+ background-color: #111827;
53
+ border: 1px solid #334155;
54
+ border-radius: 8px;
55
+ color: #cbd5e1;
56
+ font-size: 11px;
57
+ text-align: left;
58
+ padding-left: 10px;
59
+ }
60
+
61
+ QPushButton#task_button:checked {
62
+ background-color: #1f2937;
63
+ border: 2px solid #38bdf8;
64
+ color: #f8fafc;
65
+ }
66
+
67
+ QPushButton#sidebar_toggle_button {
68
+ background-color: #0f172a;
69
+ border: 1px solid #334155;
70
+ border-radius: 8px;
71
+ color: #93c5fd;
72
+ font-size: 13px;
73
+ font-weight: 700;
74
+ }
75
+
76
+ QPushButton#sidebar_toggle_button:hover {
77
+ background-color: #111827;
78
+ border: 1px solid #38bdf8;
79
+ }
80
+
81
+ QPushButton#sidebar_archive_toggle {
82
+ background-color: #0b1220;
83
+ border: 1px solid #334155;
84
+ border-radius: 8px;
85
+ color: #94a3b8;
86
+ font-size: 16px;
87
+ font-weight: 700;
88
+ }
89
+
90
+ QPushButton#sidebar_archive_toggle:hover {
91
+ border: 1px solid #f59e0b;
92
+ color: #fbbf24;
93
+ }
94
+
95
+ QPushButton#sidebar_archive_toggle:checked {
96
+ background-color: #3b2f14;
97
+ border: 2px solid #f59e0b;
98
+ color: #fde68a;
99
+ }
@@ -0,0 +1,2 @@
1
+ background-color: #0b1220;
2
+ border: 1px solid #243244;
@@ -0,0 +1,5 @@
1
+ background-color: #111827;
2
+ border: 1px solid #334155;
3
+ color: #cbd5e1;
4
+ font-size: 13px;
5
+ font-weight: 700;
@@ -0,0 +1,5 @@
1
+ background-color: #0ea5e9;
2
+ border: 1px solid #0284c7;
3
+ color: #ffffff;
4
+ font-size: 14px;
5
+ font-weight: 800;
@@ -0,0 +1,5 @@
1
+ background-color: #ef4444;
2
+ border: 1px solid #dc2626;
3
+ color: #ffffff;
4
+ font-size: 14px;
5
+ font-weight: 800;
@@ -0,0 +1,2 @@
1
+ background-color: #0f172a;
2
+ border: 0px;
@@ -0,0 +1,16 @@
1
+ QScrollArea {
2
+ background-color: #111827;
3
+ border: 1px solid #2b3b4f;
4
+ }
5
+ QScrollBar:vertical {
6
+ background: #0f172a;
7
+ width: 12px;
8
+ margin: 2px;
9
+ border: 1px solid #334155;
10
+ border-radius: 6px;
11
+ }
12
+ QScrollBar::handle:vertical {
13
+ background: #475569;
14
+ min-height: 28px;
15
+ border-radius: 5px;
16
+ }
@@ -0,0 +1,6 @@
1
+ background-color: #1f2937;
2
+ border: 1px solid #334155;
3
+ color: #cbd5e1;
4
+ font-size: 13px;
5
+ font-weight: 700;
6
+ padding-left: 12px;
@@ -0,0 +1,5 @@
1
+ background-color: #0b1220;
2
+ border: 1px solid #243244;
3
+ color: #94a3b8;
4
+ font-size: 12px;
5
+ padding-left: 24px;
@@ -0,0 +1,6 @@
1
+ background-color: #111827;
2
+ border: 1px solid #334155;
3
+ color: #e2e8f0;
4
+ font-size: 14px;
5
+ font-weight: 700;
6
+ padding-left: 12px;
@@ -0,0 +1,5 @@
1
+ background-color: #0f172a;
2
+ border: 1px solid #334155;
3
+ color: #cbd5e1;
4
+ font-size: 12px;
5
+ font-weight: 700;
@@ -0,0 +1,5 @@
1
+ background-color: #1e293b;
2
+ border: 2px solid #38bdf8;
3
+ color: #f8fafc;
4
+ font-size: 12px;
5
+ font-weight: 800;
@@ -0,0 +1,2 @@
1
+ color: #9ca3af;
2
+ font-size: 12px;
@@ -0,0 +1,3 @@
1
+ color: #e5e7eb;
2
+ font-size: 18px;
3
+ font-weight: 800;
@@ -0,0 +1,2 @@
1
+ background-color: #111827;
2
+ border-right: 1px solid #2b3b4f;
@@ -0,0 +1,2 @@
1
+ color: #9ca3af;
2
+ font-size: 12px;
@@ -0,0 +1,5 @@
1
+ background-color: #111827;
2
+ border: 1px solid #334155;
3
+ color: #e2e8f0;
4
+ font-size: 14px;
5
+ padding-left: 8px;
@@ -0,0 +1,5 @@
1
+ background-color: #111827;
2
+ border: 1px solid #334155;
3
+ color: #cbd5e1;
4
+ font-size: 13px;
5
+ font-weight: 700;
@@ -0,0 +1,3 @@
1
+ background-color: #0f172a;
2
+ border: 1px solid #2b3b4f;
3
+ color: #e2e8f0;