@lexho111/plainblog 0.5.27 → 0.5.28

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/Blog.js CHANGED
@@ -10,6 +10,7 @@ import path from "path";
10
10
  import { fileURLToPath } from "url";
11
11
  import { compileStyles, mergeStyles } from "./build-styles.js";
12
12
  import pkg from "./package.json" with { type: "json" };
13
+ import process from 'node:process';
13
14
 
14
15
  export default class Blog {
15
16
  constructor() {
@@ -166,9 +167,9 @@ export default class Blog {
166
167
  res.writeHead(401, { "Content-Type": "text/html" });
167
168
  res.end(`${header("My Blog")}
168
169
  <body>
169
- <h1>Unauthorized</h1><p>Please enter the password.<form method="POST">
170
+ <h1>Unauthorized</h1><div class="box"><p>Please enter the password.<form method="POST">
170
171
  <input type="password" name="password" placeholder="Password" />
171
- <button style="margin: 2px;">Login</button></form>
172
+ <button style="margin: 2px;">Login</button></form></div>
172
173
  </body></html>`);
173
174
  }
174
175
  }
@@ -210,7 +211,7 @@ export default class Blog {
210
211
  const __filename = fileURLToPath(import.meta.url);
211
212
  const __dirname = path.dirname(__filename);
212
213
  const srcStylePath = path.join(__dirname, "src", "styles.css");
213
- const publicStylePath = path.join(__dirname, "public", "styles.min.css");
214
+ const publicStylePath = path.join(process.cwd(), "public", "styles.min.css");
214
215
 
215
216
  let publicHash = null;
216
217
  let srcStyles = "";
@@ -243,7 +244,7 @@ export default class Blog {
243
244
  console.log("Styles have changed. Recompiling...");
244
245
  const finalStyles = await mergeStyles(this.#styles, srcStyles);
245
246
  try {
246
- //await fs.promises.mkdir(path.dirname(publicStylePath), { recursive: true });
247
+ await fs.promises.mkdir(path.dirname(publicStylePath), { recursive: true });
247
248
  await fs.promises.writeFile(
248
249
  publicStylePath,
249
250
  finalStyles + `\n/* source-hash: ${srcHash} */`
@@ -355,9 +356,9 @@ export default class Blog {
355
356
  res.writeHead(200, { "Content-Type": "text/html" });
356
357
  res.end(`${header("My Blog")}
357
358
  <body>
358
- <h1>Login</h1><form method="POST">
359
+ <h1>Login</h1><div class="box"><form method="POST">
359
360
  <input type="password" name="password" placeholder="Password" />
360
- <button style="margin: 2px;">Login</button></form>
361
+ <button style="margin: 2px;">Login</button></form></div>
361
362
  </body></html>`);
362
363
  return;
363
364
  } else if (req.method === "POST") {
@@ -410,9 +411,7 @@ export default class Blog {
410
411
  } else {
411
412
  // Try to serve static files from public folder
412
413
  try {
413
- const __filename = fileURLToPath(import.meta.url);
414
- const __dirname = path.dirname(__filename);
415
- const publicDir = path.join(__dirname, "public");
414
+ const publicDir = path.join(process.cwd(), "public");
416
415
  const parsedUrl = new URL(
417
416
  req.url,
418
417
  `http://${req.headers.host || "localhost"}`
@@ -648,10 +647,9 @@ export default class Blog {
648
647
  this.compiledStyles = await compileStyles(fileData);
649
648
 
650
649
  // generate a file
651
- const __filename = fileURLToPath(import.meta.url);
652
- const __dirname = path.dirname(__filename);
653
- const publicDir = path.join(__dirname, "public");
650
+ const publicDir = path.join(process.cwd(), "public");
654
651
 
652
+ await fs.promises.mkdir(publicDir, { recursive: true });
655
653
  await fs.promises.writeFile(
656
654
  path.join(publicDir, "styles.min.css"),
657
655
  this.compiledStyles + `\n/* source-hash: ${currentHash} */`
package/Formatter.js CHANGED
@@ -27,11 +27,13 @@ export function formatHTML(data) {
27
27
  let form1 = "";
28
28
  if (data.loggedin) {
29
29
  form1 = `<form action="/" method="POST">
30
+ <div class="box">
30
31
  <h3>Add a New Article</h3>
31
32
  <input type="text" id="title" name="title" placeholder="Article Title" required style="display: block; width: 300px; margin-bottom: 10px;">
32
33
  <textarea id="content" name="content" placeholder="Article Content" required style="display: block; width: 300px; height: 100px; margin-bottom: 10px;"></textarea>
33
34
  <button type="submit">Add Article</button>${button}
34
35
  </form>
36
+ </div>
35
37
  <hr>`;
36
38
  }
37
39
  const form = form1;
@@ -42,7 +44,7 @@ export function formatHTML(data) {
42
44
  </nav>
43
45
  <div id="header">
44
46
  <h1>${data.title}</h1>
45
- <!--<img src="headerphoto.jpg"/>-->
47
+ <img src="headerphoto.jpg" onerror="this.classList.add('hide-image')" />
46
48
  </div>
47
49
  <div id="wrapper">
48
50
  ${form}
package/README.md CHANGED
@@ -26,6 +26,10 @@ Now you can open your blog in your webbrowser on `http://localhost:8080`. Login
26
26
 
27
27
  ## More Features
28
28
 
29
+ ### add a header photo
30
+
31
+ To add a headerphoto to your blog simply name it "headerphoto.jpg" and put it in the _public_ folder.
32
+
29
33
  ### set a Database Adapter
30
34
 
31
35
  #### connect to a sqlite database
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@lexho111/plainblog",
3
- "version": "0.5.27",
3
+ "version": "0.5.28",
4
4
  "description": "A tool for creating and serving a minimalist, single-page blog.",
5
5
  "main": "index.js",
6
6
  "type": "module",
7
7
  "scripts": {
8
8
  "dev": "node index.js",
9
+ "postinstall": "node postinstall.js",
9
10
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
10
11
  "lint": "eslint ."
11
12
  },
package/postinstall.js ADDED
@@ -0,0 +1,89 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { fileURLToPath } from "url";
4
+ import process from "node:process";
5
+
6
+ // This script is executed after the package is installed.
7
+ // Its purpose is to copy default static assets from the package's `public`
8
+ // directory to the user's project's `public` directory.
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+
13
+ async function main() {
14
+ try {
15
+ // The source is the 'public' directory inside our package.
16
+ // We use __dirname to be sure we are looking inside the package itself.
17
+ const sourceDir = path.join(__dirname, "public");
18
+
19
+ // The destination is the 'public' folder in the user's project root.
20
+ // process.env.INIT_CWD is the directory where `npm install` was run.
21
+ // If not available, we fallback to traversing up from node_modules.
22
+ const projectRoot =
23
+ process.env.INIT_CWD || path.resolve(__dirname, "../..");
24
+ const destDir = path.join(projectRoot, "public");
25
+
26
+ console.log(
27
+ `[plainblog] Postinstall: Copying assets from ${sourceDir} to ${destDir}`
28
+ );
29
+
30
+ // 1. Check if source directory exists
31
+ try {
32
+ await fs.promises.access(sourceDir);
33
+ } catch {
34
+ console.log(
35
+ `[plainblog] Source directory '${sourceDir}' not found. Skipping.`
36
+ );
37
+ return;
38
+ }
39
+
40
+ // 2. Avoid copying if source and destination are the same (e.g. local dev install)
41
+ if (path.relative(sourceDir, destDir) === "") {
42
+ console.log(
43
+ "[plainblog] Source and destination are the same. Skipping copy."
44
+ );
45
+ return;
46
+ }
47
+
48
+ // Ensure the user's public directory exists, creating it if not.
49
+ await fs.promises.mkdir(destDir, { recursive: true });
50
+
51
+ const filesToCopy = await fs.promises.readdir(sourceDir);
52
+
53
+ for (const file of filesToCopy) {
54
+ const sourceFile = path.join(sourceDir, file);
55
+ const destFile = path.join(destDir, file);
56
+
57
+ try {
58
+ // Check if destination file exists.
59
+ await fs.promises.access(destFile);
60
+ // If it exists, we do nothing to avoid overwriting user files.
61
+ } catch (error) {
62
+ if (error.code === "ENOENT") {
63
+ // File doesn't exist in the destination, so copy it.
64
+ try {
65
+ await fs.promises.copyFile(sourceFile, destFile);
66
+ console.log(
67
+ `[plainblog] Copied default asset '${file}' to project's '/public' directory.`
68
+ );
69
+ } catch (copyError) {
70
+ console.error(
71
+ `[plainblog] Error copying asset '${file}':`,
72
+ copyError
73
+ );
74
+ }
75
+ } else {
76
+ console.error(
77
+ `[plainblog] Error checking asset '${destFile}':`,
78
+ error
79
+ );
80
+ }
81
+ }
82
+ }
83
+ } catch (error) {
84
+ // We log errors but don't fail the entire installation.
85
+ console.error("[plainblog] Postinstall error:", error);
86
+ }
87
+ }
88
+
89
+ main();
@@ -1,2 +1 @@
1
- body{font-family:Arial;font-family:Arial,sans-serif}h1{color:#333}.grid{border:0 solid #000;display:grid;gap:.25rem;grid-template-columns:1fr}.grid article{border:0 solid #ccc;border-radius:4px;min-width:0;overflow-wrap:break-word;padding:.25rem}.grid article h2{color:#353535;margin-bottom:5px}.grid article .datetime{color:#757575;margin:0}.grid article p{margin-bottom:0;margin-top:10px}article a,article a:visited,h1{color:#696969}nav a{color:#3b40c1;font-size:20px;text-decoration:underline}nav a:visited{color:#3b40c1;text-decoration-color:#3b40c1}#wrapper{max-width:500px;width:100%}@media screen and (max-width:1000px){*{font-size:4vw}#wrapper{box-sizing:border-box;max-width:100%;padding:0 10px;width:100%}}
2
- /* source-hash: a07f631befba4b6bc703f8709f5ef455faafeff4e5f00b62f835576eea7fb529 */
1
+ body{font-family:Arial;margin:0}nav{margin-top:10px}.box,h1,nav{margin-left:10px}.grid{border:0 solid #000;display:grid;grid-gap:.25rem;gap:.25rem;grid-template-columns:1fr}.grid article{border:0 solid #ccc;border-radius:4px;min-width:0;word-wrap:break-word;padding:.25rem}.grid article h2{color:#353535;margin-bottom:5px}.grid article .datetime{color:#757575;margin:0}.grid article p{margin-bottom:0;margin-top:10px}article a,article a:visited,h1{color:#696969}nav a{color:#3b40c1;font-size:20px;-webkit-text-decoration:underline;text-decoration:underline}nav a:visited{color:#3b40c1;text-decoration-color:#3b40c1}#wrapper{max-width:500px;width:100%}.hide-image{display:none}@media screen and (max-width:1000px){*{font-size:4vw}#wrapper{box-sizing:border-box;max-width:100%;padding:0 10px;width:100%}}
package/src/styles.css CHANGED
@@ -1,3 +1,17 @@
1
+ body {
2
+ margin: 0;
3
+ font-family: Arial;
4
+ }
5
+ nav {
6
+ margin-top: 10px;
7
+ }
8
+ nav,
9
+ h1 {
10
+ margin-left: 10px;
11
+ }
12
+ .box {
13
+ margin-left: 10px;
14
+ }
1
15
  .grid {
2
16
  border: 0 solid #000;
3
17
  display: grid;
@@ -52,6 +66,10 @@ nav a:visited {
52
66
  width: 100%;
53
67
  }
54
68
 
69
+ .hide-image {
70
+ display: none;
71
+ }
72
+
55
73
  /* Mobile Layout (screens smaller than 1000px) */
56
74
  @media screen and (max-width: 1000px) {
57
75
  * {