astro-html 0.19.0 → 0.20.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.astro +91 -1
- package/index.js +60 -37
- package/package.json +1 -1
package/index.astro
CHANGED
|
@@ -114,6 +114,8 @@ if (failed) {
|
|
|
114
114
|
<html>
|
|
115
115
|
<head>
|
|
116
116
|
<title>Astro Email</title>
|
|
117
|
+
|
|
118
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
117
119
|
|
|
118
120
|
<Fragment
|
|
119
121
|
set:html={`
|
|
@@ -129,8 +131,14 @@ if (failed) {
|
|
|
129
131
|
</head>
|
|
130
132
|
|
|
131
133
|
<body>
|
|
134
|
+
<button id="mobile-menu-toggle" class="mobile-menu-toggle" aria-label="Toggle menu">
|
|
135
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
136
|
+
<path d="M3 12h18M3 6h18M3 18h18"/>
|
|
137
|
+
</svg>
|
|
138
|
+
</button>
|
|
139
|
+
|
|
132
140
|
<div class="layout">
|
|
133
|
-
<div class="sidebar">
|
|
141
|
+
<div class="sidebar" id="sidebar">
|
|
134
142
|
<div class="sidebar-header">
|
|
135
143
|
<h1>Templates</h1>
|
|
136
144
|
<button id="download-assets" class="download-button" data-has-assets="true">
|
|
@@ -289,6 +297,25 @@ if (failed) {
|
|
|
289
297
|
window.addEventListener("hashchange", () => {
|
|
290
298
|
showTemplate(location.hash.substring(1));
|
|
291
299
|
});
|
|
300
|
+
|
|
301
|
+
// Mobile menu toggle
|
|
302
|
+
const menuToggle = document.querySelector("#mobile-menu-toggle");
|
|
303
|
+
const sidebar = document.querySelector("#sidebar");
|
|
304
|
+
|
|
305
|
+
if (menuToggle && sidebar) {
|
|
306
|
+
menuToggle.addEventListener("click", () => {
|
|
307
|
+
sidebar.classList.toggle("open");
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Close sidebar when clicking a template link on mobile
|
|
311
|
+
document.querySelectorAll('.button a[href^="#"]').forEach(link => {
|
|
312
|
+
link.addEventListener("click", () => {
|
|
313
|
+
if (window.innerWidth <= 768) {
|
|
314
|
+
sidebar.classList.remove("open");
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
}
|
|
292
319
|
</script>
|
|
293
320
|
</div>
|
|
294
321
|
</div>
|
|
@@ -364,6 +391,8 @@ if (failed) {
|
|
|
364
391
|
box-sizing: border-box;
|
|
365
392
|
border-right: 1px solid #e0e0e0;
|
|
366
393
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
394
|
+
max-height: 100vh;
|
|
395
|
+
overflow-y: auto;
|
|
367
396
|
}
|
|
368
397
|
|
|
369
398
|
.sidebar-header {
|
|
@@ -495,6 +524,62 @@ if (failed) {
|
|
|
495
524
|
box-shadow: none;
|
|
496
525
|
}
|
|
497
526
|
|
|
527
|
+
.mobile-menu-toggle {
|
|
528
|
+
display: none;
|
|
529
|
+
position: fixed;
|
|
530
|
+
bottom: 20px;
|
|
531
|
+
right: 20px;
|
|
532
|
+
z-index: 1000;
|
|
533
|
+
width: 56px;
|
|
534
|
+
height: 56px;
|
|
535
|
+
border-radius: 50%;
|
|
536
|
+
background: #007bff;
|
|
537
|
+
color: white;
|
|
538
|
+
border: none;
|
|
539
|
+
box-shadow: 0 4px 12px rgba(0, 123, 255, 0.4);
|
|
540
|
+
cursor: pointer;
|
|
541
|
+
align-items: center;
|
|
542
|
+
justify-content: center;
|
|
543
|
+
transition: transform 0.2s;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
.mobile-menu-toggle:active {
|
|
547
|
+
transform: scale(0.95);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
@media (max-width: 768px) {
|
|
551
|
+
.layout {
|
|
552
|
+
grid-template-columns: 1fr;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
.sidebar {
|
|
556
|
+
position: fixed;
|
|
557
|
+
left: 0;
|
|
558
|
+
top: 0;
|
|
559
|
+
bottom: 0;
|
|
560
|
+
z-index: 999;
|
|
561
|
+
transform: translateX(-100%);
|
|
562
|
+
transition: transform 0.3s ease;
|
|
563
|
+
margin: 0;
|
|
564
|
+
border-radius: 0;
|
|
565
|
+
width: 280px;
|
|
566
|
+
max-width: 85vw;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
.sidebar.open {
|
|
570
|
+
transform: translateX(0);
|
|
571
|
+
box-shadow: 4px 0 12px rgba(0, 0, 0, 0.15);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
.mobile-menu-toggle {
|
|
575
|
+
display: flex;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.preview {
|
|
579
|
+
margin: 0;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
|
|
498
583
|
@media (prefers-color-scheme: dark) {
|
|
499
584
|
button {
|
|
500
585
|
border: 1px solid #4b4b4b;
|
|
@@ -516,6 +601,11 @@ if (failed) {
|
|
|
516
601
|
.download-button:disabled {
|
|
517
602
|
background: #6c757d;
|
|
518
603
|
}
|
|
604
|
+
|
|
605
|
+
.mobile-menu-toggle {
|
|
606
|
+
background: #0066cc;
|
|
607
|
+
box-shadow: 0 4px 12px rgba(0, 102, 204, 0.4);
|
|
608
|
+
}
|
|
519
609
|
}
|
|
520
610
|
</style>
|
|
521
611
|
</body>
|
package/index.js
CHANGED
|
@@ -12,33 +12,6 @@ import child_process from "node:child_process";
|
|
|
12
12
|
export default function email(options) {
|
|
13
13
|
return {
|
|
14
14
|
name: "email",
|
|
15
|
-
configureServer(server) {
|
|
16
|
-
server.middlewares.use((req, res, next) => {
|
|
17
|
-
const url = req.url;
|
|
18
|
-
if (!url) return next();
|
|
19
|
-
|
|
20
|
-
// Extract the filename from any sub-path
|
|
21
|
-
const segments = url.split("/").filter(Boolean);
|
|
22
|
-
const filename = segments[segments.length - 1];
|
|
23
|
-
|
|
24
|
-
// Only handle requests for files with extensions
|
|
25
|
-
if (filename?.includes(".")) {
|
|
26
|
-
const publicPath = path.join(process.cwd(), "public", filename);
|
|
27
|
-
|
|
28
|
-
if (fs.existsSync(publicPath)) {
|
|
29
|
-
const stat = fs.statSync(publicPath);
|
|
30
|
-
if (stat.isFile()) {
|
|
31
|
-
res.setHeader("Content-Length", stat.size);
|
|
32
|
-
const stream = fs.createReadStream(publicPath);
|
|
33
|
-
stream.pipe(res);
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
next();
|
|
40
|
-
});
|
|
41
|
-
},
|
|
42
15
|
hooks: {
|
|
43
16
|
"astro:config:setup": ({
|
|
44
17
|
command,
|
|
@@ -57,6 +30,7 @@ export default function email(options) {
|
|
|
57
30
|
plugins: [
|
|
58
31
|
react(),
|
|
59
32
|
optionsPlugin(false), // required for @astrojs/react/server.js to work.
|
|
33
|
+
publicAssetsPlugin(),
|
|
60
34
|
],
|
|
61
35
|
build: {
|
|
62
36
|
assetsInlineLimit: 1024 * 20, // inline all assets
|
|
@@ -78,12 +52,24 @@ export default function email(options) {
|
|
|
78
52
|
"astro:build:done": async ({ dir, pages }) => {
|
|
79
53
|
if (options.filename) {
|
|
80
54
|
const manifest = [];
|
|
55
|
+
const publicDir = path.resolve("public");
|
|
56
|
+
const publicFiles = [];
|
|
57
|
+
|
|
58
|
+
if (fs.existsSync(publicDir)) {
|
|
59
|
+
const files = fs.readdirSync(publicDir);
|
|
60
|
+
for (const file of files) {
|
|
61
|
+
const publicFilePath = path.resolve(publicDir, file);
|
|
62
|
+
if (fs.statSync(publicFilePath).isFile()) {
|
|
63
|
+
publicFiles.push(file);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
81
67
|
|
|
82
68
|
for (const page of pages) {
|
|
83
69
|
const pathname = page.pathname;
|
|
84
70
|
const basename = pathname.split(".")[0];
|
|
85
71
|
|
|
86
|
-
if (!pathname) continue;
|
|
72
|
+
if (!pathname) continue;
|
|
87
73
|
|
|
88
74
|
const name =
|
|
89
75
|
typeof options.filename === "string"
|
|
@@ -97,19 +83,24 @@ export default function email(options) {
|
|
|
97
83
|
|
|
98
84
|
const files = [name];
|
|
99
85
|
|
|
100
|
-
//
|
|
101
|
-
const
|
|
102
|
-
if (
|
|
103
|
-
const
|
|
86
|
+
// Copy public files to subdirectories if needed
|
|
87
|
+
const pathSegments = pathname.split("/").filter(Boolean);
|
|
88
|
+
if (pathSegments.length > 1) {
|
|
89
|
+
const subdirPath = path.resolve(
|
|
90
|
+
dir.pathname,
|
|
91
|
+
...pathSegments.slice(0, -1),
|
|
92
|
+
);
|
|
93
|
+
fs.mkdirSync(subdirPath, { recursive: true });
|
|
94
|
+
|
|
104
95
|
for (const publicFile of publicFiles) {
|
|
105
|
-
const
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
96
|
+
const targetPath = path.resolve(subdirPath, publicFile);
|
|
97
|
+
const sourcePath = path.resolve(publicDir, publicFile);
|
|
98
|
+
fs.copyFileSync(sourcePath, targetPath);
|
|
109
99
|
}
|
|
110
100
|
}
|
|
111
101
|
|
|
112
|
-
|
|
102
|
+
files.push(...publicFiles);
|
|
103
|
+
|
|
113
104
|
const jpgPath = path.resolve("src/pages", `${pathname}.jpg`);
|
|
114
105
|
if (fs.existsSync(jpgPath)) {
|
|
115
106
|
const newJpgName =
|
|
@@ -167,3 +158,35 @@ function optionsPlugin(experimentalReactChildren) {
|
|
|
167
158
|
},
|
|
168
159
|
};
|
|
169
160
|
}
|
|
161
|
+
|
|
162
|
+
/** @type {() => vite.Plugin} */
|
|
163
|
+
function publicAssetsPlugin() {
|
|
164
|
+
return {
|
|
165
|
+
name: "astro-html/public-assets",
|
|
166
|
+
configureServer(server) {
|
|
167
|
+
server.middlewares.use((req, res, next) => {
|
|
168
|
+
const url = req.url?.split("?")[0];
|
|
169
|
+
if (!url) return next();
|
|
170
|
+
|
|
171
|
+
const segments = url.split("/").filter(Boolean);
|
|
172
|
+
const filename = segments[segments.length - 1];
|
|
173
|
+
|
|
174
|
+
if (filename?.includes(".")) {
|
|
175
|
+
const publicPath = path.join(process.cwd(), "public", filename);
|
|
176
|
+
|
|
177
|
+
if (fs.existsSync(publicPath)) {
|
|
178
|
+
const stat = fs.statSync(publicPath);
|
|
179
|
+
if (stat.isFile()) {
|
|
180
|
+
res.setHeader("Content-Length", stat.size);
|
|
181
|
+
const stream = fs.createReadStream(publicPath);
|
|
182
|
+
stream.pipe(res);
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
next();
|
|
189
|
+
});
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
}
|