diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index d48a46505..e95fc1503 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -28,8 +28,9 @@ RUN apt-get update && apt-get install -y zsh # install Oh My Zsh RUN sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended -# Bun +# Bun and pnpm installation RUN curl -fsSL https://bun.sh/install | bash +RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.bashrc" SHELL="$(which bash)" bash - # Register Bun in bashrc and zshrc RUN echo 'export PATH="$HOME/.bun/bin:$PATH"' >> ~/.bashrc diff --git a/.gitignore b/.gitignore index 3aaa9a60f..a7384153c 100644 --- a/.gitignore +++ b/.gitignore @@ -53,4 +53,5 @@ apps/mail/scripts.ts worker-configuration.d.ts .dev.vars.* -.react-router \ No newline at end of file +.react-router +.pnpm-store \ No newline at end of file diff --git a/README.md b/README.md index 1347532a0..a922f92f3 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,42 @@ You can set up Zero in two ways: Visit [http://localhost:3000](http://localhost:3000) +
+Devcontainer Setup + +#### Quick Start guide + +1. **Clone and Install** + + ```bash + # Clone the repository + git clone https://github.com/Mail-0/Zero.git + cd Zero + ``` + + Then open the code in devcontainer and install the dependencies: + + ``` + pnpm install + + # Start the database locally + pnpm docker:db:up + ``` + +2. **Set Up Environment** + + - Run `pnpm nizzy env` to setup your environment variables + - Run `pnpm nizzy sync` to sync your environment variables and types + - Start the database with the provided docker compose setup: `pnpm docker:db:up` + - Initialize the database: `pnpm db:push` + +3. **Start The App** + ```bash + pnpm dev + ``` + Visit [http://localhost:3000](http://localhost:3000) +
+ ### Environment Setup 1. **Better Auth Setup** diff --git a/apps/mail/components/mail/mail-display.tsx b/apps/mail/components/mail/mail-display.tsx index a77119941..039f7ea03 100644 --- a/apps/mail/components/mail/mail-display.tsx +++ b/apps/mail/components/mail/mail-display.tsx @@ -16,7 +16,7 @@ import { import { memo, useEffect, useMemo, useState, useRef, useCallback } from 'react'; import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'; import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip'; -import { Briefcase, Star, StickyNote, Users, Lock } from 'lucide-react'; +import { Briefcase, Star, StickyNote, Users, Lock, Download, Printer } from 'lucide-react'; import { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'; import { useActiveConnection } from '@/hooks/use-connections'; import { handleUnsubscribe } from '@/lib/email-utils.client'; @@ -310,9 +310,9 @@ const MailDisplay = ({ emailData, index, totalEmails, demo }: Props) => { () => emailData.listUnsubscribe ? getListUnsubscribeAction({ - listUnsubscribe: emailData.listUnsubscribe, - listUnsubscribePost: emailData.listUnsubscribePost, - }) + listUnsubscribe: emailData.listUnsubscribe, + listUnsubscribePost: emailData.listUnsubscribePost, + }) : undefined, [emailData.listUnsubscribe, emailData.listUnsubscribePost], ); @@ -370,6 +370,347 @@ const MailDisplay = ({ emailData, index, totalEmails, demo }: Props) => { } }, [isCollapsed, preventCollapse, openDetailsPopover]); + // email printing + const printMail = () => { + try { + // Create a hidden iframe for printing + const printFrame = document.createElement('iframe'); + printFrame.style.position = 'absolute'; + printFrame.style.top = '-9999px'; + printFrame.style.left = '-9999px'; + printFrame.style.width = '0px'; + printFrame.style.height = '0px'; + printFrame.style.border = 'none'; + + document.body.appendChild(printFrame); + + // Generate clean, simple HTML content for printing + const printContent = ` + + + + + Print Email - ${emailData.subject || 'No Subject'} + + + +
+ +
+

${emailData.subject || 'No Subject'}

+ + ${emailData?.tags && emailData.tags.length > 0 ? ` +
+ ${emailData.tags.map(tag => + `${tag.name}` + ).join('')} +
+ ` : ''} + + +
+ +
+ + +
+ +
+ + + ${emailData.attachments && emailData.attachments.length > 0 ? ` +
+

Attachments (${emailData.attachments.length})

+ ${emailData.attachments.map((attachment, index) => ` +
+ ${attachment.filename} + ${formatFileSize(attachment.size) ? ` - ${formatFileSize(attachment.size)}` : ''} +
+ `).join('')} +
+ ` : ''} +
+ + + `; + + // Write content to the iframe + const iframeDoc = printFrame.contentDocument || printFrame.contentWindow.document; + iframeDoc.open(); + iframeDoc.write(printContent); + iframeDoc.close(); + + // Wait for content to load, then print + printFrame.onload = function () { + setTimeout(() => { + try { + // Focus the iframe and print + printFrame.contentWindow.focus(); + printFrame.contentWindow.print(); + + // Clean up - remove the iframe after a delay + setTimeout(() => { + if (printFrame && printFrame.parentNode) { + document.body.removeChild(printFrame); + } + }, 1000); + } catch (error) { + console.error('Error during print:', error); + // Clean up on error + if (printFrame && printFrame.parentNode) { + document.body.removeChild(printFrame); + } + } + }, 500); + }; + + } catch (error) { + console.error('Error printing email:', error); + alert('Failed to print email. Please try again.'); + } + }; + const renderPerson = useCallback( (person: Sender) => ( @@ -621,9 +962,29 @@ const MailDisplay = ({ emailData, index, totalEmails, demo }: Props) => { - +
+ + + + {/* print button */} + +

@@ -744,9 +1105,11 @@ const MailDisplay = ({ emailData, index, totalEmails, demo }: Props) => { >

+ {/* mail main body */} {emailData?.decodedBody ? ( ) : null} + {/* mail attachments */} {emailData?.attachments && emailData?.attachments.length > 0 ? (
{emailData?.attachments.map((attachment, index) => ( @@ -860,6 +1223,18 @@ const MailDisplay = ({ emailData, index, totalEmails, demo }: Props) => { f + {/* */}