from fasthtml.components import * from myfasthtml.controls.BaseCommands import BaseCommands from myfasthtml.controls.helpers import mk from myfasthtml.core.AuthProxy import AuthProxy from myfasthtml.core.commands import Command from myfasthtml.core.instances import SingleInstance, RootInstance from myfasthtml.core.utils import retrieve_user_info from myfasthtml.icons.material import dark_mode_filled, person_outline_sharp from myfasthtml.icons.material_p1 import light_mode_filled, alternate_email_filled class UserProfileState: def __init__(self, owner): self._owner = owner self._session = owner.get_session() self.theme = "light" self.load() def load(self): user_info = retrieve_user_info(self._session) user_settings = user_info.get("user_settings", {}) for k, v in user_settings.items(): if hasattr(self, k): setattr(self, k, v) def save(self): user_settings = {k: v for k, v in self.__dict__.items() if not k.startswith("_")} auth_proxy = AuthProxy(RootInstance) auth_proxy.save_user_info(self._session["access_token"], {"user_settings": user_settings}) class Commands(BaseCommands): def update_dark_mode(self): return Command("UpdateDarkMode", "Set the dark mode", self._owner.update_dark_mode).htmx(target=None) class UserProfile(SingleInstance): def __init__(self, parent=None, _id=None): super().__init__(parent, _id=_id) self._state = UserProfileState(self) self._commands = Commands(self) def update_dark_mode(self, client_response): self._state.theme = client_response.get("theme", "light") self._state.save() retrieve_user_info(self._session).get("user_settings", {})["theme"] = self._state.theme def render(self): user_info = retrieve_user_info(self._session) return Div( Div(user_info['username'], tabindex="0", role="button", cls="btn btn-xs"), Div( Div(mk.icon(person_outline_sharp, cls="mr-1"), user_info['username'], cls="flex m-1"), Div(mk.icon(alternate_email_filled, cls="mr-1"), user_info['email'], cls="flex m-1"), Div(mk.icon(dark_mode_filled, cls="mr-1"), self.mk_dark_mode(), cls="flex m-1"), Div(A("Logout", cls="btn btn-xs mr-1", href="/logout"), cls="flex justify-center items-center"), tabindex="-1", cls="dropdown-content menu w-52 rounded-box bg-base-300 shadow-xl" ), cls="dropdown dropdown-end" ) def mk_dark_mode(self): return Label( mk.mk(Input(type="checkbox", name='theme', aria_label='Dark', value="dark", checked='true' if self._state.theme == 'dark' else None, cls='theme-controller'), command=self._commands.update_dark_mode()), light_mode_filled, dark_mode_filled, cls="toggle text-base-content" ) def __ft__(self): return self.render()