nx-webmail: redesign login and force fullscreen webmail
Some checks failed
Publish nx-webmail Image (Gitea) / publish (push) Has been cancelled

This commit is contained in:
2026-02-23 13:25:41 +01:00
parent ecc0cd4b6c
commit 7f43441367
5 changed files with 70 additions and 144 deletions

View File

@@ -30,7 +30,7 @@ Umbrel installation is most reliable when your app uses a prebuilt image from a
- `git.weektab.org/nexus/nx-webmail:latest` - `git.weektab.org/nexus/nx-webmail:latest`
3. The workflow then pins `nx-webmail/docker-compose.yml` to `tag@sha256:digest` automatically. 3. The workflow then pins `nx-webmail/docker-compose.yml` to `tag@sha256:digest` automatically.
4. Manual fallback: 4. Manual fallback:
docker buildx build --platform linux/amd64,linux/arm64 -t git.weektab.org/nexus/nx-webmail:1.0.2 --push . docker buildx build --platform linux/amd64,linux/arm64 -t git.weektab.org/nexus/nx-webmail:1.0.3 --push .
## Umbrel app packaging ## Umbrel app packaging
@@ -55,7 +55,7 @@ This repository is prepared for Umbrel app-store usage.
Notes: Notes:
- Umbrel uses the `app_proxy` service in `docker-compose.yml`. - Umbrel uses the `app_proxy` service in `docker-compose.yml`.
- Internal app port is `3001`. - Internal app port is `3001`.
- `server` uses a prebuilt registry image (`git.weektab.org/nexus/nx-webmail:1.0.2`). - `server` uses a prebuilt registry image (`git.weektab.org/nexus/nx-webmail:1.0.3`).
- If your store prefix changes, update `id` in `umbrel-app.yml` and `APP_HOST` in `docker-compose.yml`. - If your store prefix changes, update `id` in `umbrel-app.yml` and `APP_HOST` in `docker-compose.yml`.
## Notes ## Notes

View File

@@ -7,7 +7,7 @@ services:
APP_PORT: 3001 APP_PORT: 3001
server: server:
image: git.weektab.org/nexus/nx-webmail:1.0.2@sha256:3ab2ab8c21bee911963254218dee65726df9579d5445a2063e16908a55d5c9e5 image: git.weektab.org/nexus/nx-webmail:1.0.3@sha256:78bcd3b7b8589fbcee065b0cdcc196907a98f747e7680e48f3cefd66478cbe3a
init: true init: true
restart: on-failure restart: on-failure
stop_grace_period: 1m stop_grace_period: 1m

View File

