فهرست منبع

feat: add mailbox app (inbox, read, compose)

Three-page mailbox suite, restoring functionality from v3:

- mailbox/inbox.html    Folder rail (Inbox / Sent / Drafts / Starred /
                       Archive / Spam / Trash) with badge counts, label
                       chips, bulk-action toolbar, unread row state,
                       search.
- mailbox/read.html     Sender meta, message body, attachment chips,
                       reply / forward / archive / delete actions.
- mailbox/compose.html  To / Cc / Bcc / Subject / Body / Attachments
                       form. Hooks for plugging in a rich-text editor
                       are documented in the field hint.

Pure Bootstrap 5, no custom CSS, no external dependencies.
Aigars Silkalns 20 ساعت پیش
والد
کامیت
80adf15d6a
3فایلهای تغییر یافته به همراه618 افزوده شده و 0 حذف شده
  1. 127 0
      src/html/pages/mailbox/compose.astro
  2. 302 0
      src/html/pages/mailbox/inbox.astro
  3. 189 0
      src/html/pages/mailbox/read.astro

+ 127 - 0
src/html/pages/mailbox/compose.astro

@@ -0,0 +1,127 @@
+---
+import Head from "@components/_head.astro"
+import Footer from "@components/dashboard/_footer.astro"
+import Topbar from "@components/dashboard/_topbar.astro"
+import Sidenav from "@components/dashboard/_sidenav.astro"
+import Scripts from "@components/_scripts.astro"
+
+const title = "AdminLTE 4 | Mailbox - Compose"
+const path = "../../../dist"
+const htmlPath = ".."
+const mainPage = "mailbox"
+const page = "compose";
+---
+
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <Head title={title} path={path} />
+  </head>
+  <body class="layout-fixed sidebar-expand-lg bg-body-tertiary">
+    <div class="app-wrapper">
+      <Topbar path={path} />
+      <Sidenav path={path} mainPage={mainPage} page={page} />
+      <main class="app-main">
+        <div class="app-content-header">
+          <div class="container-fluid">
+            <div class="row">
+              <div class="col-sm-6">
+                <h3 class="mb-0">Compose Message</h3>
+              </div>
+              <div class="col-sm-6">
+                <ol class="breadcrumb float-sm-end">
+                  <li class="breadcrumb-item"><a href="#">Home</a></li>
+                  <li class="breadcrumb-item">
+                    <a href={htmlPath + "/mailbox/inbox.html"}>Mailbox</a>
+                  </li>
+                  <li class="breadcrumb-item active" aria-current="page">Compose</li>
+                </ol>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="app-content">
+          <div class="container-fluid">
+            <div class="card">
+              <div class="card-header">
+                <h3 class="card-title">New Message</h3>
+              </div>
+              <div class="card-body">
+                <form class="row g-3">
+                  <div class="col-12">
+                    <label class="form-label" for="mail-to">To</label>
+                    <input
+                      type="email"
+                      class="form-control"
+                      id="mail-to"
+                      placeholder="recipient@example.com"
+                    />
+                  </div>
+                  <div class="col-md-6">
+                    <label class="form-label" for="mail-cc">Cc</label>
+                    <input type="text" class="form-control" id="mail-cc" />
+                  </div>
+                  <div class="col-md-6">
+                    <label class="form-label" for="mail-bcc">Bcc</label>
+                    <input type="text" class="form-control" id="mail-bcc" />
+                  </div>
+                  <div class="col-12">
+                    <label class="form-label" for="mail-subject">Subject</label>
+                    <input type="text" class="form-control" id="mail-subject" />
+                  </div>
+                  <div class="col-12">
+                    <label class="form-label" for="mail-body">Message</label>
+                    <textarea
+                      id="mail-body"
+                      class="form-control"
+                      rows="12"
+                      placeholder="Write your message&hellip;"
+                      style="min-height: 16rem;"></textarea>
+                    <small class="text-secondary">
+                      Hook up a rich-text editor such as
+                      <a
+                        href="https://quilljs.com/"
+                        target="_blank"
+                        rel="noopener">Quill</a
+                      >
+                      or
+                      <a
+                        href="https://github.com/Ionaru/easy-markdown-editor"
+                        target="_blank"
+                        rel="noopener">EasyMDE</a
+                      >
+                      to upgrade this textarea.
+                    </small>
+                  </div>
+                  <div class="col-12">
+                    <label class="form-label" for="mail-attach">Attachments</label>
+                    <input
+                      type="file"
+                      class="form-control"
+                      id="mail-attach"
+                      multiple
+                    />
+                  </div>
+                </form>
+              </div>
+              <div class="card-footer d-flex gap-2">
+                <button class="btn btn-primary" type="button">
+                  <i class="bi bi-send me-1" aria-hidden="true"></i>Send
+                </button>
+                <button class="btn btn-outline-secondary" type="button">
+                  <i class="bi bi-file-earmark me-1" aria-hidden="true"></i>
+                  Save draft
+                </button>
+                <button class="btn btn-outline-danger ms-auto" type="button">
+                  <i class="bi bi-x-lg me-1" aria-hidden="true"></i>Discard
+                </button>
+              </div>
+            </div>
+          </div>
+        </div>
+      </main>
+      <Footer />
+    </div>
+    <Scripts path={path} />
+  </body>
+</html>

