@django-stack/cli 0.0.1 → 0.1.0

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.
Files changed (79) hide show
  1. package/README.md +27 -3
  2. package/dist/bin.js +1302 -2
  3. package/dist/index.d.ts +250 -1
  4. package/dist/index.js +1 -4
  5. package/dist/stack-OTrWHXrO.js +712 -0
  6. package/package.json +14 -7
  7. package/templates/backend/.dockerignore +11 -0
  8. package/templates/backend/Dockerfile +45 -0
  9. package/templates/backend/config/__init__.py +0 -0
  10. package/templates/backend/config/asgi.py +7 -0
  11. package/templates/backend/config/settings.py +87 -0
  12. package/templates/backend/config/studio.py +20 -0
  13. package/templates/backend/config/urls.py +9 -0
  14. package/templates/backend/config/wsgi.py +7 -0
  15. package/templates/backend/conftest.py +7 -0
  16. package/templates/backend/content/__init__.py +0 -0
  17. package/templates/backend/content/admin.py +107 -0
  18. package/templates/backend/content/apps.py +6 -0
  19. package/templates/backend/content/blocks.py +51 -0
  20. package/templates/backend/content/migrations/0001_initial.py +418 -0
  21. package/templates/backend/content/migrations/__init__.py +0 -0
  22. package/templates/backend/content/models.py +234 -0
  23. package/templates/backend/content/seed.py +153 -0
  24. package/templates/backend/content/tests/__init__.py +0 -0
  25. package/templates/backend/content/tests/test_api.py +73 -0
  26. package/templates/backend/entrypoint.sh +27 -0
  27. package/templates/backend/manage.py +16 -0
  28. package/templates/backend/pyproject.toml +33 -0
  29. package/templates/backend/vendor/.gitkeep +0 -0
  30. package/templates/base/.github/workflows/deploy.yml +70 -0
  31. package/templates/base/AGENTS.md +78 -0
  32. package/templates/base/CLAUDE.md +1 -0
  33. package/templates/base/Caddyfile +51 -0
  34. package/templates/base/README.md +87 -0
  35. package/templates/base/SECURITY.md +12 -0
  36. package/templates/base/compose.yaml +303 -0
  37. package/templates/base/env.example +80 -0
  38. package/templates/base/gitignore +15 -0
  39. package/templates/base/package.json +21 -0
  40. package/templates/frontend-astro/.dockerignore +4 -0
  41. package/templates/frontend-astro/Dockerfile +32 -0
  42. package/templates/frontend-astro/astro.config.mjs +38 -0
  43. package/templates/frontend-astro/package.json +31 -0
  44. package/templates/frontend-astro/public/favicon.svg +1 -0
  45. package/templates/frontend-astro/src/components/Blocks.astro +32 -0
  46. package/templates/frontend-astro/src/components/ContactForm.astro +68 -0
  47. package/templates/frontend-astro/src/components/Image.astro +34 -0
  48. package/templates/frontend-astro/src/components/PostCard.astro +41 -0
  49. package/templates/frontend-astro/src/components/PostList.astro +39 -0
  50. package/templates/frontend-astro/src/components/RichText.astro +14 -0
  51. package/templates/frontend-astro/src/components/Seo.astro +20 -0
  52. package/templates/frontend-astro/src/components/blocks/CallToAction.astro +23 -0
  53. package/templates/frontend-astro/src/components/blocks/Image.astro +24 -0
  54. package/templates/frontend-astro/src/components/blocks/Quote.astro +10 -0
  55. package/templates/frontend-astro/src/components/blocks/Text.astro +8 -0
  56. package/templates/frontend-astro/src/layouts/Base.astro +122 -0
  57. package/templates/frontend-astro/src/lib/api.ts +24 -0
  58. package/templates/frontend-astro/src/lib/cache.ts +58 -0
  59. package/templates/frontend-astro/src/lib/headless.ts +344 -0
  60. package/templates/frontend-astro/src/middleware.ts +69 -0
  61. package/templates/frontend-astro/src/pages/404.astro +13 -0
  62. package/templates/frontend-astro/src/pages/[...slug].astro +21 -0
  63. package/templates/frontend-astro/src/pages/blog/[slug].astro +50 -0
  64. package/templates/frontend-astro/src/pages/blog/index.astro +15 -0
  65. package/templates/frontend-astro/src/pages/category/[slug].astro +25 -0
  66. package/templates/frontend-astro/src/pages/index.astro +28 -0
  67. package/templates/frontend-astro/src/pages/preview/exit.ts +7 -0
  68. package/templates/frontend-astro/src/pages/preview/index.ts +26 -0
  69. package/templates/frontend-astro/src/pages/revalidate.ts +19 -0
  70. package/templates/frontend-astro/src/pages/robots.txt.ts +7 -0
  71. package/templates/frontend-astro/src/pages/rss.xml.ts +19 -0
  72. package/templates/frontend-astro/src/pages/sitemap.xml.ts +29 -0
  73. package/templates/frontend-astro/src/pages/tag/[slug].astro +24 -0
  74. package/templates/frontend-astro/src/styles/global.css +101 -0
  75. package/templates/frontend-astro/test/blocks.test.ts +42 -0
  76. package/templates/frontend-astro/test/cache.test.ts +22 -0
  77. package/templates/frontend-astro/tsconfig.json +5 -0
  78. package/templates/frontend-astro/vendor/.gitkeep +0 -0
  79. package/templates/frontend-astro/vitest.config.ts +8 -0
