campsitejs 0.0.1 → 0.0.3

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.js CHANGED
@@ -11,6 +11,17 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
11
11
  const templateDir = join(__dirname, "template");
12
12
  // Variant pages live under the template folder
13
13
  const variantDir = join(templateDir, "variants");
14
+ const pkgJsonPath = join(__dirname, "package.json");
15
+
16
+ async function getCliVersion() {
17
+ try {
18
+ const raw = await readFile(pkgJsonPath, "utf8");
19
+ const pkg = JSON.parse(raw);
20
+ return pkg.version || "0.0.0";
21
+ } catch {
22
+ return "0.0.0";
23
+ }
24
+ }
14
25
 
15
26
  function formatPackageName(name) {
16
27
  return name
@@ -71,11 +82,13 @@ async function writeConfig(targetDir, answers) {
71
82
  outDir: "dist",
72
83
  templateEngine: "${primaryEngine}",
73
84
  markdown: ${answers.markdown},
85
+ minifyCSS: false,
86
+ minifyHTML: false,
74
87
  integrations: {
75
88
  nunjucks: ${answers.templateEngines.includes("nunjucks")},
76
89
  liquid: ${answers.templateEngines.includes("liquid")},
77
- vue: ${answers.templateEngines.includes("vue")},
78
- alpine: ${answers.templateEngines.includes("alpine")}
90
+ vue: ${answers.jsFrameworks.includes("vue")},
91
+ alpine: ${answers.jsFrameworks.includes("alpine")}
79
92
  }
80
93
  };
81
94
  `;
@@ -90,19 +103,60 @@ async function updatePackageJson(targetDir, answers) {
90
103
  pkg.devDependencies = pkg.devDependencies || {};
91
104
  const deps = pkg.dependencies;
92
105
  const devDeps = pkg.devDependencies;
106
+ pkg.scripts = pkg.scripts || {};
93
107
  const localCoreDir = resolve(__dirname, "../basecampjs");
94
108
  if (existsSync(localCoreDir)) {
95
109
  const relCore = relative(targetDir, localCoreDir) || ".";
96
- deps["basecampjs"] = `file:${relCore}`;
110
+ devDeps["basecampjs"] = `file:${relCore}`;
111
+ } else {
112
+ devDeps["basecampjs"] = "^0.0.1";
113
+ }
114
+ if (answers.markdown) devDeps["markdown-it"] = "^14.1.0";
115
+ if (answers.templateEngines.includes("nunjucks")) devDeps["nunjucks"] = "^3.2.4";
116
+ if (answers.templateEngines.includes("liquid")) devDeps["liquidjs"] = "^10.12.0";
117
+ if (answers.jsFrameworks.includes("vue")) deps["vue"] = "^3.4.0";
118
+ if (answers.jsFrameworks.includes("alpine")) deps["alpinejs"] = "^3.13.0";
119
+
120
+ // CSS framework selection
121
+ const cssFramework = answers.cssFramework || "tailwind";
122
+ const cssDeps = {
123
+ bootstrap: ["bootstrap", "^5.3.3"],
124
+ foundation: ["foundation-sites", "^6.8.1"],
125
+ bulma: ["bulma", "^0.9.4"]
126
+ };
127
+
128
+ // Reset CSS-related scripts before applying framework-specific ones
129
+ ["build:css", "dev:css", "dev:site", "prebuild", "postinstall"].forEach((script) => {
130
+ delete pkg.scripts[script];
131
+ });
132
+
133
+ if (cssFramework === "tailwind") {
134
+ devDeps["tailwindcss"] = "^3.4.13";
135
+ devDeps["npm-run-all"] = "^4.1.5";
136
+ pkg.scripts["build:css"] = "tailwindcss -c tailwind.config.cjs -i ./src/styles/tailwind.css -o ./public/style.css --minify";
137
+ pkg.scripts["dev:css"] = "tailwindcss -c tailwind.config.cjs -i ./src/styles/tailwind.css -o ./public/style.css --watch";
138
+ pkg.scripts["dev:site"] = "campsite dev";
139
+ pkg.scripts["dev"] = "npm-run-all -p dev:css dev:site";
140
+ pkg.scripts["prebuild"] = "npm run build:css";
141
+ pkg.scripts["build"] = "campsite build";
142
+ pkg.scripts["serve"] = "campsite serve";
143
+ pkg.scripts["postinstall"] = "npm run build:css";
97
144
  } else {
98
- deps["basecampjs"] = "^0.0.1";
145
+ delete devDeps["tailwindcss"];
146
+ delete devDeps["npm-run-all"];
147
+ Object.entries(cssDeps).forEach(([key, [name]]) => {
148
+ if (key !== cssFramework) delete deps[name];
149
+ });
150
+ const selected = cssDeps[cssFramework];
151
+ if (selected) {
152
+ const [name, version] = selected;
153
+ deps[name] = version;
154
+ }
155
+ pkg.scripts["dev"] = "campsite dev";
156
+ pkg.scripts["build"] = "campsite build";
157
+ pkg.scripts["serve"] = "campsite serve";
99
158
  }
100
- if (answers.markdown) deps["markdown-it"] = "^14.1.0";
101
- if (answers.templateEngines.includes("nunjucks")) deps["nunjucks"] = "^3.2.4";
102
- if (answers.templateEngines.includes("liquid")) deps["liquidjs"] = "^10.12.0";
103
- if (answers.templateEngines.includes("vue")) deps["vue"] = "^3.4.0";
104
- if (answers.templateEngines.includes("alpine")) deps["alpinejs"] = "^3.13.0";
105
- devDeps["tailwindcss"] = "^3.4.13";
159
+
106
160
  await writeFile(pkgPath, JSON.stringify(pkg, null, 2), "utf8");
107
161
  }
108
162
 
@@ -119,14 +173,23 @@ async function swapPageTemplates(targetDir, answers) {
119
173
 
120
174
  async function pruneComponents(targetDir, answers) {
121
175
  const componentDir = join(targetDir, "src", "components");
122
- if (!answers.templateEngines.includes("vue")) {
176
+ if (!answers.jsFrameworks.includes("vue")) {
123
177
  await rm(join(componentDir, "HelloCampsite.vue")).catch(() => {});
124
178
  }
125
- if (!answers.templateEngines.includes("alpine")) {
179
+ if (!answers.jsFrameworks.includes("alpine")) {
126
180
  await rm(join(componentDir, "alpine-card.html")).catch(() => {});
127
181
  }
128
182
  }
129
183
 
184
+ async function pruneCssFramework(targetDir, answers) {
185
+ if (answers.cssFramework === "tailwind") return;
186
+ const tailwindFiles = [
187
+ join(targetDir, "tailwind.config.cjs"),
188
+ join(targetDir, "src", "styles", "tailwind.css")
189
+ ];
190
+ await Promise.all(tailwindFiles.map((file) => rm(file).catch(() => {})));
191
+ }
192
+
130
193
  async function installDependencies(targetDir, packageManager) {
131
194
  return new Promise((resolve, reject) => {
132
195
  const child = spawn(packageManager, ["install"], {
@@ -142,8 +205,9 @@ async function installDependencies(targetDir, packageManager) {
142
205
  }
143
206
 
144
207
  async function main() {
145
- console.log(kleur.bold().cyan("\nšŸ•ļø Welcome to Campsite"));
146
- console.log(kleur.dim("Scaffold a cozy static site in seconds.\n"));
208
+ const version = await getCliVersion();
209
+ console.log(kleur.bold().cyan(`\nšŸ•ļø Welcome to CampSiteJS v${version}`));
210
+ console.log(kleur.dim("Build a cozy static campsite in seconds.\n"));
147
211
 
148
212
  const argProjectName = process.argv[2];
149
213
  const defaultProjectName = argProjectName || nextCampsiteName(process.cwd());
@@ -165,15 +229,37 @@ async function main() {
165
229
  {
166
230
  type: "multiselect",
167
231
  name: "templateEngines",
168
- message: "Choose templating and UI options",
232
+ message: "Choose templating engines",
169
233
  hint: "Use space to toggle, enter to confirm",
170
234
  instructions: false,
171
235
  min: 1,
172
236
  choices: [
173
237
  { title: "Nunjucks", value: "nunjucks", selected: true },
174
- { title: "Liquid", value: "liquid", selected: true },
175
- { title: "Vue components", value: "vue" },
176
- { title: "AlpineJS sprinkles", value: "alpine" }
238
+ { title: "Liquid", value: "liquid" }
239
+ ]
240
+ },
241
+ {
242
+ type: "multiselect",
243
+ name: "jsFrameworks",
244
+ message: "Sprinkle in JS frameworks?",
245
+ hint: "Use space to toggle, enter to confirm",
246
+ instructions: false,
247
+ min: 0,
248
+ choices: [
249
+ { title: "Alpine.js", value: "alpine", selected: true },
250
+ { title: "Vue.js", value: "vue" }
251
+ ]
252
+ },
253
+ {
254
+ type: "select",
255
+ name: "cssFramework",
256
+ message: "CSS framework",
257
+ initial: 0,
258
+ choices: [
259
+ { title: "Tailwind CSS", value: "tailwind" },
260
+ { title: "Bootstrap", value: "bootstrap" },
261
+ { title: "Foundation", value: "foundation" },
262
+ { title: "Bulma", value: "bulma" }
177
263
  ]
178
264
  },
179
265
  {
@@ -208,6 +294,7 @@ async function main() {
208
294
  await copyBaseTemplate(targetDir);
209
295
  await swapPageTemplates(targetDir, answers);
210
296
  await pruneComponents(targetDir, answers);
297
+ await pruneCssFramework(targetDir, answers);
211
298
  await writeConfig(targetDir, answers);
212
299
  await updatePackageJson(targetDir, answers);
213
300
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "campsitejs",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "type": "module",
5
5
  "description": "Create a new Campsite static site (campsitejs).",
6
6
  "bin": {
@@ -4,6 +4,8 @@ export default {
4
4
  outDir: "dist",
5
5
  templateEngine: "nunjucks",
6
6
  markdown: true,
7
+ minifyCSS: false,
8
+ minifyHTML: false,
7
9
  integrations: {
8
10
  nunjucks: true,
9
11
  liquid: false,
@@ -1,35 +1,26 @@
1
- <!doctype html>
1
+ {% set meta_title = frontmatter.title or title or site.name %}{% set meta_description = frontmatter.description or page.description or "A cozy Campsite starter." %}{% set meta_url = frontmatter.canonical or frontmatter.url %}<!doctype html>
2
2
  <html lang="en" class="min-h-screen bg-radial bg-gradient-to-br from-campfire-900 from-10% to-black to-90%">
3
-
4
3
  <head>
5
4
  <meta charset="UTF-8">
6
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- {% set meta_title = frontmatter.title or title or site.name %}
8
- {% set meta_description = frontmatter.description or page.description or "A cozy Campsite starter." %}
9
- {% set meta_url = frontmatter.canonical or frontmatter.url %}
10
6
  <title>{{ meta_title }}</title>
11
- <meta name="description" content="{{ meta_description }}">
12
- {% if frontmatter.robots %}
13
- <meta name="robots" content="{{ frontmatter.robots }}">{% endif %}
14
- {% if meta_url %}
7
+ <meta name="description" content="{{ meta_description }}">{% if frontmatter.robots %}
8
+ <meta name="robots" content="{{ frontmatter.robots }}">{% endif %}{% if meta_url %}
15
9
  <link rel="canonical" href="{{ meta_url }}">{% endif %}
16
10
  <meta property="og:title" content="{{ meta_title }}">
17
- <meta property="og:description" content="{{ meta_description }}">
18
- {% if meta_url %}
11
+ <meta property="og:description" content="{{ meta_description }}">{% if meta_url %}
19
12
  <meta property="og:url" content="{{ meta_url }}">{% endif %}
20
13
  <meta property="og:type" content="{{ frontmatter.og_type or " website" }}">
21
14
  <meta property="og:site_name" content="{{ site.name }}">
22
15
  <meta name="twitter:card" content="{{ frontmatter.twitter_card or " summary_large_image" }}">
23
16
  <meta name="twitter:title" content="{{ meta_title }}">
24
- <meta name="twitter:description" content="{{ meta_description }}">
25
- {% if meta_url %}
17
+ <meta name="twitter:description" content="{{ meta_description }}">{% if meta_url %}
26
18
  <meta name="twitter:url" content="{{ meta_url }}">{% endif %}
27
19
  <link rel="stylesheet" href="/style.css">
28
20
  <link rel="preconnect" href="https://fonts.googleapis.com">
29
21
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
30
22
  <link href="https://fonts.googleapis.com/css2?family=Caprasimo&display=swap" rel="stylesheet">
31
23
  </head>
32
-
33
24
  <body class="space-y-12 font-serif">
34
25
  <header class="bg-stone-950 flex items-stretch justify-between py-2 px-6">
35
26
  <a href="/" class="inline-flex items-center text-amber-50 font-bold text-lg tracking-wide py-3">
@@ -37,7 +28,7 @@
37
28
  </a>
38
29
  <nav class="flex items-center gap-2">
39
30
  <a href="/" class="px-2">Home</a>
40
- <a href="https://github.com/FoxGroveMedia/campsite" target="_blank" rel="noreferrer" class="px-2">Docs</a>
31
+ <a href="https://campsite.foxgrovemedia.com/docs/overview" target="_blank" rel="noreferrer" class="px-2">Docs</a>
41
32
  <a href="https://github.com/FoxGroveMedia" target="_blank" rel="noreferrer">
42
33
  <svg class="size-7" fill="currentColor" xmlns="http://www.w3.org/2000/svg"
43
34
  viewBox="0 0 640 640"><!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.-->
@@ -57,24 +48,17 @@
57
48
  <main class="mx-auto max-w-5xl px-4 sm:px-6 lg:px-8">
58
49
  <div
59
50
  class="rounded-lg bg-white/5 shadow dark:bg-gray-800/50 dark:shadow-none dark:outline dark:outline-1 dark:-outline-offset-1 dark:outline-white/10 text-white">
60
- <div class="px-4 py-5 sm:p-6">
61
- {% block content %}
62
- {% if content %}
63
- {{ content | safe }}
64
- {% else %}
51
+ <div class="px-4 py-5 sm:p-6">{% block content %}{% if content %}
52
+ {{ content | safe }}{% else %}
65
53
  <section class="hero">
66
54
  <p class="eyebrow">Campfire ready</p>
67
55
  <h1>Welcome to Campsite</h1>
68
56
  <p>Edit <code>src/pages/index.md</code> to get started.</p>
69
- </section>
70
- {% endif %}
71
- {% endblock %}
72
- </div>
57
+ </section>{% endif %}{% endblock %}</div>
73
58
  </div>
74
59
  </main>
75
60
  <footer class="text-xs text-amber-50/40 text-center">
76
61
  <p>Built with <span class="font-semibold text-amber-50/60">Campsite</span>.</p>
77
62
  </footer>
78
63
  </body>
79
-
80
64
  </html>
@@ -0,0 +1,13 @@
1
+ ---
2
+ title: Error 404 - Page Not Found
3
+ layout: base.njk
4
+ description: The page you are looking for does not exist.
5
+ ---
6
+
7
+ <div class="flex min-h-96 flex-col items-center justify-center bg-stone-900 px-4 text-center">
8
+ <h1 class="text-6xl font-display font-bold text-amber-500 mb-4">404</h1>
9
+ <p class="text-xl text-stone-400 mb-8">Oops! The page you're looking for can't be found.</p>
10
+ <a href="/" class="inline-block rounded bg-amber-500 px-6 py-3 font-semibold text-white hover:bg-amber-600 transition">
11
+ Go Back Home
12
+ </a>
13
+ </div>