+ 302 - 0
src/html/pages/mailbox/inbox.astro

@@ -0,0 +1,302 @@
+---
+import Head from "@components/_head.astro"
+import Footer from "@components/dashboard/_footer.astro"
+import Topbar from "@components/dashboard/_topbar.astro"
+import Sidenav from "@components/dashboard/_sidenav.astro"
+import Scripts from "@components/_scripts.astro"
+
+const title = "AdminLTE 4 | Mailbox"
+const path = "../../../dist"
+const htmlPath = ".."
+const mainPage = "mailbox"
+const page = "inbox";
+
+const messages = [
+  { from: "Olivia Bennett", subject: "Re: design system v2.4 sign-off", preview: "Approved — a few small notes on the success state for forms.", time: "10:42 AM", unread: true, starred: true, label: "primary" },
+  { from: "GitHub", subject: "[fullcalendar/fullcalendar] PR #6912 merged", preview: "Allow custom render hooks for time grid axis labels.", time: "9:08 AM", unread: true, starred: false, label: "secondary" },
+  { from: "Stripe", subject: "Your May invoice is ready", preview: "Invoice INV-2026-00428 totaling $108.31 has been issued.", time: "8:15 AM", unread: true, starred: false, label: "success" },
+  { from: "Marcus Reyes", subject: "Lunch on Thursday?", preview: "Free around 1pm at the usual place. Let me know.", time: "Yesterday", unread: false, starred: true, label: "info" },
+  { from: "Linear", subject: "[ADM-441] Calendar drag-and-drop not working on Safari iOS", preview: "Reproduces consistently on iOS 18.4 in Safari and Chrome.", time: "Yesterday", unread: false, starred: false, label: "warning" },
+  { from: "Vercel", subject: "Deployment succeeded — production", preview: "main@a3c91fb deployed to production in 47s.", time: "May 16", unread: false, starred: false, label: "success" },
+  { from: "Sara Khan", subject: "Customer interview notes — Acme Corp", preview: "Three big themes: onboarding friction, billing visibility, mobile.", time: "May 15", unread: false, starred: false, label: "primary" },
+  { from: "AWS", subject: "Your monthly bill summary", preview: "Total charges for April 2026: $312.94. View in console.", time: "May 14", unread: false, starred: false, label: "danger" }
+];
+---
+
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <Head title={title} path={path} />
+  </head>
+  <body class="layout-fixed sidebar-expand-lg bg-body-tertiary">
+    <div class="app-wrapper">
+      <Topbar path={path} />
+      <Sidenav path={path} mainPage={mainPage} page={page} />
+      <main class="app-main">
+        <div class="app-content-header">
+          <div class="container-fluid">
+            <div class="row">
+              <div class="col-sm-6">
+                <h3 class="mb-0">Mailbox</h3>
+              </div>
+              <div class="col-sm-6">
+                <ol class="breadcrumb float-sm-end">
+                  <li class="breadcrumb-item"><a href="#">Home</a></li>
+                  <li class="breadcrumb-item active" aria-current="page">Inbox</li>
+                </ol>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="app-content">
+          <div class="container-fluid">
+            <div class="row g-3">
+              <!-- Folder sidebar -->
+              <div class="col-lg-3">
+                <a
+                  href={htmlPath + "/mailbox/compose.html"}
+                  class="btn btn-primary w-100 mb-3"
+                >
+                  <i class="bi bi-pencil-square me-1" aria-hidden="true"></i>
+                  Compose
+                </a>
+                <div class="card">
+                  <div class="card-header">
+                    <h3 class="card-title">Folders</h3>
+                  </div>
+                  <div class="card-body p-0">
+                    <ul class="nav nav-pills flex-column mb-0">
+                      <li class="nav-item">
+                        <a
+                          href={htmlPath + "/mailbox/inbox.html"}
+                          class="nav-link active rounded-0 d-flex justify-content-between"
+                        >
+                          <span>
+                            <i class="bi bi-inbox me-2" aria-hidden="true"></i>Inbox
+                          </span>
+                          <span class="badge text-bg-primary">3</span>
+                        </a>
+                      </li>
+                      <li class="nav-item">
+                        <a href="#" class="nav-link rounded-0">
+                          <i class="bi bi-send me-2" aria-hidden="true"></i>Sent
+                        </a>
+                      </li>
+                      <li class="nav-item">
+                        <a
+                          href="#"
+                          class="nav-link rounded-0 d-flex justify-content-between"
+                        >
+                          <span>
+                            <i class="bi bi-file-earmark me-2" aria-hidden="true"></i>
+                            Drafts
+                          </span>
+                          <span class="badge text-bg-secondary">2</span>
+                        </a>
+                      </li>
+                      <li class="nav-item">
+                        <a href="#" class="nav-link rounded-0">
+                          <i class="bi bi-star me-2" aria-hidden="true"></i>Starred
+                        </a>
+                      </li>
+                      <li class="nav-item">
+                        <a href="#" class="nav-link rounded-0">
+                          <i class="bi bi-archive me-2" aria-hidden="true"></i>Archive
+                        </a>
+                      </li>
+                      <li class="nav-item">
+                        <a href="#" class="nav-link rounded-0">
+                          <i
+                            class="bi bi-exclamation-octagon me-2"
+                            aria-hidden="true"
+                          ></i>
+                          Spam
+                        </a>
+                      </li>
+                      <li class="nav-item">
+                        <a href="#" class="nav-link rounded-0">
+                          <i class="bi bi-trash me-2" aria-hidden="true"></i>Trash
+                        </a>
+                      </li>
+                    </ul>
+                  </div>
+                </div>
+                <div class="card mt-3">
+                  <div class="card-header">
+                    <h3 class="card-title">Labels</h3>
+                  </div>
+                  <div class="card-body p-0">
+                    <ul class="nav flex-column mb-0">
+                      <li class="nav-item">
+                        <a href="#" class="nav-link">
+                          <i
+                            class="bi bi-circle-fill text-primary me-2"
+                            style="font-size: 0.6rem;"
+                            aria-hidden="true"
+                          ></i>
+                          Customers
+                        </a>
+                      </li>
+                      <li class="nav-item">
+                        <a href="#" class="nav-link">
+                          <i
+                            class="bi bi-circle-fill text-success me-2"
+                            style="font-size: 0.6rem;"
+                            aria-hidden="true"
+                          ></i>
+                          Billing
+                        </a>
+                      </li>
+                      <li class="nav-item">
+                        <a href="#" class="nav-link">
+                          <i
+                            class="bi bi-circle-fill text-warning me-2"
+                            style="font-size: 0.6rem;"
+                            aria-hidden="true"
+                          ></i>
+                          Internal
+                        </a>
+                      </li>
+                    </ul>
+                  </div>
+                </div>
+              </div>
+
+              <!-- Inbox list -->
+              <div class="col-lg-9">
+                <div class="card">
+                  <div class="card-header">
+                    <h3 class="card-title">Inbox</h3>
+                    <div class="card-tools">
+                      <div class="input-group input-group-sm" style="width: 16rem;">
+                        <span class="input-group-text">
+                          <i class="bi bi-search" aria-hidden="true"></i>
+                        </span>
+                        <input
+                          type="search"
+                          class="form-control"
+                          placeholder="Search mail&hellip;"
+                          aria-label="Search mail"
+                        />
+                      </div>
+                    </div>
+                  </div>
+                  <div class="card-body p-0">
+                    <div
+                      class="d-flex align-items-center px-3 py-2 border-bottom"
+                    >
+                      <div class="form-check mb-0">
+                        <input
+                          class="form-check-input"
+                          type="checkbox"
+                          id="select-all"
+                        />
+                        <label class="form-check-label visually-hidden" for="select-all">
+                          Select all
+                        </label>
+                      </div>
+                      <div class="btn-group btn-group-sm ms-3">
+                        <button
+                          class="btn btn-outline-secondary"
+                          type="button"
+                          title="Refresh"
+                        >
+                          <i class="bi bi-arrow-clockwise" aria-hidden="true"></i>
+                        </button>
+                        <button
+                          class="btn btn-outline-secondary"
+                          type="button"
+                          title="Archive"
+                        >
+                          <i class="bi bi-archive" aria-hidden="true"></i>
+                        </button>
+                        <button
+                          class="btn btn-outline-secondary"
+                          type="button"
+                          title="Mark as spam"
+                        >
+                          <i class="bi bi-exclamation-octagon" aria-hidden="true"></i>
+                        </button>
+                        <button
+                          class="btn btn-outline-secondary"
+                          type="button"
+                          title="Delete"
+                        >
+                          <i class="bi bi-trash" aria-hidden="true"></i>
+                        </button>
+                      </div>
+                      <span class="ms-auto text-secondary small">
+                        1&ndash;{messages.length} of {messages.length}
+                      </span>
+                    </div>
+                    <ul class="list-group list-group-flush mb-0">
+                      {
+                        messages.map((m, idx) => (
+                          <li
+                            class:list={[
+                              "list-group-item d-flex align-items-center gap-2",
+                              m.unread && "fw-semibold bg-body-secondary"
+                            ]}
+                          >
+                            <div class="form-check mb-0">
+                              <input
+                                class="form-check-input"
+                                type="checkbox"
+                                id={`msg-${idx}`}
+                              />
+                              <label
+                                class="form-check-label visually-hidden"
+                                for={`msg-${idx}`}
+                              >
+                                Select message from {m.from}
+                              </label>
+                            </div>
+                            <button
+                              class="btn btn-link p-0 text-warning lh-1"
+                              type="button"
+                              title={m.starred ? "Starred" : "Star"}
+                              aria-label={m.starred ? "Starred" : "Star"}
+                            >
+                              <i
+                                class={
+                                  m.starred ? "bi bi-star-fill" : "bi bi-star"
+                                }
+                                aria-hidden="true"
+                              />
+                            </button>
+                            <a
+                              href={htmlPath + "/mailbox/read.html"}
+                              class="flex-grow-1 d-flex flex-column flex-md-row gap-md-3 text-decoration-none text-body"
+                            >
+                              <span class="text-truncate" style="min-width: 9rem;">
+                                {m.from}
+                              </span>
+                              <span class="flex-grow-1 text-truncate">
+                                <span class={`badge text-bg-${m.label} me-2`}>
+                                  &middot;
+                                </span>
+                                {m.subject}
+                                <span class="fw-normal text-secondary">
+                                  &nbsp;&mdash; {m.preview}
+                                </span>
+                              </span>
+                              <span class="text-secondary small text-md-end" style="min-width: 5rem;">
+                                {m.time}
+                              </span>
+                            </a>
+                          </li>
+                        ))
+                      }
+                    </ul>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </main>
+      <Footer />
+    </div>
+    <Scripts path={path} />
+  </body>
+</html>

