super-time-tracker-ui 0.1.2

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 (276) hide show
  1. package/AGENTS.md +5 -0
  2. package/CHANGELOG.md +28 -0
  3. package/CLAUDE.md +1 -0
  4. package/README.md +36 -0
  5. package/app/api/backup/route.ts +39 -0
  6. package/app/api/entry/delete-bulk/route.ts +53 -0
  7. package/app/api/entry/move/route.ts +46 -0
  8. package/app/api/entry/move-bulk/route.ts +62 -0
  9. package/app/api/entry/route.ts +75 -0
  10. package/app/api/in/route.ts +38 -0
  11. package/app/api/note/route.ts +120 -0
  12. package/app/api/out/route.ts +31 -0
  13. package/app/api/sheet/route.ts +68 -0
  14. package/app/api/state/route.ts +16 -0
  15. package/app/api/tags/route.ts +75 -0
  16. package/app/color-palettes.css +260 -0
  17. package/app/favicon.ico +0 -0
  18. package/app/globals.css +140 -0
  19. package/app/layout.tsx +54 -0
  20. package/app/page.tsx +24 -0
  21. package/app/reporting/page.tsx +11 -0
  22. package/app/settings/data/page.tsx +9 -0
  23. package/app/settings/display/page.tsx +8 -0
  24. package/app/settings/page.tsx +12 -0
  25. package/app/settings/tags/page.tsx +13 -0
  26. package/bin/stt-ui.js +63 -0
  27. package/components/active-entry-panel.tsx +199 -0
  28. package/components/backup-restore-setting.tsx +168 -0
  29. package/components/check-in-form-collapsed-setting.tsx +44 -0
  30. package/components/check-in-form-collapsible.tsx +52 -0
  31. package/components/check-in-form.tsx +89 -0
  32. package/components/checkbox.tsx +75 -0
  33. package/components/checkout-button-group.tsx +73 -0
  34. package/components/chevron-icon.tsx +25 -0
  35. package/components/clear-tag-filters-on-sheet-change-setting.tsx +45 -0
  36. package/components/color-palette-setting.tsx +75 -0
  37. package/components/compact-lists-setting.tsx +42 -0
  38. package/components/confirm-before-checkout-setting.tsx +42 -0
  39. package/components/confirm-destructive-actions-setting.tsx +46 -0
  40. package/components/confirm-dialog-provider.tsx +71 -0
  41. package/components/confirm-dialog.tsx +90 -0
  42. package/components/data-settings-view.tsx +47 -0
  43. package/components/default-reporting-range-setting.tsx +56 -0
  44. package/components/default-reporting-sort-setting.tsx +45 -0
  45. package/components/default-sheet-session-setting.tsx +118 -0
  46. package/components/display-settings-view.tsx +75 -0
  47. package/components/duration-format-setting.tsx +40 -0
  48. package/components/entry-actions-menu.tsx +207 -0
  49. package/components/entry-edit-form.tsx +113 -0
  50. package/components/entry-list-bulk-bar.tsx +128 -0
  51. package/components/entry-list-sort-setting.tsx +41 -0
  52. package/components/entry-list.tsx +336 -0
  53. package/components/entry-notes-list.tsx +211 -0
  54. package/components/entry-tag-filter.tsx +99 -0
  55. package/components/format_datetime_hint.ts +8 -0
  56. package/components/format_time.ts +10 -0
  57. package/components/general-settings-view.tsx +40 -0
  58. package/components/hamburger-icon.tsx +21 -0
  59. package/components/note-edit-form.tsx +77 -0
  60. package/components/note-form.tsx +109 -0
  61. package/components/pencil-icon.tsx +21 -0
  62. package/components/reporting-date-range-picker.tsx +121 -0
  63. package/components/reporting-sort-controls.tsx +53 -0
  64. package/components/reporting-view.tsx +340 -0
  65. package/components/setting-radio-group.tsx +79 -0
  66. package/components/settings-nav.tsx +66 -0
  67. package/components/settings-page-layout.tsx +53 -0
  68. package/components/settings-saved-toast.tsx +57 -0
  69. package/components/sheet-actions-menu.tsx +108 -0
  70. package/components/sheet-sidebar.tsx +196 -0
  71. package/components/tag-autocomplete-input.tsx +183 -0
  72. package/components/tag-filter-mode-setting.tsx +47 -0
  73. package/components/tag-management-view.tsx +290 -0
  74. package/components/theme-mode-setting.tsx +44 -0
  75. package/components/theme-mode-system-listener.tsx +43 -0
  76. package/components/theme_switcher.tsx +38 -0
  77. package/components/time-format-setting.tsx +39 -0
  78. package/components/timer-in-title-setting.tsx +38 -0
  79. package/components/timer-show-seconds-setting.tsx +41 -0
  80. package/components/tracker-active-bar.tsx +76 -0
  81. package/components/tracker-app.tsx +338 -0
  82. package/components/tracker-breadcrumb.tsx +56 -0
  83. package/components/tracker-document-title.tsx +67 -0
  84. package/components/tracker-topbar.tsx +63 -0
  85. package/components/trash-icon.tsx +24 -0
  86. package/components/week-starts-on-setting.tsx +39 -0
  87. package/eslint.config.mjs +18 -0
  88. package/lib/add_note_to_entry.ts +65 -0
  89. package/lib/api_error_response.ts +10 -0
  90. package/lib/apply_accent_color.ts +12 -0
  91. package/lib/apply_color_palette.ts +12 -0
  92. package/lib/apply_compact_lists.ts +9 -0
  93. package/lib/apply_tag_autocomplete_selection.ts +26 -0
  94. package/lib/apply_theme.ts +8 -0
  95. package/lib/build_reporting_stats.ts +55 -0
  96. package/lib/build_resume_description.ts +15 -0
  97. package/lib/check_in_entry.ts +81 -0
  98. package/lib/check_out_entry.ts +75 -0
  99. package/lib/collect_known_tags.ts +22 -0
  100. package/lib/collect_tag_stats.ts +27 -0
  101. package/lib/collect_tags_from_entries.ts +35 -0
  102. package/lib/config.ts +9 -0
  103. package/lib/convert_json_db.ts +49 -0
  104. package/lib/delete_entries.ts +62 -0
  105. package/lib/delete_entry.ts +29 -0
  106. package/lib/delete_note_on_entry.ts +42 -0
  107. package/lib/delete_sheet.ts +30 -0
  108. package/lib/delete_tracker_action.ts +22 -0
  109. package/lib/edit_entry.ts +56 -0
  110. package/lib/edit_note_on_entry.ts +49 -0
  111. package/lib/ensure_dir_exists.ts +22 -0
  112. package/lib/entry_matches_tag_filter.ts +26 -0
  113. package/lib/fetch_tracker_state.ts +15 -0
  114. package/lib/filter_entries_by_tags.ts +20 -0
  115. package/lib/filter_known_tags.ts +20 -0
  116. package/lib/find_all_serialized_active_entries.ts +28 -0
  117. package/lib/find_serialized_active_entry.ts +12 -0
  118. package/lib/find_serialized_active_entry_for_sheet.ts +31 -0
  119. package/lib/find_sheet_with_active_entry.ts +16 -0
  120. package/lib/format_display_tag.ts +6 -0
  121. package/lib/format_duration.ts +45 -0
  122. package/lib/gen_db.ts +43 -0
  123. package/lib/get_active_panel_class_name.ts +20 -0
  124. package/lib/get_average_entry_ms.ts +13 -0
  125. package/lib/get_button_class_name.ts +24 -0
  126. package/lib/get_check_out_confirm_dialog.ts +19 -0
  127. package/lib/get_clipped_entry_duration_ms.ts +18 -0
  128. package/lib/get_compact_lists_snapshot.ts +15 -0
  129. package/lib/get_date_range_ms_from_inputs.ts +31 -0
  130. package/lib/get_delete_entries_confirm_dialog.ts +21 -0
  131. package/lib/get_delete_entry_confirm_dialog.ts +19 -0
  132. package/lib/get_delete_note_confirm_dialog.ts +21 -0
  133. package/lib/get_delete_sheet_confirm_dialog.ts +25 -0
  134. package/lib/get_entry_duration_ms.ts +14 -0
  135. package/lib/get_entry_row_key.ts +8 -0
  136. package/lib/get_initial_preferred_sheet_name.ts +34 -0
  137. package/lib/get_initial_reporting_range_inputs.ts +31 -0
  138. package/lib/get_input_class_name.ts +15 -0
  139. package/lib/get_merge_tags_confirm_dialog.ts +25 -0
  140. package/lib/get_period_range_ms.ts +43 -0
  141. package/lib/get_reporting_date_range_shortcut_inputs.ts +84 -0
  142. package/lib/get_reporting_period_totals.ts +39 -0
  143. package/lib/get_reporting_stats.ts +25 -0
  144. package/lib/get_restore_db_confirm_dialog.ts +14 -0
  145. package/lib/get_running_entry_key.ts +8 -0
  146. package/lib/get_serialized_entries_total_ms.ts +10 -0
  147. package/lib/get_sheet.ts +14 -0
  148. package/lib/get_sheet_report_stats.ts +22 -0
  149. package/lib/get_sheet_report_stats_for_range.ts +46 -0
  150. package/lib/get_sheet_tag_filter_snapshot.ts +22 -0
  151. package/lib/get_sheets_duration_in_range.ts +27 -0
  152. package/lib/get_tag_autocomplete_context.ts +32 -0
  153. package/lib/get_theme_snapshot.ts +16 -0
  154. package/lib/get_tracker_state.ts +67 -0
  155. package/lib/has_string_value.ts +6 -0
  156. package/lib/is_entry_in_day.ts +15 -0
  157. package/lib/is_idle_sheet_report.ts +8 -0
  158. package/lib/is_json_time_tracker_db.ts +14 -0
  159. package/lib/merge_tags_across_db.ts +79 -0
  160. package/lib/migrate_json_db.ts +56 -0
  161. package/lib/migrate_json_db_to_version_three.ts +51 -0
  162. package/lib/migrate_json_db_to_version_two.ts +50 -0
  163. package/lib/move_entries_to_sheet.ts +152 -0
  164. package/lib/move_entry_to_sheet.ts +82 -0
  165. package/lib/normalize_stored_tag.ts +16 -0
  166. package/lib/notify_settings_saved.ts +47 -0
  167. package/lib/parse_default_sheet_session_mode.ts +21 -0
  168. package/lib/parse_entry_from_input.ts +23 -0
  169. package/lib/parse_natural_language_date.ts +23 -0
  170. package/lib/parse_reporting_source_sheets.ts +22 -0
  171. package/lib/partition_sheet_report_stats.ts +30 -0
  172. package/lib/patch_tracker_action.ts +22 -0
  173. package/lib/persist_ui_preference.ts +18 -0
  174. package/lib/post_tracker_action.ts +22 -0
  175. package/lib/preferences/accent_color_preference.ts +21 -0
  176. package/lib/preferences/check_in_form_collapsed_preference.ts +20 -0
  177. package/lib/preferences/clear_tag_filters_on_sheet_change_preference.ts +20 -0
  178. package/lib/preferences/color_palette_preference.ts +21 -0
  179. package/lib/preferences/confirm_before_checkout_preference.ts +20 -0
  180. package/lib/preferences/confirm_destructive_actions_preference.ts +20 -0
  181. package/lib/preferences/default_reporting_range_preference.ts +21 -0
  182. package/lib/preferences/default_reporting_sort_preference.ts +24 -0
  183. package/lib/preferences/duration_format_preference.ts +19 -0
  184. package/lib/preferences/entry_list_sort_preference.ts +21 -0
  185. package/lib/preferences/tag_filter_mode_preference.ts +18 -0
  186. package/lib/preferences/theme_mode_preference.ts +18 -0
  187. package/lib/preferences/time_format_preference.ts +18 -0
  188. package/lib/preferences/timer_in_title_preference.ts +18 -0
  189. package/lib/preferences/timer_show_seconds_preference.ts +19 -0
  190. package/lib/preferences/week_starts_on_preference.ts +19 -0
  191. package/lib/prompt_check_out_at.ts +17 -0
  192. package/lib/prompt_entry_note.ts +14 -0
  193. package/lib/prune_sheet_tag_filter.ts +27 -0
  194. package/lib/read_db.ts +49 -0
  195. package/lib/read_db_backup_contents.ts +22 -0
  196. package/lib/read_document_compact_lists.ts +12 -0
  197. package/lib/read_document_theme.ts +14 -0
  198. package/lib/read_sheet_tag_filter.ts +26 -0
  199. package/lib/read_stored_active_sheet.ts +14 -0
  200. package/lib/read_stored_compact_lists.ts +24 -0
  201. package/lib/read_stored_default_sheet_fixed_name.ts +16 -0
  202. package/lib/read_stored_default_sheet_session_mode.ts +18 -0
  203. package/lib/read_stored_sheet_tag_filters.ts +28 -0
  204. package/lib/read_stored_theme.ts +18 -0
  205. package/lib/rename_sheet.ts +39 -0
  206. package/lib/rename_tag_across_db.ts +19 -0
  207. package/lib/resolve_active_sheet_name.ts +36 -0
  208. package/lib/resolve_session_preferred_sheet.ts +37 -0
  209. package/lib/resolve_theme.ts +18 -0
  210. package/lib/resolve_theme_mode_to_theme.ts +19 -0
  211. package/lib/restore_db_from_uploaded_json.ts +24 -0
  212. package/lib/serialize_entry.ts +27 -0
  213. package/lib/serialize_reporting_source_sheets.ts +19 -0
  214. package/lib/serialize_sheet_entries.ts +18 -0
  215. package/lib/set_accent_color.ts +12 -0
  216. package/lib/set_active_sheet.ts +18 -0
  217. package/lib/set_color_palette.ts +12 -0
  218. package/lib/set_compact_lists.ts +12 -0
  219. package/lib/set_default_sheet_fixed_name.ts +8 -0
  220. package/lib/set_default_sheet_session_mode.ts +11 -0
  221. package/lib/set_sheet_tag_filter.ts +13 -0
  222. package/lib/set_theme_mode.ts +19 -0
  223. package/lib/sheet_tag_filter_snapshots.ts +48 -0
  224. package/lib/sort_serialized_entries.ts +35 -0
  225. package/lib/sort_sheet_report_stats.ts +43 -0
  226. package/lib/subscribe_compact_lists.ts +25 -0
  227. package/lib/subscribe_sheet_tag_filters.ts +28 -0
  228. package/lib/subscribe_theme.ts +23 -0
  229. package/lib/sync_active_sheet_preference.ts +19 -0
  230. package/lib/tags_are_equal.ts +12 -0
  231. package/lib/theme_init_script.ts +11 -0
  232. package/lib/toggle_sheet_tag_filter.ts +28 -0
  233. package/lib/toggle_theme.ts +20 -0
  234. package/lib/types/confirm_dialog.ts +9 -0
  235. package/lib/types/data.ts +16 -0
  236. package/lib/types/generic_data.ts +25 -0
  237. package/lib/types/index.ts +2 -0
  238. package/lib/types/reporting.ts +59 -0
  239. package/lib/types/tag_management.ts +7 -0
  240. package/lib/types/theme.ts +3 -0
  241. package/lib/types/tracker_state.ts +39 -0
  242. package/lib/types/ui_preferences.ts +104 -0
  243. package/lib/types/ui_settings.ts +17 -0
  244. package/lib/ui_preference_store.ts +80 -0
  245. package/lib/ui_settings_init_script.ts +33 -0
  246. package/lib/use_check_in_form_collapsed.ts +18 -0
  247. package/lib/use_clear_tag_filters_on_sheet_change.ts +18 -0
  248. package/lib/use_confirm_before_checkout.ts +18 -0
  249. package/lib/use_confirm_destructive_actions.ts +18 -0
  250. package/lib/use_duration_format.ts +17 -0
  251. package/lib/use_entry_list_sort.ts +17 -0
  252. package/lib/use_tag_filter_mode.ts +17 -0
  253. package/lib/use_time_format.ts +17 -0
  254. package/lib/use_timer_in_title.ts +18 -0
  255. package/lib/use_timer_show_seconds.ts +18 -0
  256. package/lib/use_week_starts_on.ts +17 -0
  257. package/lib/validate_entry_times.ts +12 -0
  258. package/lib/week_starts_on_to_index.ts +8 -0
  259. package/lib/write_active_sheet_preference.ts +28 -0
  260. package/lib/write_db.ts +20 -0
  261. package/lib/write_sheet_tag_filter.ts +20 -0
  262. package/lib/write_stored_compact_lists.ts +15 -0
  263. package/lib/write_stored_default_sheet_fixed_name.ts +28 -0
  264. package/lib/write_stored_default_sheet_session_mode.ts +24 -0
  265. package/lib/write_stored_sheet_tag_filters.ts +18 -0
  266. package/lib/write_stored_theme.ts +12 -0
  267. package/next.config.ts +7 -0
  268. package/package.json +96 -0
  269. package/pnpm-workspace.yaml +7 -0
  270. package/postcss.config.mjs +7 -0
  271. package/public/file.svg +1 -0
  272. package/public/globe.svg +1 -0
  273. package/public/next.svg +1 -0
  274. package/public/vercel.svg +1 -0
  275. package/public/window.svg +1 -0
  276. package/tsconfig.json +34 -0