@@ -0,0 +1,24 @@
1
+ ---
2
+ import PostList from "../../components/PostList.astro";
3
+ import Base from "../../layouts/Base.astro";
4
+ import { getContent } from "../../lib/api";
5
+
6
+ const content = getContent(Astro.cookies);
7
+ const slug = Astro.params.slug ?? "";
8
+ const tag = await content.getTag(slug);
9
+
10
+ if (!tag) {
11
+ return Astro.rewrite("/404");
12
+ }
13
+
14
+ const page = Math.max(1, Number(Astro.url.searchParams.get("page")) || 1);
15
+ const result = await content.getPosts({ tag: slug, page, limit: 9 });
16
+ ---
17
+
18
+ <Base page={{ title: `#${tag.name}` }}>
19
+ <section class="container">
20
+ <p class="muted">Tag</p>
21
+ <h1>#{tag.name}</h1>
22
+ <PostList result={result} base={`/tag/${slug}`} />
23
+ </section>
24
+ </Base>
@@ -0,0 +1,101 @@
1
+ /* A small, plain stylesheet: replace it with your own design. */
2
+ :root {
3
+ --color-bg: #ffffff;
4
+ --color-text: #1d2420;
5
+ --color-muted: #5b6862;
6
+ --color-line: #e3e8e4;
7
+ --color-accent: #0c4b33;
8
+ --color-accent-soft: #e8f3ee;
9
+ --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
10
+ --width: 72rem;
11
+ --width-text: 44rem;
12
+ color-scheme: light dark;
13
+ }
14
+
15
+ @media (prefers-color-scheme: dark) {
16
+ :root {
17
+ --color-bg: #111614;
18
+ --color-text: #e6ebe8;
19
+ --color-muted: #a1aba6;
20
+ --color-line: #2a322e;
21
+ --color-accent: #6fcf9f;
22
+ --color-accent-soft: #1b2a23;
23
+ }
24
+ }
25
+
26
+ *,
27
+ *::before,
28
+ *::after {
29
+ box-sizing: border-box;
30
+ }
31
+
32
+ body {
33
+ margin: 0;
34
+ background: var(--color-bg);
35
+ color: var(--color-text);
36
+ font-family: var(--font-body);
37
+ line-height: 1.6;
38
+ }
39
+
40
+ a {
41
+ color: var(--color-accent);
42
+ }
43
+
44
+ img {
45
+ max-width: 100%;
46
+ height: auto;
47
+ }
48
+
49
+ .container {
50
+ width: min(100% - 2rem, var(--width));
51
+ margin-inline: auto;
52
+ }
53
+
54
+ .narrow {
55
+ width: min(100% - 2rem, var(--width-text));
56
+ margin-inline: auto;
57
+ }
58
+
59
+ .muted {
60
+ color: var(--color-muted);
61
+ }
62
+
63
+ .prose h2,
64
+ .prose h3 {
65
+ line-height: 1.25;
66
+ margin-top: 2em;
67
+ }
68
+
69
+ .prose blockquote {
70
+ margin: 2rem 0;
71
+ padding-left: 1.25rem;
72
+ border-left: 4px solid var(--color-accent);
73
+ }
74
+
75
+ .button {
76
+ display: inline-block;
77
+ padding: 0.6rem 1.2rem;
78
+ border-radius: 0.5rem;
79
+ background: var(--color-accent);
80
+ color: var(--color-bg);
81
+ font-weight: 600;
82
+ text-decoration: none;
83
+ border: 0;
84
+ cursor: pointer;
85
+ font-family: inherit;
86
+ font-size: inherit;
87
+ }
88
+
89
+ .grid {
90
+ display: grid;
91
+ gap: 2rem;
92
+ grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
93
+ }
94
+
95
+ .preview-banner {
96
+ background: #fde68a;
97
+ color: #422006;
98
+ padding: 0.5rem 1rem;
99
+ text-align: center;
100
+ font-size: 0.9rem;
101
+ }
@@ -0,0 +1,42 @@
1
+ import { experimental_AstroContainer as AstroContainer } from "astro/container";
2
+ import { describe, expect, it } from "vitest";
3
+ import Blocks from "../src/components/Blocks.astro";
4
+
5
+ const image = {
6
+ id: "1",
7
+ type: "image",
8
+ name: "Photo",
9
+ alt: "A photo",
10
+ url: "http://localhost:3000/media/photo",
11
+ width: 1600,
12
+ height: 900,
13
+ focal_point: null,
14
+ sizes: { content: { url: "http://localhost:3000/media/content.webp", width: 1200, height: 675 } },
15
+ };
16
+
17
+ describe("Blocks", () => {
18
+ it("renders every block type and skips unknown ones", async () => {
19
+ const container = await AstroContainer.create();
20
+ const html = await container.renderToString(Blocks, {
21
+ props: {
22
+ blocks: [
23
+ { id: "a", type: "text", value: { body: "<p>Hello <strong>world</strong></p>" } },
24
+ { id: "b", type: "image", value: { image, caption: "A caption" } },
25
+ { id: "c", type: "quote", value: { text: "Quoted", attribution: "Someone" } },
26
+ {
27
+ id: "d",
28
+ type: "call_to_action",
29
+ value: { title: "Act", text: "", button_label: "Go", button_url: "/go" },
30
+ },
31
+ { id: "e", type: "unknown", value: {} },
32
+ ],
33
+ },
34
+ });
35
+ expect(html).toContain("<strong>world</strong>");
36
+ expect(html).toContain('src="http://localhost:3000/media/content.webp"');
37
+ expect(html).toContain('alt="A photo"');
38
+ expect(html).toContain("A caption");
39
+ expect(html).toContain("Quoted");
40
+ expect(html).toContain('href="/go"');
41
+ });
42
+ });
@@ -0,0 +1,22 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { getCached, purgeAll, store } from "../src/lib/cache";
3
+
4
+ describe("page cache", () => {
5
+ it("stores, serves and purges pages", async () => {
6
+ purgeAll();
7
+ expect(getCached("/about")).toBeNull();
8
+ const response = await store(
9
+ "/about",
10
+ new Response("<h1>About</h1>", { headers: { "Content-Type": "text/html" } }),
11
+ );
12
+ expect(response.headers.get("X-Cache")).toBe("MISS");
13
+ expect(await response.text()).toBe("<h1>About</h1>");
14
+
15
+ const hit = getCached("/about");
16
+ expect(hit?.headers.get("X-Cache")).toBe("HIT");
17
+ expect(await hit?.text()).toBe("<h1>About</h1>");
18
+
19
+ expect(purgeAll()).toBe(1);
20
+ expect(getCached("/about")).toBeNull();
21
+ });
22
+ });
@@ -0,0 +1,5 @@
1
+ {
2
+ "extends": "astro/tsconfigs/strict",
3
+ "include": [".astro/types.d.ts", "**/*"],
4
+ "exclude": ["dist"]
5
+ }
File without changes
@@ -0,0 +1,8 @@
1
+ /// <reference types="vitest/config" />
2
+ import { getViteConfig } from "astro/config";
3
+
4
+ export default getViteConfig({
5
+ test: {
6
+ include: ["test/**/*.test.ts"],
7
+ },
8
+ });