WIP PWA for Grain
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: add plus button to bottom nav for gallery creation

+62 -1
+62 -1
src/components/organisms/grain-bottom-nav.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 { draftGallery } from '../../services/draft-gallery.js'; 5 + import { processPhotos } from '../../utils/image-resize.js'; 4 6 import '../atoms/grain-icon.js'; 5 7 6 8 export class GrainBottomNav extends LitElement { 7 9 static properties = { 8 - _user: { state: true } 10 + _user: { state: true }, 11 + _processing: { state: true } 9 12 }; 10 13 11 14 static styles = css` ··· 41 44 button.active { 42 45 color: var(--color-text-primary); 43 46 } 47 + button.plus { 48 + background: none; 49 + border: none; 50 + padding: 8px; 51 + cursor: pointer; 52 + color: var(--color-text-secondary); 53 + } 54 + button.plus:disabled { 55 + opacity: 0.5; 56 + cursor: not-allowed; 57 + } 58 + input[type="file"] { 59 + display: none; 60 + } 44 61 `; 45 62 46 63 constructor() { 47 64 super(); 48 65 this._user = auth.user; 66 + this._processing = false; 49 67 this._onNavigate = () => this.requestUpdate(); 50 68 } 51 69 ··· 83 101 } 84 102 } 85 103 104 + #handleCreate() { 105 + this.shadowRoot.getElementById('photo-input').click(); 106 + } 107 + 108 + async #handleFilesSelected(e) { 109 + const files = Array.from(e.target.files); 110 + e.target.value = ''; 111 + 112 + if (files.length === 0) return; 113 + if (files.length > 10) { 114 + alert('Maximum 10 photos allowed'); 115 + return; 116 + } 117 + 118 + try { 119 + this._processing = true; 120 + const processed = await processPhotos(files); 121 + draftGallery.setPhotos(processed); 122 + router.push('/create'); 123 + } catch (err) { 124 + console.error('Failed to process photos:', err); 125 + alert('Failed to process photos. Please try again.'); 126 + } finally { 127 + this._processing = false; 128 + } 129 + } 130 + 86 131 render() { 87 132 return html` 88 133 <nav> ··· 92 137 > 93 138 <grain-icon name=${this.#isHome ? 'home' : 'homeLine'} size="20"></grain-icon> 94 139 </button> 140 + ${this._user ? html` 141 + <button 142 + class="plus" 143 + @click=${this.#handleCreate} 144 + ?disabled=${this._processing} 145 + > 146 + <grain-icon name="plus" size="20"></grain-icon> 147 + </button> 148 + <input 149 + type="file" 150 + id="photo-input" 151 + accept="image/*" 152 + multiple 153 + @change=${this.#handleFilesSelected} 154 + > 155 + ` : ''} 95 156 <button 96 157 class=${this.#isOwnProfile ? 'active' : ''} 97 158 @click=${this.#handleProfile}