WIP PWA for Grain

feat: convert profile ellipsis to action menu with share option

+47 -9
+47 -9
src/components/organisms/grain-profile-header.js
··· 1 1 import { LitElement, html, css } from 'lit'; 2 2 import { router } from '../../router.js'; 3 3 import { auth } from '../../services/auth.js'; 4 + import { share } from '../../services/share.js'; 4 5 import '../atoms/grain-avatar.js'; 5 6 import '../atoms/grain-icon.js'; 7 + import '../atoms/grain-toast.js'; 6 8 import '../molecules/grain-profile-stats.js'; 9 + import '../organisms/grain-action-dialog.js'; 7 10 8 11 export class GrainProfileHeader extends LitElement { 9 12 static properties = { 10 13 profile: { type: Object }, 11 14 _showFullscreen: { state: true }, 12 - _user: { state: true } 15 + _user: { state: true }, 16 + _menuOpen: { state: true } 13 17 }; 14 18 15 19 static styles = css` ··· 84 88 border-radius: 50%; 85 89 object-fit: cover; 86 90 } 87 - .settings-button { 91 + .menu-button { 88 92 background: none; 89 93 border: none; 90 94 padding: 0; ··· 97 101 super(); 98 102 this._showFullscreen = false; 99 103 this._user = auth.user; 104 + this._menuOpen = false; 100 105 } 101 106 102 107 connectedCallback() { ··· 115 120 return this._user?.handle && this._user.handle === this.profile?.handle; 116 121 } 117 122 118 - #goToSettings() { 119 - router.push('/settings'); 123 + get #menuActions() { 124 + const actions = [{ label: 'Share', action: 'share' }]; 125 + if (this.#isOwnProfile) { 126 + actions.push({ label: 'Settings', action: 'settings' }); 127 + } 128 + return actions; 129 + } 130 + 131 + #openMenu() { 132 + this._menuOpen = true; 133 + } 134 + 135 + #closeMenu() { 136 + this._menuOpen = false; 137 + } 138 + 139 + async #handleAction(e) { 140 + const action = e.detail.action; 141 + this._menuOpen = false; 142 + 143 + if (action === 'settings') { 144 + router.push('/settings'); 145 + } else if (action === 'share') { 146 + const result = await share(window.location.href); 147 + if (result.success && result.method === 'clipboard') { 148 + this.shadowRoot.querySelector('grain-toast').show('Link copied'); 149 + } 150 + } 120 151 } 121 152 122 153 #openFullscreen() { ··· 150 181 <div class="right-column"> 151 182 <div class="handle-row"> 152 183 <span class="handle">${handle}</span> 153 - ${this.#isOwnProfile ? html` 154 - <button class="settings-button" @click=${this.#goToSettings}> 155 - <grain-icon name="ellipsisVertical" size="20"></grain-icon> 156 - </button> 157 - ` : ''} 184 + <button class="menu-button" @click=${this.#openMenu}> 185 + <grain-icon name="ellipsisVertical" size="20"></grain-icon> 186 + </button> 158 187 </div> 159 188 ${displayName ? html`<div class="name">${displayName}</div>` : ''} 160 189 <grain-profile-stats ··· 166 195 ${description ? html`<div class="bio">${description}</div>` : ''} 167 196 </div> 168 197 </div> 198 + 199 + <grain-action-dialog 200 + ?open=${this._menuOpen} 201 + .actions=${this.#menuActions} 202 + @action=${this.#handleAction} 203 + @close=${this.#closeMenu} 204 + ></grain-action-dialog> 205 + 206 + <grain-toast></grain-toast> 169 207 `; 170 208 } 171 209 }