@@ -92,7 +92,6 @@ export default function Webmail() {
const [isEmptyingTrash, setIsEmptyingTrash] = useState(false); const [isEmptyingTrash, setIsEmptyingTrash] = useState(false);
const [selectedEmailIds, setSelectedEmailIds] = useState([]); const [selectedEmailIds, setSelectedEmailIds] = useState([]);
const [isDeletingSelected, setIsDeletingSelected] = useState(false); const [isDeletingSelected, setIsDeletingSelected] = useState(false);
const [isFullscreen, setIsFullscreen] = useState(false);
const [replyText, setReplyText] = useState(''); const [replyText, setReplyText] = useState('');
const [isSending, setIsSending] = useState(false); const [isSending, setIsSending] = useState(false);
@@ -1116,16 +1115,6 @@ export default function Webmail() {
}; };
}, []); }, []);
useEffect(() => {
const onKeyDown = (event) => {
if (event.key === 'Escape') {
setIsFullscreen(false);
}
};
window.addEventListener('keydown', onKeyDown);
return () => window.removeEventListener('keydown', onKeyDown);
}, []);
useEffect(() => { useEffect(() => {
if (!isLoggedIn || !activeAccountId || !activeFolder) return undefined; if (!isLoggedIn || !activeAccountId || !activeFolder) return undefined;
@@ -1448,18 +1437,9 @@ export default function Webmail() {
); );
const webmailWorkspace = ( const webmailWorkspace = (
<div className={`webmail-app ${isFullscreen ? 'webmail-app--fullscreen' : ''}`}> <div className="webmail-app webmail-app--fullscreen">
<div className="missive-sidebar"> <div className="missive-sidebar">
<div className="sidebar-header"> <div className="sidebar-header">
<div className="sidebar-actions">
<button
className="fullscreen-btn"
onClick={() => setIsFullscreen((prev) => !prev)}
title={isFullscreen ? 'Exit fullscreen' : 'Fullscreen'}
>
<i className={isFullscreen ? 'ri-fullscreen-exit-line' : 'ri-fullscreen-line'} />
</button>
</div>
<button <button
className={`add-btn ${isRefreshingInbox ? 'syncing' : ''}`} className={`add-btn ${isRefreshingInbox ? 'syncing' : ''}`}
onClick={handleManualRefresh} onClick={handleManualRefresh}
@@ -1789,20 +1769,19 @@ export default function Webmail() {
return ( return (
<> <>
<div className="webmail-stage">
<p>Webmail</p>
<h1>Mailbox and message management</h1>
<p>This layout uses the same page frame as the homepage.</p>
</div>
{!isLoggedIn ? ( {!isLoggedIn ? (
<div className="webmail-login-window-wrap"> <div className="webmail-login-page">
<div className="webmail-login-window"> <div className="webmail-login-panel">
<p className="webmail-login-kicker">Webmail</p>
<h1 className="webmail-login-title">Mailbox and message management</h1>
<p className="webmail-login-subtitle">Sign in with your IMAP account to start reading and sending email.</p>
<div className="webmail-login-form-wrap">
{loginForm} {loginForm}
</div> </div>
</div> </div>
</div>
) : ( ) : (
<div className="webmail-shell-scroll">{webmailWorkspace}</div> webmailWorkspace
)} )}
{isRestoringSession && ( {isRestoringSession && (

View File

@@ -72,7 +72,7 @@ body.webmail-active {
.sidebar-header { .sidebar-header {
padding: 16px 16px 12px 16px; padding: 16px 16px 12px 16px;
display: flex; display: flex;
justify-content: space-between; justify-content: flex-end;
align-items: center; align-items: center;
} }
@@ -1371,97 +1371,63 @@ body.webmail-active {
font-size: 14px; font-size: 14px;
margin-top: 40px; margin-top: 40px;
} }
.webmail-stage {
background: #ffffff;
border-radius: 16px;
padding: 24px 32px;
margin: 0 -4rem 2rem -4rem;
}
.webmail-stage p {
margin: 0 0 6px;
color: #667085;
}
.webmail-stage h1 {
margin: 0 0 8px;
font-size: 32px;
line-height: 1.2;
}
.webmail-hero-split {
display: flex;
gap: 24px;
align-items: flex-start;
background: #fff;
border-radius: 16px;
padding: 3rem;
margin: 0 -4rem 2rem -4rem;
}
.webmail-hero-split__left {
flex: 0 0 360px;
}
.webmail-hero-split__right {
flex: 1 1 auto;
}
.webmail-info-tile {
border: 1px solid #e5e7eb;
border-radius: 12px;
padding: 20px;
background: #fafafa;
}
.webmail-info-tile h3 {
margin: 0 0 12px;
}
.webmail-info-list {
margin: 0;
padding-left: 18px;
}
.webmail-info-list li {
margin-bottom: 8px;
}
.login-form--billing { .login-form--billing {
max-width: none; max-width: none;
width: 100%; width: 100%;
box-shadow: none; box-shadow: none !important;
border: 1px solid #e5e7eb; border: 1px solid #e5e7eb;
border-radius: 14px;
background: rgba(255, 255, 255, 0.94);
backdrop-filter: blur(4px);
} }
.webmail-login-window-wrap { .webmail-login-page {
min-height: 100vh;
width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: flex-start;
min-height: calc(100vh - 260px); padding: 48px clamp(20px, 6vw, 84px);
padding: 24px; background-image:
linear-gradient(90deg, rgba(10, 16, 28, 0.72) 0%, rgba(10, 16, 28, 0.54) 34%, rgba(10, 16, 28, 0.18) 62%, rgba(10, 16, 28, 0.08) 100%),
url('https://images.unsplash.com/photo-1516117172878-fd2c41f4a759?auto=format&fit=crop&w=2400&q=80');
background-size: cover;
background-position: center center;
background-repeat: no-repeat;
} }
.webmail-login-window { .webmail-login-panel {
width: min(100%, 520px);
color: #f8fafc;
}
.webmail-login-kicker {
margin: 0 0 12px;
font-size: 14px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: rgba(248, 250, 252, 0.86);
}
.webmail-login-title {
margin: 0;
font-size: clamp(32px, 4.2vw, 48px);
line-height: 1.08;
font-weight: 700;
color: #ffffff;
text-wrap: balance;
}
.webmail-login-subtitle {
margin: 14px 0 28px;
font-size: 15px;
line-height: 1.6;
color: rgba(248, 250, 252, 0.88);
max-width: 46ch;
}
.webmail-login-form-wrap {
width: min(100%, 460px); width: min(100%, 460px);
border-radius: 14px;
background: #ffffff;
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.12);
}
.webmail-login-window .login-form--billing {
border: 1px solid #e5e7eb;
border-radius: 14px;
box-shadow: none;
}
.webmail-shell-scroll {
width: auto;
overflow-x: auto;
background: #fff;
border-radius: 16px;
padding: 16px;
margin: 0 -4rem 2rem -4rem;
} }
.webmail-app { .webmail-app {
@@ -1504,37 +1470,18 @@ body.webmail-active {
} }
@media (max-width: 900px) { @media (max-width: 900px) {
.webmail-stage, .webmail-login-page {
.webmail-hero-split { align-items: flex-start;
margin-left: 0; padding: 24px 18px;
margin-right: 0; background-position: 58% center;
} }
.webmail-shell-scroll { .webmail-login-panel,
margin-left: 0; .webmail-login-form-wrap {
margin-right: 0;
}
.webmail-hero-split {
flex-direction: column;
padding: 24px;
}
.webmail-hero-split__left {
flex: 1 1 auto;
width: 100%; width: 100%;
} }
.webmail-stage { .webmail-login-title {
padding: 20px 24px; font-size: 30px;
}
.webmail-login-window-wrap {
min-height: auto;
padding: 0;
}
.webmail-login-window {
width: 100%;
} }
} }

View File

@@ -4,7 +4,7 @@ name: Webmail
tagline: Self-hosted IMAP/SMTP webmail client tagline: Self-hosted IMAP/SMTP webmail client
icon: logo.svg icon: logo.svg
category: utilities category: utilities
version: "1.0.2" version: "1.0.3"
port: 3001 port: 3001
description: >- description: >-
Webmail is a lightweight, self-hosted webmail app for connecting to external Webmail is a lightweight, self-hosted webmail app for connecting to external
@@ -17,7 +17,7 @@ repo: https://git.weektab.org/nexus/webmail
support: https://git.weektab.org/nexus/webmail/issues support: https://git.weektab.org/nexus/webmail/issues
gallery: [] gallery: []
releaseNotes: >- releaseNotes: >-
Centered login window layout and refreshed container image digest. Modernized login screen with left-aligned layout and forced fullscreen webmail.
dependencies: [] dependencies: []
path: "" path: ""
defaultUsername: "" defaultUsername: ""