@@ -0,0 +1,17 @@
1
+ 'use client'
2
+
3
+ import { useSyncExternalStore } from 'react'
4
+
5
+ import { week_starts_on_preference } from '@/lib/preferences/week_starts_on_preference'
6
+ import { type WeekStartsOn } from '@/lib/types/ui_preferences'
7
+
8
+ /**
9
+ * Subscribes to the week-starts-on preference.
10
+ */
11
+ export function use_week_starts_on(): WeekStartsOn {
12
+ return useSyncExternalStore(
13
+ week_starts_on_preference.subscribe,
14
+ week_starts_on_preference.get_snapshot,
15
+ week_starts_on_preference.get_server_snapshot,
16
+ )
17
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Ensures a completed entry has a start time strictly before its end time.
3
+ */
4
+ export function validate_entry_times(start: Date, end: Date | null): void {
5
+ if (end === null) {
6
+ return;
7
+ }
8
+
9
+ if (+start >= +end) {
10
+ throw new Error("Start must be before end");
11
+ }
12
+ }
@@ -0,0 +1,8 @@
1
+ import { type WeekStartsOn } from '@/lib/types/ui_preferences'
2
+
3
+ /**
4
+ * Maps the week-starts-on preference to a date-fns week start index.
5
+ */
6
+ export function week_starts_on_to_index(value: WeekStartsOn): 0 | 1 {
7
+ return value === 'sunday' ? 0 : 1
8
+ }
@@ -0,0 +1,28 @@
1
+ import {
2
+ ACTIVE_SHEET_COOKIE_NAME,
3
+ ACTIVE_SHEET_STORAGE_KEY,
4
+ } from '@/lib/types/ui_settings'
5
+
6
+ /**
7
+ * Persists the last opened sheet in localStorage and a cookie for SSR reloads.
8
+ */
9
+ export function write_active_sheet_preference(sheet_name: string): void {
10
+ const trimmed = sheet_name.trim()
11
+
12
+ if (trimmed.length === 0) {
13
+ return
14
+ }
15
+
16
+ try {
17
+ window.localStorage.setItem(ACTIVE_SHEET_STORAGE_KEY, trimmed)
18
+ } catch {
19
+ // Ignore storage failures in private browsing.
20
+ }
21
+
22
+ try {
23
+ const encoded = encodeURIComponent(trimmed)
24
+ document.cookie = `${ACTIVE_SHEET_COOKIE_NAME}=${encoded}; Path=/; Max-Age=31536000; SameSite=Lax`
25
+ } catch {
26
+ // Ignore cookie failures.
27
+ }
28
+ }
@@ -0,0 +1,20 @@
1
+ import { promises as fs } from "node:fs";
2
+
3
+ import { DB_PATH } from "@/lib/config";
4
+ import { type TimeTrackerDB } from "@/lib/types";
5
+
6
+ /**
7
+ * Persists the in-memory database to disk as JSON.
8
+ */
9
+ export async function write_db(
10
+ db: TimeTrackerDB,
11
+ db_path: string = DB_PATH,
12
+ ): Promise<void> {
13
+ const db_json = JSON.stringify(db);
14
+
15
+ try {
16
+ await fs.writeFile(db_path, db_json);
17
+ } catch (err: unknown) {
18
+ throw new Error(`Failed to save DB: ${String(err)}`, { cause: err });
19
+ }
20
+ }
@@ -0,0 +1,20 @@
1
+ import { read_stored_sheet_tag_filters } from '@/lib/read_stored_sheet_tag_filters'
2
+ import { write_stored_sheet_tag_filters } from '@/lib/write_stored_sheet_tag_filters'
3
+
4
+ /**
5
+ * Updates one sheet's tag filter list in localStorage.
6
+ */
7
+ export function write_sheet_tag_filter(
8
+ sheet_name: string,
9
+ filter_tags: string[],
10
+ ): void {
11
+ const filters = read_stored_sheet_tag_filters()
12
+
13
+ if (filter_tags.length === 0) {
14
+ delete filters[sheet_name]
15
+ } else {
16
+ filters[sheet_name] = filter_tags
17
+ }
18
+
19
+ write_stored_sheet_tag_filters(filters)
20
+ }
@@ -0,0 +1,15 @@
1
+ import { COMPACT_LISTS_STORAGE_KEY } from "@/lib/types/ui_settings";
2
+
3
+ /**
4
+ * Persists the compact lists setting to localStorage.
5
+ */
6
+ export function write_stored_compact_lists(enabled: boolean): void {
7
+ try {
8
+ window.localStorage.setItem(
9
+ COMPACT_LISTS_STORAGE_KEY,
10
+ enabled ? "true" : "false",
11
+ );
12
+ } catch {
13
+ // Ignore storage failures in private browsing.
14
+ }
15
+ }
@@ -0,0 +1,28 @@
1
+ import {
2
+ DEFAULT_SHEET_FIXED_NAME_COOKIE_NAME,
3
+ DEFAULT_SHEET_FIXED_NAME_STORAGE_KEY,
4
+ } from '@/lib/types/ui_settings'
5
+
6
+ /**
7
+ * Persists the fixed default sheet name in localStorage and a cookie.
8
+ */
9
+ export function write_stored_default_sheet_fixed_name(sheet_name: string): void {
10
+ const trimmed = sheet_name.trim()
11
+
12
+ if (trimmed.length === 0) {
13
+ return
14
+ }
15
+
16
+ try {
17
+ window.localStorage.setItem(DEFAULT_SHEET_FIXED_NAME_STORAGE_KEY, trimmed)
18
+ } catch {
19
+ // Ignore storage failures in private browsing.
20
+ }
21
+
22
+ try {
23
+ const encoded = encodeURIComponent(trimmed)
24
+ document.cookie = `${DEFAULT_SHEET_FIXED_NAME_COOKIE_NAME}=${encoded}; Path=/; Max-Age=31536000; SameSite=Lax`
25
+ } catch {
26
+ // Ignore cookie failures.
27
+ }
28
+ }
@@ -0,0 +1,24 @@
1
+ import { type DefaultSheetSessionMode } from '@/lib/types/ui_settings'
2
+ import {
3
+ DEFAULT_SHEET_SESSION_MODE_COOKIE_NAME,
4
+ DEFAULT_SHEET_SESSION_MODE_STORAGE_KEY,
5
+ } from '@/lib/types/ui_settings'
6
+
7
+ /**
8
+ * Persists the default sheet session mode in localStorage and a cookie.
9
+ */
10
+ export function write_stored_default_sheet_session_mode(
11
+ mode: DefaultSheetSessionMode,
12
+ ): void {
13
+ try {
14
+ window.localStorage.setItem(DEFAULT_SHEET_SESSION_MODE_STORAGE_KEY, mode)
15
+ } catch {
16
+ // Ignore storage failures in private browsing.
17
+ }
18
+
19
+ try {
20
+ document.cookie = `${DEFAULT_SHEET_SESSION_MODE_COOKIE_NAME}=${mode}; Path=/; Max-Age=31536000; SameSite=Lax`
21
+ } catch {
22
+ // Ignore cookie failures.
23
+ }
24
+ }
@@ -0,0 +1,18 @@
1
+ import { read_stored_sheet_tag_filters } from '@/lib/read_stored_sheet_tag_filters'
2
+ import { SHEET_TAG_FILTERS_STORAGE_KEY } from '@/lib/types/ui_settings'
3
+
4
+ /**
5
+ * Persists per-sheet tag filter selections to localStorage.
6
+ */
7
+ export function write_stored_sheet_tag_filters(
8
+ filters: Record<string, string[]>,
9
+ ): void {
10
+ try {
11
+ window.localStorage.setItem(
12
+ SHEET_TAG_FILTERS_STORAGE_KEY,
13
+ JSON.stringify(filters),
14
+ )
15
+ } catch {
16
+ // Ignore storage failures in private browsing.
17
+ }
18
+ }
@@ -0,0 +1,12 @@
1
+ import { THEME_STORAGE_KEY, type Theme } from "@/lib/types/theme";
2
+
3
+ /**
4
+ * Persists the active theme to localStorage.
5
+ */
6
+ export function write_stored_theme(theme: Theme): void {
7
+ try {
8
+ window.localStorage.setItem(THEME_STORAGE_KEY, theme);
9
+ } catch {
10
+ // Storage may be unavailable in private browsing or restricted contexts.
11
+ }
12
+ }
package/next.config.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { NextConfig } from "next";
2
+
3
+ const nextConfig: NextConfig = {
4
+ output: 'standalone',
5
+ }
6
+
7
+ export default nextConfig;
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "super-time-tracker-ui",
3
+ "version": "0.1.2",
4
+ "description": "Web UI for the super-time-tracker CLI time sheets",
5
+ "keywords": [
6
+ "nextjs",
7
+ "react",
8
+ "time-tracking",
9
+ "timesheet",
10
+ "super-time-tracker",
11
+ "ui"
12
+ ],
13
+ "homepage": "https://github.com/f3rnox/super-time-tracker-ui",
14
+ "bugs": {
15
+ "url": "https://github.com/f3rnox/super-time-tracker-ui/issues"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/f3rnox/super-time-tracker-ui.git"
20
+ },
21
+ "license": "MIT",
22
+ "author": "Cris Mihalache <f3rnox42@gmail.com>",
23
+ "engines": {
24
+ "node": ">=20.0.0"
25
+ },
26
+ "bin": {
27
+ "stt-ui": "./bin/stt-ui.js"
28
+ },
29
+ "scripts": {
30
+ "dev": "next dev",
31
+ "build": "next build",
32
+ "start": "next start",
33
+ "stt-ui": "node bin/stt-ui.js",
34
+ "format": "pnpm format:prettier",
35
+ "format:check": "pnpm format:prettier:check",
36
+ "format:prettier": "prettier --write .",
37
+ "format:prettier:check": "prettier --check .",
38
+ "lint": "pnpm lint:markdownlint && pnpm lint:eslint",
39
+ "lint:eslint": "eslint package.json src/**/*",
40
+ "lint:eslint:fix": "eslint package.json src/**/*",
41
+ "lint:fix": "pnpm lint:markdownlint:fix && pnpm lint:eslint:fix",
42
+ "lint:markdownlint": "markdownlint README.md",
43
+ "lint:markdownlint:fix": "markdownlint --fix README.md",
44
+ "prepare": "husky",
45
+ "prepare-release": "pnpm build && git add docs",
46
+ "prepublish": "pnpm build",
47
+ "release": "pnpm prepare-release && pnpm update-version && git push --follow-tags origin main",
48
+ "serve:coverage": "http-server ./coverage",
49
+ "serve:docs": "http-server ./docs",
50
+ "test": "NODE_PATH=./src NODE_ENV=test vitest run",
51
+ "update-deps": "updates -u -g -c",
52
+ "update-version": "standard-version -a"
53
+ },
54
+ "dependencies": {
55
+ "date-fns": "^4.2.1",
56
+ "humanize-duration": "^3.33.2",
57
+ "next": "16.2.6",
58
+ "react": "19.2.4",
59
+ "react-dom": "19.2.4",
60
+ "time-speak": "^1.9.0"
61
+ },
62
+ "devDependencies": {
63
+ "@tailwindcss/postcss": "^4",
64
+ "@types/humanize-duration": "^3.27.4",
65
+ "@types/node": "^20",
66
+ "@types/react": "^19",
67
+ "@types/react-dom": "^19",
68
+ "eslint": "^9",
69
+ "eslint-config-next": "16.2.6",
70
+ "tailwindcss": "^4",
71
+ "typescript": "^5",
72
+ "@commitlint/cli": "^20.5.0",
73
+ "@commitlint/config-conventional": "^20.5.0",
74
+ "@commitlint/format": "^20.5.0",
75
+ "@commitlint/types": "^20.5.0",
76
+ "@eslint/js": "^10.0.1",
77
+ "@istanbuljs/nyc-config-typescript": "^1.0.2",
78
+ "globals": "^17.4.0",
79
+ "http-server": "^14.1.1",
80
+ "husky": "^9.1.7",
81
+ "jiti": "^2.6.1",
82
+ "lint-staged": "^16.4.0",
83
+ "markdownlint-cli": "^0.48.0",
84
+ "nyc": "^18.0.0",
85
+ "prettier": "^3.8.1",
86
+ "remark": "^15.0.1",
87
+ "standard-version": "^9.5.0",
88
+ "ts-node": "^10.9.2",
89
+ "tslib": "^2.8.1",
90
+ "tsx": "^4.21.0",
91
+ "typedoc": "^0.28.18",
92
+ "typescript-eslint": "^8.58.0",
93
+ "updates": "^17.13.5",
94
+ "vitest": "^4.1.2"
95
+ }
96
+ }
@@ -0,0 +1,7 @@
1
+ allowBuilds:
2
+ esbuild: false
3
+ sharp: false
4
+ unrs-resolver: false
5
+ ignoredBuiltDependencies:
6
+ - sharp
7
+ - unrs-resolver
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1 @@
1
+ <svg fill="none" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M14.5 13.5V5.41a1 1 0 0 0-.3-.7L9.8.29A1 1 0 0 0 9.08 0H1.5v13.5A2.5 2.5 0 0 0 4 16h8a2.5 2.5 0 0 0 2.5-2.5m-1.5 0v-7H8v-5H3v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1M9.5 5V2.12L12.38 5zM5.13 5h-.62v1.25h2.12V5zm-.62 3h7.12v1.25H4.5zm.62 3h-.62v1.25h7.12V11z" clip-rule="evenodd" fill="#666" fill-rule="evenodd"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g clip-path="url(#a)"><path fill-rule="evenodd" clip-rule="evenodd" d="M10.27 14.1a6.5 6.5 0 0 0 3.67-3.45q-1.24.21-2.7.34-.31 1.83-.97 3.1M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16m.48-1.52a7 7 0 0 1-.96 0H7.5a4 4 0 0 1-.84-1.32q-.38-.89-.63-2.08a40 40 0 0 0 3.92 0q-.25 1.2-.63 2.08a4 4 0 0 1-.84 1.31zm2.94-4.76q1.66-.15 2.95-.43a7 7 0 0 0 0-2.58q-1.3-.27-2.95-.43a18 18 0 0 1 0 3.44m-1.27-3.54a17 17 0 0 1 0 3.64 39 39 0 0 1-4.3 0 17 17 0 0 1 0-3.64 39 39 0 0 1 4.3 0m1.1-1.17q1.45.13 2.69.34a6.5 6.5 0 0 0-3.67-3.44q.65 1.26.98 3.1M8.48 1.5l.01.02q.41.37.84 1.31.38.89.63 2.08a40 40 0 0 0-3.92 0q.25-1.2.63-2.08a4 4 0 0 1 .85-1.32 7 7 0 0 1 .96 0m-2.75.4a6.5 6.5 0 0 0-3.67 3.44 29 29 0 0 1 2.7-.34q.31-1.83.97-3.1M4.58 6.28q-1.66.16-2.95.43a7 7 0 0 0 0 2.58q1.3.27 2.95.43a18 18 0 0 1 0-3.44m.17 4.71q-1.45-.12-2.69-.34a6.5 6.5 0 0 0 3.67 3.44q-.65-1.27-.98-3.1" fill="#666"/></g><defs><clipPath id="a"><path fill="#fff" d="M0 0h16v16H0z"/></clipPath></defs></svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1155 1000"><path d="m577.3 0 577.4 1000H0z" fill="#fff"/></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path fill-rule="evenodd" clip-rule="evenodd" d="M1.5 2.5h13v10a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1zM0 1h16v11.5a2.5 2.5 0 0 1-2.5 2.5h-11A2.5 2.5 0 0 1 0 12.5zm3.75 4.5a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5M7 4.75a.75.75 0 1 1-1.5 0 .75.75 0 0 1 1.5 0m1.75.75a.75.75 0 1 0 0-1.5.75.75 0 0 0 0 1.5" fill="#666"/></svg>
package/tsconfig.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "react-jsx",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./*"]
23
+ }
24
+ },
25
+ "include": [
26
+ "next-env.d.ts",
27
+ "**/*.ts",
28
+ "**/*.tsx",
29
+ ".next/types/**/*.ts",
30
+ ".next/dev/types/**/*.ts",
31
+ "**/*.mts"
32
+ ],
33
+ "exclude": ["node_modules"]
34
+ }