From 3c91c12cd1aac58cafb0a85ef22cbe2f548263a8 Mon Sep 17 00:00:00 2001 From: Nizzy Date: Mon, 24 Mar 2025 13:33:11 -0700 Subject: [PATCH 001/136] adjustable height --- apps/mail/components/mail/reply-composer.tsx | 91 +++++++++++++++++++- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/apps/mail/components/mail/reply-composer.tsx b/apps/mail/components/mail/reply-composer.tsx index a835ebb0ec..1c33d5e8eb 100644 --- a/apps/mail/components/mail/reply-composer.tsx +++ b/apps/mail/components/mail/reply-composer.tsx @@ -1,4 +1,4 @@ -import { type Dispatch, type SetStateAction, useRef, useState, useEffect } from 'react'; +import { type Dispatch, type SetStateAction, useRef, useState, useEffect, useCallback } from 'react'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { UploadedFileIcon } from '@/components/create/uploaded-file-icon'; import { ArrowUp, Paperclip, Reply, X, Plus } from 'lucide-react'; @@ -26,6 +26,11 @@ export default function ReplyCompose({ emailData, isOpen, setIsOpen }: ReplyComp const [isComposerOpen, setIsComposerOpen] = useState(false); const [isDragging, setIsDragging] = useState(false); const [isEditorFocused, setIsEditorFocused] = useState(false); + const [editorHeight, setEditorHeight] = useState(150); // Initial height 150px + const [isResizing, setIsResizing] = useState(false); + const resizeStartY = useRef(0); + const startHeight = useRef(0); + const composerRef = useRef(null); const t = useTranslations(); // Use external state if provided, otherwise use internal state @@ -197,6 +202,66 @@ export default function ReplyCompose({ emailData, isOpen, setIsOpen }: ReplyComp } }, [composerIsOpen]); + // Handle dynamic resizing + const handleMouseMove = useCallback( + (e: MouseEvent) => { + if (isResizing) { + e.preventDefault(); + // Invert the delta so dragging up grows the editor and dragging down shrinks it + const deltaY = resizeStartY.current - e.clientY; + let newHeight = Math.max(100, Math.min(500, startHeight.current + deltaY)); + + // Ensure height stays within bounds + newHeight = Math.max(100, Math.min(500, newHeight)); + setEditorHeight(newHeight); + } + }, + [isResizing] + ); + + const handleMouseUp = useCallback(() => { + if (isResizing) { + setIsResizing(false); + } + }, [isResizing]); + + // Set up and clean up event listeners for resizing + useEffect(() => { + if (isResizing) { + document.addEventListener('mousemove', handleMouseMove); + document.addEventListener('mouseup', handleMouseUp); + } + + return () => { + document.removeEventListener('mousemove', handleMouseMove); + document.removeEventListener('mouseup', handleMouseUp); + }; + }, [isResizing, handleMouseMove, handleMouseUp]); + + // Auto-grow effect when typing + useEffect(() => { + if (composerIsOpen) { + const editorElement = document.querySelector('.ProseMirror'); + if (editorElement instanceof HTMLElement) { + // Observer to watch for content changes and adjust height + const resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries) { + const contentHeight = entry.contentRect.height; + + // If content exceeds current height but is less than max, grow the container + if (contentHeight > editorHeight - 20 && editorHeight < 500) { + const newHeight = Math.min(500, contentHeight + 20); + setEditorHeight(newHeight); + } + } + }); + + resizeObserver.observe(editorElement); + return () => resizeObserver.disconnect(); + } + } + }, [composerIsOpen, editorHeight]); + // Check if the message is empty const isMessageEmpty = !messageContent || @@ -235,6 +300,7 @@ export default function ReplyCompose({ emailData, isOpen, setIsOpen }: ReplyComp return (
-
+ {/* Resize handle at the top */} +
{ + e.preventDefault(); + setIsResizing(true); + resizeStartY.current = e.clientY; + startHeight.current = editorHeight; + }} + > +
+
+ +
e.stopPropagation()} @@ -311,6 +397,7 @@ export default function ReplyCompose({ emailData, isOpen, setIsOpen }: ReplyComp
+
-
- )} - - {!searchMode && ( + + {mail.bulkSelected.length > 0 ? ( <> - {mail.bulkSelected.length > 0 ? ( - <> -
- - {t('common.mail.selected', { count: mail.bulkSelected.length })} - - - - - - {t('common.mail.clearSelection')} - -
- - - ) : ( - <> -
- -
-
+
+ + {t('common.mail.selected', { count: mail.bulkSelected.length })} + + + -
- - )} + + {t('common.mail.clearSelection')} + +
+ + + ) : ( + <> +
+ +
+
+ +
)}
@@ -601,6 +583,65 @@ const Categories = () => { ]; }; +function CategorySelect() { + const [, setSearchValue] = useSearchValue(); + const categories = Categories(); + const [defaultCategory, setDefaultCategory] = useState('Primary'); + + // Safely access localStorage on the client side only + useEffect(() => { + // Check if we're in the browser environment + if (typeof window !== 'undefined') { + const savedCategory = localStorage.getItem('mailActiveCategory'); + if (savedCategory) { + setDefaultCategory(savedCategory); + } + } + }, []); + + return ( + + ); +} + function MailCategoryTabs({ iconsOnly = false, isLoading = false, From 1650306c646de897adc8042023be21eaaecde5db Mon Sep 17 00:00:00 2001 From: pietrodev07 Date: Tue, 25 Mar 2025 16:45:39 +0100 Subject: [PATCH 004/136] feat(navbar): update item label based on auth status --- apps/mail/components/home/navbar.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/mail/components/home/navbar.tsx b/apps/mail/components/home/navbar.tsx index 3badafc2d4..c96687a34c 100644 --- a/apps/mail/components/home/navbar.tsx +++ b/apps/mail/components/home/navbar.tsx @@ -1,6 +1,7 @@ 'use client'; import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from '../ui/sheet'; import { VisuallyHidden } from '@radix-ui/react-visually-hidden'; +import { useSession } from '@/lib/auth-client'; import { useEffect, useState } from 'react'; import { Menu, X } from 'lucide-react'; import { Button } from '../ui/button'; @@ -9,6 +10,7 @@ import Link from 'next/link'; export default function Navbar() { const [open, setOpen] = useState(false); + const { data: session } = useSession(); // Automatically lose sheet on lg screen useEffect(() => { @@ -80,7 +82,7 @@ export default function Navbar() { href="login" className="text-sm text-gray-800 transition-opacity hover:opacity-80 dark:bg-gradient-to-r dark:from-gray-300 dark:via-gray-100 dark:to-gray-200 dark:bg-clip-text dark:text-transparent" > - Sign in + {session ? "Dashboard": "Sign in"}
+ +## 🤍 The team + +Curious who makes Zero? Here are our [contributors and maintainers](https://0.email/contributors) From 4f66da82c26ccec539ab26a442ea41e1b7b4af9b Mon Sep 17 00:00:00 2001 From: Ahmet Kilinc Date: Tue, 25 Mar 2025 22:22:38 +0000 Subject: [PATCH 010/136] remove text-decoration --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 69591e408b..01988d6c4e 100644 --- a/README.md +++ b/README.md @@ -302,7 +302,7 @@ If you'd like to help with translating Zero to other languages, check out our [t ## This project wouldn't be possible without these awesome companies -
+
Vercel From 2b96a33af802640e6d4867348d94e72c2cb86530 Mon Sep 17 00:00:00 2001 From: Ahmet Kilinc Date: Tue, 25 Mar 2025 22:23:28 +0000 Subject: [PATCH 011/136] text-decoration --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 01988d6c4e..7ba14a941b 100644 --- a/README.md +++ b/README.md @@ -302,17 +302,17 @@ If you'd like to help with translating Zero to other languages, check out our [t ## This project wouldn't be possible without these awesome companies -
- + From de4231df439761144c215f320cd6b88d96f24504 Mon Sep 17 00:00:00 2001 From: Nizzy Date: Tue, 25 Mar 2025 21:15:11 -0700 Subject: [PATCH 012/136] remove auto focus on search --- apps/mail/components/mail/search-bar.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/mail/components/mail/search-bar.tsx b/apps/mail/components/mail/search-bar.tsx index 179726fe5e..a3bcd99080 100644 --- a/apps/mail/components/mail/search-bar.tsx +++ b/apps/mail/components/mail/search-bar.tsx @@ -577,7 +577,6 @@ export function SearchBar() {