Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
e2b97b5
perf(server): parallelize and batch mail sync (#1788)
retrogtx Jul 26, 2025
8ad891d
Add user topics generation and label management (#1837)
MrgSub Jul 26, 2025
2015ef3
Add Effect language service and configure pretty logging (#1843)
MrgSub Jul 27, 2025
724cbb8
fix: auto-focus reply input when reply is triggered (#1841)
ayushsharma74 Jul 27, 2025
7cd0e40
Add auth validation and logging for API endpoints (#1844)
MrgSub Jul 27, 2025
7cd7d85
Optimize thread synchronization with rate limiting and concurrency co…
MrgSub Jul 28, 2025
a11d219
Update subscription expiration check to use database instead of KV st…
MrgSub Jul 28, 2025
2e46251
Add expired subscription handling for non-Google providers (#1847)
MrgSub Jul 28, 2025
b753afa
Remove brain state dependency and fix Gmail subscription key format (…
MrgSub Jul 28, 2025
180133f
Enable workflows in server configuration (#1849)
MrgSub Jul 28, 2025
e455bf0
Refactor thread workflow to use modular workflow engine (#1852)
MrgSub Jul 28, 2025
d043eaa
Refactor workflow processing to use durable objects for better concur…
MrgSub Jul 29, 2025
4c86d59
Fix WorkflowRunner to use this.env instead of global env (#1857)
MrgSub Jul 29, 2025
e9d32f4
fix: add draft generation check (#1855)
ahmetskilinc Jul 29, 2025
6a97621
feat: add a transition when user switches emails (#1854)
retrogtx Jul 29, 2025
4639fd9
Switch to Llama 4 Scout model and add delay in workflow execution (#1…
MrgSub Jul 29, 2025
e6165e8
Update thread labels workflow to use Llama 4 Scout model (#1860)
MrgSub Jul 29, 2025
def4234
Add bulk delete utility for Cloudflare KV keys in workflow processing…
MrgSub Jul 29, 2025
8807459
Integrate Sentry error monitoring for Cloudflare worker environment (…
MrgSub Jul 29, 2025
091bb5d
Replace Sentry with Cloudflare WorkerEntrypoint class (#1865)
MrgSub Jul 29, 2025
67a4cbf
Add local environment support to bulkDeleteKeys function (#1866)
MrgSub Jul 29, 2025
762895a
Pass results to workflow step condition function (#1867)
MrgSub Jul 29, 2025
15bbf89
Add Effect-free workflow implementation for direct Cloudflare Workers…
MrgSub Jul 29, 2025
f664c53
feat: sync threadId to ZeroAgent via WebSocket for multi-tab support …
devin-ai-integration[bot] Jul 30, 2025
9707613
feat: add email template management functionality (#1573)
retrogtx Jul 30, 2025
803a6ca
Implement workflow chain execution to share results between workflows…
MrgSub Jul 30, 2025
78987ea
Add email composition and sending tools to MCP agent (#1874)
MrgSub Jul 31, 2025
7572947
HMR fix (#1882)
ahmetskilinc Aug 1, 2025
908fdbb
feat: update translations via @LingoDotDev (#1858)
github-actions[bot] Aug 1, 2025
e1cdeb8
feat: add tests using playwright (#1877)
retrogtx Aug 1, 2025
b709dfc
Centralize env imports from cloudflare:workers (#1792)
devin-ai-integration[bot] Aug 1, 2025
bcf2d17
Integrate Dormroom for durable object management and queryable storag…
MrgSub Aug 1, 2025
824b232
fix: update locale keys for Chinese language support (#1878)
zhyd1997 Aug 1, 2025
1ea4bfe
Upgrade to Tailwind CSS v4 (#1881)
brandonmcconnell Aug 1, 2025
9a22f39
Pass thread context to AI chat via system messages instead of prompt …
MrgSub Aug 1, 2025
032006c
Add voice SSE endpoint and thread summary tool to MCP agent (#1884)
MrgSub Aug 1, 2025
0343c29
Allow SSE connections without X-Caller header (#1885)
MrgSub Aug 1, 2025
fd6a222
Allow SSE connections with system__caller_id (#1886)
MrgSub Aug 1, 2025
a34028c
Streamline email assistant prompt and add server-side tool execution …
MrgSub Aug 1, 2025
108dc8d
Make AutoRAG optional and improve thread summary fallback (#1888)
MrgSub Aug 1, 2025
e1e7624
Comment out unused constants and set default server URL (#1890)
MrgSub Aug 2, 2025
5723c62
Remove thread ID tracking and filter suggestion files (#1895)
MrgSub Aug 3, 2025
649eb45
Add thread context to AI chat and enhance security with locked prompt…
MrgSub Aug 3, 2025
99bc631
Remove unused variables and comment out getFolderLabelId function (#1…
MrgSub Aug 3, 2025
838057d
Fix toast styling (#1893)
brandonmcconnell Aug 3, 2025
c4b7517
Fix sizes and styles of AI sidebar icons (#1894)
brandonmcconnell Aug 3, 2025
c6fd1d8
fix: Trigger refetch() after label creation toast completes (#1889)
ayushsharma74 Aug 3, 2025
c3582d3
Remove hardcoded Cloudflare credentials from configuration files (#1898)
MrgSub Aug 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
217 changes: 217 additions & 0 deletions .cursor/rules/tailwind-css-v4.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
---
name: tailwind_v4
description: Guide for using Tailwind CSS v4 instead of v3.x
globs: ["**/*.{js,ts,jsx,tsx,mdx,css}"]
tags:
- tailwind
- css
---

# Tailwind CSS v4

## Core Changes

- **CSS-first configuration**: Configuration is now done in CSS instead of JavaScript
- Use `@theme` directive in CSS instead of `tailwind.config.js`
- Example:
```css
@import "tailwindcss";

@theme {
--font-display: "Satoshi", "sans-serif";
--breakpoint-3xl: 1920px;
--color-avocado-500: oklch(0.84 0.18 117.33);
--ease-fluid: cubic-bezier(0.3, 0, 0, 1);
}
```
- Legacy `tailwind.config.js` files can still be imported using the `@config` directive:
```css
@import "tailwindcss";
@config "../../tailwind.config.js";
```
- **CSS import syntax**: Use `@import "tailwindcss"` instead of `@tailwind` directives
- Old: `@tailwind base; @tailwind components; @tailwind utilities;`
- New: `@import "tailwindcss";`

- **Package changes**:
- PostCSS plugin is now `@tailwindcss/postcss` (not `tailwindcss`)
- CLI is now `@tailwindcss/cli`
- Vite plugin is `@tailwindcss/vite`
- No need for `postcss-import` or `autoprefixer` anymore

- **Native CSS cascade layers**: Uses real CSS `@layer` instead of Tailwind's custom implementation

## Theme Configuration

- **CSS theme variables**: All design tokens are available as CSS variables
- Namespace format: `--category-name` (e.g., `--color-blue-500`, `--font-sans`)
- Access in CSS: `var(--color-blue-500)`
- Available namespaces:
- `--color-*` : Color utilities like `bg-red-500` and `text-sky-300`
- `--font-*` : Font family utilities like `font-sans`
- `--text-*` : Font size utilities like `text-xl`
- `--font-weight-*` : Font weight utilities like `font-bold`
- `--tracking-*` : Letter spacing utilities like `tracking-wide`
- `--leading-*` : Line height utilities like `leading-tight`
- `--breakpoint-*` : Responsive breakpoint variants like `sm:*`
- `--container-*` : Container query variants like `@sm:*` and size utilities like `max-w-md`
- `--spacing-*` : Spacing and sizing utilities like `px-4` and `max-h-16`
- `--radius-*` : Border radius utilities like `rounded-sm`
- `--shadow-*` : Box shadow utilities like `shadow-md`
- `--inset-shadow-*` : Inset box shadow utilities like `inset-shadow-xs`
- `--drop-shadow-*` : Drop shadow filter utilities like `drop-shadow-md`
- `--blur-*` : Blur filter utilities like `blur-md`
- `--perspective-*` : Perspective utilities like `perspective-near`
- `--aspect-*` : Aspect ratio utilities like `aspect-video`
- `--ease-*` : Transition timing function utilities like `ease-out`
- `--animate-*` : Animation utilities like `animate-spin`


- **Simplified theme configuration**: Many utilities no longer need theme configuration
- Utilities like `grid-cols-12`, `z-40`, and `opacity-70` work without configuration
- Data attributes like `data-selected:opacity-100` don't need configuration

- **Dynamic spacing scale**: Derived from a single spacing value
- Default: `--spacing: 0.25rem`
- Every multiple of the base value is available (e.g., `mt-21` works automatically)

- **Overriding theme namespaces**:
- Override entire namespace: `--font-*: initial;`
- Override entire theme: `--*: initial;`


## New Features

- **Container query support**: Built-in now, no plugin needed
- `@container` for container context
- `@sm:`, `@md:`, etc. for container-based breakpoints
- `@max-md:` for max-width container queries
- Combine with `@min-md:@max-xl:hidden` for ranges

- **3D transforms**:
- `transform-3d` enables 3D transforms
- `rotate-x-*`, `rotate-y-*`, `rotate-z-*` for 3D rotation
- `scale-z-*` for z-axis scaling
- `translate-z-*` for z-axis translation
- `perspective-*` utilities (`perspective-near`, `perspective-distant`, etc.)
- `perspective-origin-*` utilities
- `backface-visible` and `backface-hidden`

- **Gradient enhancements**:
- Linear gradient angles: `bg-linear-45` (renamed from `bg-gradient-*`)
- Gradient interpolation: `bg-linear-to-r/oklch`, `bg-linear-to-r/srgb`
- Conic and radial gradients: `bg-conic`, `bg-radial-[at_25%_25%]`

- **Shadow enhancements**:
- `inset-shadow-*` and `inset-ring-*` utilities
- Can be composed with regular `shadow-*` and `ring-*`

- **New CSS property utilities**:
- `field-sizing-content` for auto-resizing textareas
- `scheme-light`, `scheme-dark` for `color-scheme` property
- `font-stretch-*` utilities for variable fonts

## New Variants

- **Composable variants**: Chain variants together
- Example: `group-has-data-potato:opacity-100`

- **New variants**:
- `starting` variant for `@starting-style` transitions
- `not-*` variant for `:not()` pseudo-class
- `inert` variant for `inert` attribute
- `nth-*` variants (`nth-3:`, `nth-last-5:`, `nth-of-type-4:`, `nth-last-of-type-6:`)
- `in-*` variant (like `group-*` but without adding `group` class)
- `open` variant now supports `:popover-open`
- `**` variant for targeting all descendants

## Custom Extensions

- **Custom utilities**: Use `@utility` directive
```css
@utility tab-4 {
tab-size: 4;
}
```

- **Custom variants**: Use `@variant` directive
```css
@variant pointer-coarse (@media (pointer: coarse));
@variant theme-midnight (&:where([data-theme="midnight"] *));
```

- **Plugins**: Use `@plugin` directive
```css
@plugin "@tailwindcss/typography";
```

## Breaking Changes

- **Removed deprecated utilities**:
- `bg-opacity-*` → Use `bg-black/50` instead
- `text-opacity-*` → Use `text-black/50` instead
- And others: `border-opacity-*`, `divide-opacity-*`, etc.

- **Renamed utilities**:
- `shadow-sm` → `shadow-xs` (and `shadow` → `shadow-sm`)
- `drop-shadow-sm` → `drop-shadow-xs` (and `drop-shadow` → `drop-shadow-sm`)
- `blur-sm` → `blur-xs` (and `blur` → `blur-sm`)
- `rounded-sm` → `rounded-xs` (and `rounded` → `rounded-sm`)
- `outline-none` → `outline-hidden` (for the old behavior)

- **Default style changes**:
- Default border color is now `currentColor` (was `gray-200`)
- Default `ring` width is now 1px (was 3px)
- Placeholder text now uses current color at 50% opacity (was `gray-400`)
- Hover styles only apply on devices that support hover (`@media (hover: hover)`)

- **Syntax changes**:
- CSS variables in arbitrary values: `bg-(--brand-color)` instead of `bg-[--brand-color]`
- Stacked variants now apply left-to-right (not right-to-left)
- Use CSS variables instead of `theme()` function

## Advanced Configuration

- **Using a prefix**:
```css
@import "tailwindcss" prefix(tw);
```
- Results in classes like `tw:flex`, `tw:bg-red-500`, `tw:hover:bg-red-600`

- **Source detection**:
- Automatic by default (ignores `.gitignore` files and binary files)
- Add sources: `@source "../node_modules/@my-company/ui-lib";`
- Disable automatic detection: `@import "tailwindcss" source(none);`

- **Legacy config files**:
```css
@import "tailwindcss";
@config "../../tailwind.config.js";
```

- **Dark mode configuration**:
```css
@import "tailwindcss";
@variant dark (&:where(.dark, .dark *));
```

- **Container customization**: Extend with `@utility`
```css
@utility container {
margin-inline: auto;
padding-inline: 2rem;
}
```

- **Using `@apply` in Vue/Svelte**:
```html
<style>
@import "../../my-theme.css" theme(reference);
/* or */
@import "tailwindcss/theme" theme(reference);

h1 {
@apply font-bold text-2xl text-red-500;
}
</style>
```
7 changes: 6 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,9 @@ AUTUMN_SECRET_KEY=

TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_PHONE_NUMBER=
TWILIO_PHONE_NUMBER=

# FOR PLAYWRIGHT E2E TESTING
PLAYWRIGHT_SESSION_TOKEN =
PLAYWRIGHT_SESSION_DATA =
EMAIL =
1 change: 0 additions & 1 deletion AGENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ This is a pnpm workspace monorepo with the following structure:
- `packages/cli/` - CLI tools (`nizzy` command)
- `packages/db/` - Database schemas and utilities
- `packages/eslint-config/` - Shared ESLint configuration
- `packages/tailwind-config/` - Shared Tailwind configuration
- `packages/tsconfig/` - Shared TypeScript configuration

## Frequently Used Commands
Expand Down
4 changes: 2 additions & 2 deletions apps/mail/app/(auth)/login/login-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ function LoginClientContent({ providers, isProd }: LoginClientProps) {

return (
<div className="flex min-h-screen w-full flex-col items-center justify-between bg-[#111111]">
<div className="animate-in slide-in-from-bottom-4 mx-auto flex max-w-[600px] flex-grow items-center justify-center space-y-8 px-4 duration-500 sm:px-12 md:px-0">
<div className="animate-in slide-in-from-bottom-4 mx-auto flex max-w-[600px] grow items-center justify-center space-y-8 px-4 duration-500 sm:px-12 md:px-0">
<div className="w-full space-y-4">
<p className="text-center text-4xl font-bold text-white md:text-5xl">Login to Zero</p>

Expand Down Expand Up @@ -203,7 +203,7 @@ function LoginClientContent({ providers, isProd }: LoginClientProps) {
<div
className={`overflow-hidden transition-all duration-300 ease-in-out ${expandedProviders[provider.id] ? 'max-h-[500px] opacity-100' : 'max-h-0 opacity-0'}`}
>
<div className="bg-black/[0.03] p-4 font-mono text-sm dark:bg-white/[0.03]">
<div className="bg-black/3 p-4 font-mono text-sm dark:bg-white/3">
{provider.envVarStatus.map((envVar) => (
<div
key={envVar.name}
Expand Down
2 changes: 1 addition & 1 deletion apps/mail/app/(full-width)/about.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function AboutPage() {
return (
<div className="relative flex min-h-screen w-full flex-col overflow-auto bg-white dark:bg-[#111111]">
<Navigation />
<div className="relative z-10 flex flex-grow flex-col">
<div className="relative z-10 flex grow flex-col">
<div className="absolute right-4 top-6 md:left-8 md:right-auto md:top-8">
<a href="/">
<Button
Expand Down
4 changes: 2 additions & 2 deletions apps/mail/app/(full-width)/contributors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ export default function OpenPage() {
</div>

{/* Project Stats */}
<div className="mb-8 overflow-hidden rounded-xl border bg-gradient-to-b from-white/50 to-white/10 p-6 backdrop-blur-sm dark:border-neutral-700 dark:from-neutral-900/50 dark:to-neutral-900/30">
<div className="mb-8 overflow-hidden rounded-xl border bg-linear-to-b from-white/50 to-white/10 p-6 backdrop-blur-sm dark:border-neutral-700 dark:from-neutral-900/50 dark:to-neutral-900/30">
<div className="flex flex-col items-start justify-between gap-4 sm:flex-row sm:items-center">
<div className="space-y-1">
<div className="flex items-center gap-2">
Expand Down Expand Up @@ -908,7 +908,7 @@ export default function OpenPage() {
</div>

<div className="mb-8">
<div className="relative overflow-hidden rounded-xl border bg-gradient-to-br from-neutral-50 to-white shadow-sm dark:border-neutral-800 dark:from-neutral-900/80 dark:to-neutral-900/30">
<div className="relative overflow-hidden rounded-xl border bg-linear-to-br from-neutral-50 to-white shadow-sm dark:border-neutral-800 dark:from-neutral-900/80 dark:to-neutral-900/30">
<div className="absolute inset-0 opacity-20 dark:opacity-20"></div>

<div className="relative p-6">
Expand Down
2 changes: 1 addition & 1 deletion apps/mail/app/(full-width)/privacy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default function PrivacyPolicy() {
return (
<div className="relative flex min-h-screen w-full flex-col overflow-auto bg-white dark:bg-[#111111]">
<Navigation />
<div className="relative z-10 flex flex-grow flex-col">
<div className="relative z-10 flex grow flex-col">
<div className="absolute right-4 top-6 md:left-8 md:right-auto md:top-8">
<a href="/">
<Button
Expand Down
2 changes: 1 addition & 1 deletion apps/mail/app/(full-width)/terms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function TermsOfService() {
return (
<div className="relative flex min-h-screen w-full flex-col overflow-auto bg-white dark:bg-[#111111]">
<Navigation />
<div className="relative z-10 flex flex-grow flex-col">
<div className="relative z-10 flex grow flex-col">
{/* Back Button */}
<div className="absolute right-4 top-6 md:left-8 md:top-8 md:right-auto">
<a href="/">
Expand Down
2 changes: 1 addition & 1 deletion apps/mail/app/(routes)/developer/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export default function DeveloperPage() {
<div className="bg-background flex min-h-screen w-full flex-col">
<div className="flex-1 overflow-y-auto">
<div className="mx-auto max-w-[1600px] p-4 md:p-6 lg:p-8">
<div className="bg-background/95 supports-[backdrop-filter]:bg-background/60 sticky top-0 z-10 mb-8 backdrop-blur">
<div className="bg-background/95 supports-backdrop-filter:bg-background/60 sticky top-0 z-10 mb-8 backdrop-blur">
<Button
variant="ghost"
size="sm"
Expand Down
27 changes: 24 additions & 3 deletions apps/mail/app/(routes)/settings/general/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { m } from '@/paraglide/messages';
import { cn } from '@/lib/utils';
import { toast } from 'sonner';
import * as z from 'zod';
import { useCallback } from 'react';

const TimezoneSelect = memo(
({ field }: { field: ControllerRenderProps<z.infer<typeof userSettingsSchema>, 'timezone'> }) => {
Expand All @@ -61,9 +62,9 @@ const TimezoneSelect = memo(
variant="outline"
role="combobox"
aria-expanded={open}
className="flex !h-9 w-full items-center justify-start rounded-md hover:bg-transparent"
className="flex h-9! w-full items-center justify-start rounded-md hover:bg-transparent"
>
<Clock className="mr-2 h-4 w-4 flex-shrink-0" />
<Clock className="mr-2 h-4 w-4 shrink-0" />
<span className="truncate">{field.value}</span>
</Button>
</FormControl>
Expand Down Expand Up @@ -134,6 +135,7 @@ export default function GeneralPage() {
customPrompt: '',
zeroSignature: true,
defaultEmailAlias: '',
animations: false,
},
});

Expand Down Expand Up @@ -178,6 +180,20 @@ export default function GeneralPage() {
}
}

const renderAnimationsField = useCallback(({ field }: { field: any }) => (
<FormItem className="flex max-w-xl flex-row items-center justify-between rounded-lg border p-3 shadow-sm">
<div className="space-y-0.5">
<FormLabel>{m['pages.settings.general.animations']()}</FormLabel>
<FormDescription>
{m['pages.settings.general.animationsDescription']()}
</FormDescription>
</div>
<FormControl>
<Switch checked={field.value} onCheckedChange={field.onChange} />
</FormControl>
</FormItem>
), []);

return (
<div className="grid gap-6">
<SettingsCard
Expand Down Expand Up @@ -232,7 +248,7 @@ export default function GeneralPage() {
name="defaultEmailAlias"
render={({ field }) => (
<FormItem className="w-full md:w-[280px]">
<FormLabel className="!mb-1 flex flex-row items-center gap-1 text-sm font-medium">
<FormLabel className="mb-1! flex flex-row items-center gap-1 text-sm font-medium">
{m['pages.settings.general.defaultEmailAlias']()}{' '}
<Tooltip>
<TooltipTrigger asChild>
Expand Down Expand Up @@ -307,6 +323,11 @@ export default function GeneralPage() {
</FormItem>
)}
/>
<FormField
control={form.control}
name="animations"
render={renderAnimationsField}
/>
</form>
</Form>
</SettingsCard>
Expand Down
2 changes: 1 addition & 1 deletion apps/mail/app/(routes)/settings/labels/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export default function LabelsPage() {
<span>{label.name}</span>
</Badge>
</div>
<div className="dark:bg-panelDark absolute right-2 z-[25] flex items-center gap-1 rounded-xl border bg-white p-1 opacity-0 shadow-sm transition-opacity group-hover:opacity-100">
<div className="dark:bg-panelDark absolute right-2 z-25 flex items-center gap-1 rounded-xl border bg-white p-1 opacity-0 shadow-sm transition-opacity group-hover:opacity-100">
<Tooltip>
<TooltipTrigger asChild>
<Button
Expand Down
Loading