diff --git a/sl/SL_Menu.py b/sl/SL_Menu.py index 6646752..ad342e7 100644 --- a/sl/SL_Menu.py +++ b/sl/SL_Menu.py @@ -63,8 +63,139 @@ def local_css(file_name): with open(file_path, 'r', encoding='utf-8') as f: st.markdown(f'', unsafe_allow_html=True) +def render_icon_button_css(): + """ + Keeps icon-only action buttons visually consistent across all Streamlit views. + """ + button_selectors = [ + '[class*="st-key-toolbar_new_popover"] [data-testid="stPopoverButton"]', + '[class*="st-key-toolbar_report_popover"] [data-testid="stPopoverButton"]', + '[class*="st-key-toolbar_today_btn"] button', + '[class*="st-key-toolbar_planning_btn"] button', + '[class*="st-key-toolbar_email_btn"] button', + '[class*="st-key-toolbar_start_btn"] button', + '[class*="st-key-toolbar_info_btn"] button', + '[class*="st-key-toolbar_stop_btn"] button', + '[class*="st-key-toolbar_settings_btn"] button', + '[class*="st-key-main_done_button"] button', + '[class*="st-key-main_edit_button"] button', + '[class*="st-key-start_task_planning"] button', + '[class*="st-key-edit_task_planning"] button', + '[class*="st-key-today_task_planning"] button', + '[class*="st-key-done_task_planning"] button', + '[class*="st-key-start_today_task"] button', + '[class*="st-key-edit_today_task"] button', + '[class*="st-key-done_today_task"] button', + '[class*="st-key-del_email_"] button', + '[class*="st-key-clear_email_due_date_"] button', + '[class*="st-key-edit_clear_due_date_btn"] button', + '[class*="st-key-close_inactive_"] button', + ] + icon_buttons = ",\n ".join(button_selectors) + + st.markdown(f""" + + """, unsafe_allow_html=True) + config = get_config() local_css(config.get('css_file', 'style.css')) +render_icon_button_css() # --- State Management --- @@ -137,147 +268,25 @@ def view_main(): task_details = next((t for t in all_tasks if t['task_name'] == current_work['task_name']), {}) is_done = task_details.get('status') == 'done' - # Custom CSS to keep the info box and edit button side-by-side and the button square - # This CSS is now more specific to target the toolbar and the current work display separately. - st.markdown(""" - - """, unsafe_allow_html=True) - # --- Toolbar --- t_col_new, t_col_today, t_col_planning, t_col_email, t_col_start, t_col_info, t_col_stop, t_col_report, t_col_settings, _col = st.columns([1, 1, 1, 1, 1, 1, 1, 1, 1, 3]) with t_col_new: - with st.popover("✨", help=_("New")): + with st.popover("+", help=_("New"), key="toolbar_new_popover"): if st.button(_("New Project"), use_container_width=True): navigate_to('add_main_project') if st.button(_("New Task"), use_container_width=True): navigate_to('add_task') with t_col_today: - if st.button("⭐", help=_("Today View"), key="toolbar_today_btn"): + if st.button("★", help=_("Today View"), key="toolbar_today_btn"): navigate_to('today_view') with t_col_planning: - if st.button("📋", help=_("Task Planning"), key="toolbar_planning_btn"): + if st.button("▣", help=_("Task Planning"), key="toolbar_planning_btn"): navigate_to('task_planning') with t_col_email: - if st.button("✉️", help=_("E-Mail Task Assignment"), key="toolbar_email_btn"): + if st.button("@", help=_("E-Mail Task Assignment"), key="toolbar_email_btn"): navigate_to('email_assignment') with t_col_start: @@ -285,11 +294,11 @@ def view_main(): navigate_to('start_work') with t_col_info: - if st.button("ⓘ", help=_("Show current work"), key="toolbar_info_btn"): + if st.button("i", help=_("Show current work"), key="toolbar_info_btn"): navigate_to('show_current_work') with t_col_stop: - if st.button("⏹", help=_("Stop current work"), key="toolbar_stop_btn", disabled=not current_work): + if st.button("■", help=_("Stop current work"), key="toolbar_stop_btn", disabled=not current_work): if st.session_state.tracker.stop_work(): set_feedback(_("Work session stopped successfully.")) else: @@ -297,7 +306,7 @@ def view_main(): st.rerun() with t_col_report: - with st.popover("📝", help=_("Reporting")): + with st.popover("▥", help=_("Reporting"), key="toolbar_report_popover"): if st.button(_("Daily Report (Today)"), use_container_width=True, key="pop_report_today"): report = st.session_state.tracker.generate_daily_report() st.session_state.context['report'] = report @@ -314,7 +323,7 @@ def view_main(): navigate_to('report_detailed_daily') with t_col_settings: - if st.button("⚙️", help=_("Settings"), key="toolbar_settings_btn"): + if st.button("⚙", help=_("Settings"), key="toolbar_settings_btn"): navigate_to('settings') col_info, col_done, col_edit = st.columns([10, 1, 1]) @@ -326,7 +335,7 @@ def view_main(): st.info(_("No active work session.")) with col_done: - if st.button("✔", help=_("Done"), disabled=not current_work or is_done, key="main_done_button"): + if st.button("✓", help=_("Done"), disabled=not current_work or is_done, key="main_done_button"): st.session_state.tracker.update_task( current_work['main_project_name'], current_work['task_name'], @@ -340,7 +349,7 @@ def view_main(): st.rerun() with col_edit: - if st.button("✎", help=_("Edit current task"), disabled=not current_work): + if st.button("✎", help=_("Edit current task"), disabled=not current_work, key="main_edit_button"): st.session_state.context['selected_main'] = current_work['main_project_name'] st.session_state.context['selected_task'] = current_work['task_name'] st.session_state.context['return_to'] = 'main' @@ -361,57 +370,7 @@ def view_task_planning(): Renders the task planning view, showing all tasks that are not closed. """ render_header(_("Task Planning")) - - # Custom CSS for square action buttons in the task list - st.markdown(""" - - """, unsafe_allow_html=True) + # Icon action buttons are styled globally by render_icon_button_css(). filter_options = [ _("Today"), @@ -489,7 +448,7 @@ def view_task_planning(): st.session_state.context['return_to'] = 'task_planning' navigate_to('edit_task_form') with col_today_btn: - if st.button("⭐", key=f"today_task_planning_weekly_{task['main_project_name']}_{task['task_name']}_{t_idx}", help=_("Today"), disabled=task.get('today', False)): + if st.button("★", key=f"today_task_planning_weekly_{task['main_project_name']}_{task['task_name']}_{t_idx}", help=_("Today"), disabled=task.get('today', False)): st.session_state.tracker.update_task( task['main_project_name'], task['task_name'], @@ -502,7 +461,7 @@ def view_task_planning(): ) st.rerun() with col_done_btn: - if st.button("✔", key=f"done_task_planning_weekly_{task['main_project_name']}_{task['task_name']}_{t_idx}", help=_("Done"), disabled=is_done): + if st.button("✓", key=f"done_task_planning_weekly_{task['main_project_name']}_{task['task_name']}_{t_idx}", help=_("Done"), disabled=is_done): st.session_state.tracker.update_task( task['main_project_name'], task['task_name'], @@ -551,7 +510,7 @@ def view_task_planning(): st.session_state.context['return_to'] = 'task_planning' navigate_to('edit_task_form') with col_today_btn: - if st.button("⭐", key=f"today_task_planning_{task['main_project_name']}_{task['task_name']}_{t_idx}", help=_("Today"), disabled=task.get('today', False)): + if st.button("★", key=f"today_task_planning_{task['main_project_name']}_{task['task_name']}_{t_idx}", help=_("Today"), disabled=task.get('today', False)): st.session_state.tracker.update_task( task['main_project_name'], task['task_name'], @@ -564,7 +523,7 @@ def view_task_planning(): ) st.rerun() with col_done_btn: - if st.button("✔", key=f"done_task_planning_{task['main_project_name']}_{task['task_name']}_{t_idx}", help=_("Done"), disabled=is_done): + if st.button("✓", key=f"done_task_planning_{task['main_project_name']}_{task['task_name']}_{t_idx}", help=_("Done"), disabled=is_done): st.session_state.tracker.update_task( task['main_project_name'], task['task_name'], @@ -588,55 +547,7 @@ def view_today_tasks(): """ render_header(_("Today's Tasks")) - # Custom CSS for square action buttons in the task list - st.markdown(""" - - """, unsafe_allow_html=True) + # Icon action buttons are styled globally by render_icon_button_css(). st.session_state.tracker.cleanup_overdue_today_tasks() current_work = st.session_state.tracker.get_current_work() @@ -686,7 +597,7 @@ def view_today_tasks(): st.session_state.context['return_to'] = 'today_view' navigate_to('edit_task_form') with col_done_btn: - if st.button("✔", key=f"done_today_task_{task['main_project_name']}_{task['task_name']}_{t_idx}", help=_("Done"), disabled=is_done): + if st.button("✓", key=f"done_today_task_{task['main_project_name']}_{task['task_name']}_{t_idx}", help=_("Done"), disabled=is_done): st.session_state.tracker.update_task( task['main_project_name'], task['task_name'], @@ -709,16 +620,6 @@ def view_email_assignment(): Renders the view to assign tasks fetched from emails to active projects. """ render_header(_("E-Mail Task Assignment")) - - # Custom CSS to resize the trash icon and ensure centering - st.markdown(""" - - """, unsafe_allow_html=True) if 'confirm_delete_email_task_id' not in st.session_state: st.session_state.confirm_delete_email_task_id = None @@ -776,7 +677,7 @@ def view_email_assignment(): # Placeholder for delete button if no confirmation is pending with col_del_btn_placeholder: # 'use_container_width' ensures the button fills the column, centering the icon - if st.button("🗑", key=f"del_email_{task['id']}", help=_("Delete"), use_container_width=True): + if st.button("⌫", key=f"del_email_{task['id']}", help=_("Delete"), use_container_width=True): st.session_state.confirm_delete_email_task_id = task['id'] st.rerun() @@ -805,7 +706,7 @@ def view_email_assignment(): st.session_state[f'email_due_{task["id"]}'] = new_due_date with col_clear_date: st.markdown("
", unsafe_allow_html=True) - if st.button("✖️", key=f"clear_email_due_date_{task['id']}", use_container_width=True, help=_("Clear")): + if st.button("×", key=f"clear_email_due_date_{task['id']}", use_container_width=True, help=_("Clear")): st.session_state[f'email_due_{task["id"]}'] = None st.rerun() with col_today: @@ -1167,7 +1068,7 @@ def view_list_inactive_tasks(): st.markdown(f"**{item['main_project']}** / {item['task_name']}") st.caption(f"{_('Last Activity')}: {item['last_activity']}") with col_btn: - if st.button("🔒", key=f"close_inactive_{i}", help=_("Close Task")): + if st.button("■", key=f"close_inactive_{i}", help=_("Close Task")): st.session_state.tracker.close_task(item['main_project'], item['task_name'], task_id=item.get('id')) st.rerun() else: @@ -1808,7 +1709,7 @@ def view_edit_task_form(): st.session_state.edit_due_date = new_due with col_clear: st.markdown("
", unsafe_allow_html=True) - if st.button("✖️", use_container_width=True, help=_("Clear")): + if st.button("×", use_container_width=True, help=_("Clear"), key="edit_clear_due_date_btn"): st.session_state.edit_due_date = None st.rerun() @@ -2473,4 +2374,4 @@ def view_generic_placeholder(title): with st.sidebar: st.markdown("---") st.caption("Time Control © 2026") - st.caption(f"Port: {get_config().get('streamlit_port', 8501)}") \ No newline at end of file + st.caption(f"Port: {get_config().get('streamlit_port', 8501)}") diff --git a/tt/TimeTracker.py b/tt/TimeTracker.py index 4e6cea9..c5ca11e 100644 --- a/tt/TimeTracker.py +++ b/tt/TimeTracker.py @@ -32,7 +32,7 @@ class TimeTracker: The data is loaded from and saved to a JSON file. """ - VERSION = "3.12" + VERSION = "3.13" STATUS_OPEN = "open" STATUS_CLOSED = "closed" STATUS_DONE = "done"