+ 189 - 0
src/html/pages/mailbox/read.astro

@@ -0,0 +1,189 @@
+---
+import Head from "@components/_head.astro"
+import Footer from "@components/dashboard/_footer.astro"
+import Topbar from "@components/dashboard/_topbar.astro"
+import Sidenav from "@components/dashboard/_sidenav.astro"
+import Scripts from "@components/_scripts.astro"
+
+const title = "AdminLTE 4 | Mailbox - Read"
+const path = "../../../dist"
+const htmlPath = ".."
+const mainPage = "mailbox"
+const page = "read";
+---
+
+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <Head title={title} path={path} />
+  </head>
+  <body class="layout-fixed sidebar-expand-lg bg-body-tertiary">
+    <div class="app-wrapper">
+      <Topbar path={path} />
+      <Sidenav path={path} mainPage={mainPage} page={page} />
+      <main class="app-main">
+        <div class="app-content-header">
+          <div class="container-fluid">
+            <div class="row">
+              <div class="col-sm-6">
+                <h3 class="mb-0">Read Message</h3>
+              </div>
+              <div class="col-sm-6">
+                <ol class="breadcrumb float-sm-end">
+                  <li class="breadcrumb-item"><a href="#">Home</a></li>
+                  <li class="breadcrumb-item">
+                    <a href={htmlPath + "/mailbox/inbox.html"}>Mailbox</a>
+                  </li>
+                  <li class="breadcrumb-item active" aria-current="page">Read</li>
+                </ol>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div class="app-content">
+          <div class="container-fluid">
+            <div class="card">
+              <div class="card-header d-flex justify-content-between align-items-center">
+                <h3 class="card-title">Re: design system v2.4 sign-off</h3>
+                <div class="btn-group btn-group-sm">
+                  <a
+                    href={htmlPath + "/mailbox/inbox.html"}
+                    class="btn btn-outline-secondary"
+                    title="Back to inbox"
+                  >
+                    <i class="bi bi-arrow-left" aria-hidden="true"></i>
+                  </a>
+                  <button
+                    class="btn btn-outline-secondary"
+                    type="button"
+                    title="Previous"
+                  >
+                    <i class="bi bi-chevron-up" aria-hidden="true"></i>
+                  </button>
+                  <button
+                    class="btn btn-outline-secondary"
+                    type="button"
+                    title="Next"
+                  >
+                    <i class="bi bi-chevron-down" aria-hidden="true"></i>
+                  </button>
+                </div>
+              </div>
+              <div class="card-body">
+                <!-- Sender meta -->
+                <div class="d-flex gap-3 align-items-start mb-4">
+                  <div
+                    class="flex-shrink-0 rounded-circle bg-primary-subtle text-primary d-flex align-items-center justify-content-center"
+                    style="width: 48px; height: 48px;"
+                    aria-hidden="true"
+                  >
+                    OB
+                  </div>
+                  <div class="flex-grow-1">
+                    <div class="d-flex justify-content-between">
+                      <div>
+                        <p class="mb-0 fw-semibold">Olivia Bennett</p>
+                        <small class="text-secondary">
+                          olivia@example.com &mdash; to me
+                        </small>
+                      </div>
+                      <small class="text-secondary">10:42 AM &middot; 2 hours ago</small>
+                    </div>
+                  </div>
+                </div>
+
+                <!-- Body -->
+                <div class="mb-4">
+                  <p>Hey Jane,</p>
+                  <p>
+                    Reviewed the v2.4 candidate this morning. Overall: looks
+                    great, ready to ship pending two small notes:
+                  </p>
+                  <ol>
+                    <li>
+                      Success state on form inputs feels a touch light against
+                      <code>bg-body-tertiary</code>. Can we bump the border
+                      contrast by ~10%?
+                    </li>
+                    <li>
+                      The new focus ring is lovely on light theme but barely
+                      visible on dark. Worth a quick a11y pass before we cut the
+                      release.
+                    </li>
+                  </ol>
+                  <p>
+                    Otherwise, big +1. Customers are going to love the
+                    motion primitives.
+                  </p>
+                  <p class="mb-0">
+                    Olivia<br />
+                    <small class="text-secondary">Sent from my laptop</small>
+                  </p>
+                </div>
+
+                <!-- Attachments -->
+                <h6 class="fw-semibold">Attachments (2)</h6>
+                <div class="row g-2 mb-3">
+                  <div class="col-md-6">
+                    <div class="card">
+                      <div class="card-body py-2 px-3 d-flex align-items-center gap-2">
+                        <i
+                          class="bi bi-file-earmark-pdf-fill text-danger fs-3"
+                          aria-hidden="true"
+                        ></i>
+                        <div class="flex-grow-1">
+                          <p class="mb-0 small fw-semibold">design-review.pdf</p>
+                          <small class="text-secondary">1.4 MB</small>
+                        </div>
+                        <a href="#" class="btn btn-sm btn-outline-secondary">
+                          <i class="bi bi-download" aria-hidden="true"></i>
+                        </a>
+                      </div>
+                    </div>
+                  </div>
+                  <div class="col-md-6">
+                    <div class="card">
+                      <div class="card-body py-2 px-3 d-flex align-items-center gap-2">
+                        <i
+                          class="bi bi-file-earmark-image-fill text-primary fs-3"
+                          aria-hidden="true"
+                        ></i>
+                        <div class="flex-grow-1">
+                          <p class="mb-0 small fw-semibold">focus-ring-dark.png</p>
+                          <small class="text-secondary">320 KB</small>
+                        </div>
+                        <a href="#" class="btn btn-sm btn-outline-secondary">
+                          <i class="bi bi-download" aria-hidden="true"></i>
+                        </a>
+                      </div>
+                    </div>
+                  </div>
+                </div>
+              </div>
+              <div class="card-footer d-flex gap-2">
+                <a
+                  href={htmlPath + "/mailbox/compose.html"}
+                  class="btn btn-primary"
+                >
+                  <i class="bi bi-reply me-1" aria-hidden="true"></i>Reply
+                </a>
+                <button class="btn btn-outline-secondary" type="button">
+                  <i class="bi bi-arrow-90deg-right me-1" aria-hidden="true"></i>
+                  Forward
+                </button>
+                <button class="btn btn-outline-secondary ms-auto" type="button">
+                  <i class="bi bi-archive me-1" aria-hidden="true"></i>Archive
+                </button>
+                <button class="btn btn-outline-danger" type="button">
+                  <i class="bi bi-trash me-1" aria-hidden="true"></i>Delete
+                </button>
+              </div>
+            </div>
+          </div>
+        </div>
+      </main>
+      <Footer />
+    </div>
+    <Scripts path={path} />
+  </body>
+</html>