saasaloy 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 (69) hide show
  1. package/dist/index.js +8455 -0
  2. package/dist/index.js.map +1 -0
  3. package/package.json +69 -0
  4. package/schemas/manifest.schema.json +107 -0
  5. package/schemas/registry-item.schema.json +336 -0
  6. package/schemas/saasaloy-lock.schema.json +86 -0
  7. package/schemas/saasaloy.schema.json +42 -0
  8. package/templates/base/AGENTS.md +450 -0
  9. package/templates/base/CLAUDE.md +1 -0
  10. package/templates/base/DESIGN.md +209 -0
  11. package/templates/base/README.md +71 -0
  12. package/templates/base/_agents/skills/saasaloy-design/SKILL.md +198 -0
  13. package/templates/base/_agents/skills/saasaloy-landing-copy/SKILL.md +395 -0
  14. package/templates/base/_agents/skills/saasaloy-setup/SKILL.md +273 -0
  15. package/templates/base/_gitignore +32 -0
  16. package/templates/base/_husky/commit-msg +1 -0
  17. package/templates/base/_husky/pre-commit +1 -0
  18. package/templates/base/_prettierignore +31 -0
  19. package/templates/base/_saasaloy-base.json +9 -0
  20. package/templates/base/apps/web/astro.config.mjs +61 -0
  21. package/templates/base/apps/web/package.json +30 -0
  22. package/templates/base/apps/web/public/favicon.svg +4 -0
  23. package/templates/base/apps/web/src/layouts/Layout.astro +52 -0
  24. package/templates/base/apps/web/src/pages/404.astro +24 -0
  25. package/templates/base/apps/web/src/pages/500.astro +33 -0
  26. package/templates/base/apps/web/src/pages/index.astro +61 -0
  27. package/templates/base/apps/web/src/pages/privacy.astro +15 -0
  28. package/templates/base/apps/web/src/pages/terms.astro +14 -0
  29. package/templates/base/apps/web/tsconfig.json +11 -0
  30. package/templates/base/apps/web/wrangler.jsonc +27 -0
  31. package/templates/base/commitlint.config.js +9 -0
  32. package/templates/base/lint-staged.config.js +17 -0
  33. package/templates/base/oxlint.config.mjs +155 -0
  34. package/templates/base/package.json +44 -0
  35. package/templates/base/packages/tsconfig/base.json +17 -0
  36. package/templates/base/packages/tsconfig/package.json +18 -0
  37. package/templates/base/packages/ui/components.json +19 -0
  38. package/templates/base/packages/ui/package.json +39 -0
  39. package/templates/base/packages/ui/src/blocks/cta.tsx +82 -0
  40. package/templates/base/packages/ui/src/blocks/error-state.tsx +144 -0
  41. package/templates/base/packages/ui/src/blocks/faq.tsx +64 -0
  42. package/templates/base/packages/ui/src/blocks/feature-grid.tsx +185 -0
  43. package/templates/base/packages/ui/src/blocks/footer.tsx +99 -0
  44. package/templates/base/packages/ui/src/blocks/hero.tsx +84 -0
  45. package/templates/base/packages/ui/src/blocks/navbar.tsx +159 -0
  46. package/templates/base/packages/ui/src/blocks/pricing-table.tsx +175 -0
  47. package/templates/base/packages/ui/src/blocks/theme-toggle.tsx +51 -0
  48. package/templates/base/packages/ui/src/components/accordion.tsx +78 -0
  49. package/templates/base/packages/ui/src/components/badge.tsx +53 -0
  50. package/templates/base/packages/ui/src/components/button.tsx +59 -0
  51. package/templates/base/packages/ui/src/components/card.tsx +103 -0
  52. package/templates/base/packages/ui/src/components/input.tsx +20 -0
  53. package/templates/base/packages/ui/src/components/label.tsx +18 -0
  54. package/templates/base/packages/ui/src/components/separator.tsx +23 -0
  55. package/templates/base/packages/ui/src/containers/README.md +11 -0
  56. package/templates/base/packages/ui/src/content/errors.ts +58 -0
  57. package/templates/base/packages/ui/src/content/landing.ts +304 -0
  58. package/templates/base/packages/ui/src/index.ts +8 -0
  59. package/templates/base/packages/ui/src/lib/interpolate.ts +31 -0
  60. package/templates/base/packages/ui/src/lib/sentinel.ts +11 -0
  61. package/templates/base/packages/ui/src/lib/theme.ts +167 -0
  62. package/templates/base/packages/ui/src/lib/utils.ts +11 -0
  63. package/templates/base/packages/ui/src/styles/globals.css +164 -0
  64. package/templates/base/packages/ui/tsconfig.json +7 -0
  65. package/templates/base/pnpm-workspace.yaml +23 -0
  66. package/templates/base/prettier.config.js +10 -0
  67. package/templates/base/saasaloy.json +8 -0
  68. package/templates/base/stylelint.config.js +46 -0
  69. package/templates/base/turbo.json +20 -0
@@ -0,0 +1,164 @@
1
+ /* The one theme for the whole monorepo. `@repo/ui` owns Tailwind's entrypoint, the
2
+ source globs, and the token set; apps import it via the `@repo/ui/globals.css`
3
+ subpath export (see apps/web/src/layouts/Layout.astro) rather than redeclaring it.
4
+ Tokens follow shadcn's `neutral` base color with `cssVariables: true`, so anything
5
+ added later with `pnpm --filter @repo/ui exec shadcn add <x>` themes correctly. */
6
+ @import "tailwindcss";
7
+ @import "tw-animate-css";
8
+ @import "shadcn/tailwind.css";
9
+
10
+ /* Tailwind's automatic class detection is rooted at the CURRENT WORKING DIRECTORY, and
11
+ `astro dev`/`astro build` run with cwd = apps/web. Without these globs every utility
12
+ class written inside packages/ui is silently dropped — no error, no warning, just
13
+ missing CSS. A non-matching @source glob is equally silent, so both paths matter. */
14
+ @source "../**/*.{ts,tsx}";
15
+
16
+ /* FOUR levels up, not three. From packages/ui/src/styles/ the path walks
17
+ styles → src → ui → packages → <root>, so `../../../apps/**` would resolve to
18
+ packages/apps/** — a directory that does not exist. shadcn's own astro-monorepo
19
+ template ships that off-by-one and gets away with it only because cwd-rooted
20
+ auto-detection happens to cover the app; that cover vanishes when Turborepo builds
21
+ from the repo root. Do not "correct" this back to three. */
22
+ @source "../../../../apps/**/*.{ts,tsx,astro}";
23
+
24
+ /* Tailwind's own scanner skips node_modules only by way of .gitignore, and its ignore
25
+ walker needs a real .git directory to honour one. Before `git init` — a fresh
26
+ `saasaloy init`, or CI checking out a tarball — every .ts/.md under node_modules gets
27
+ scanned and the built stylesheet balloons ~5x (173 kB vs 33 kB, measured) with
28
+ utilities no page uses. This exclusion makes the result independent of git state. */
29
+ @source not "../../../../**/node_modules";
30
+
31
+ /* Dark mode is the `.dark` class shadcn assumes. It is set pre-paint by the inline
32
+ THEME_INIT_SCRIPT (packages/ui/src/lib/theme.ts) that every host document emits —
33
+ from the visitor's stored choice, falling back to the OS preference. The chosen
34
+ state also lands on <html> as `data-theme`, which is what blocks/theme-toggle.tsx
35
+ keys its icons off; nothing here needs to know about it. */
36
+ @custom-variant dark (&:is(.dark *));
37
+
38
+ :root {
39
+ /* Tell the browser which palette the document is using, so native UI it renders for
40
+ us — scrollbars, form controls, the default canvas — follows the theme too. The
41
+ tokens below only cover what we paint ourselves. Paired with `.dark` rather than
42
+ `light dark` on :root, because the theme is class-driven, not media-driven: the
43
+ pre-paint script resolves the visitor's choice (or the OS preference behind it)
44
+ into a class, and re-resolves on the fly when the OS flips while the choice is
45
+ `system`. `light dark` here would let the OS override an explicit choice. */
46
+ color-scheme: light;
47
+
48
+ --radius: 0.625rem;
49
+ --background: oklch(1 0 0);
50
+ --foreground: oklch(0.145 0 0);
51
+ --card: oklch(1 0 0);
52
+ --card-foreground: oklch(0.145 0 0);
53
+ --popover: oklch(1 0 0);
54
+ --popover-foreground: oklch(0.145 0 0);
55
+ --primary: oklch(0.205 0 0);
56
+ --primary-foreground: oklch(0.985 0 0);
57
+ --secondary: oklch(0.97 0 0);
58
+ --secondary-foreground: oklch(0.205 0 0);
59
+ --muted: oklch(0.97 0 0);
60
+ --muted-foreground: oklch(0.556 0 0);
61
+ --accent: oklch(0.97 0 0);
62
+ --accent-foreground: oklch(0.205 0 0);
63
+ --destructive: oklch(0.577 0.245 27.325);
64
+ --border: oklch(0.922 0 0);
65
+ --input: oklch(0.922 0 0);
66
+ --ring: oklch(0.708 0 0);
67
+ --chart-1: oklch(0.87 0 0);
68
+ --chart-2: oklch(0.556 0 0);
69
+ --chart-3: oklch(0.439 0 0);
70
+ --chart-4: oklch(0.371 0 0);
71
+ --chart-5: oklch(0.269 0 0);
72
+ --sidebar: oklch(0.985 0 0);
73
+ --sidebar-foreground: oklch(0.145 0 0);
74
+ --sidebar-primary: oklch(0.205 0 0);
75
+ --sidebar-primary-foreground: oklch(0.985 0 0);
76
+ --sidebar-accent: oklch(0.97 0 0);
77
+ --sidebar-accent-foreground: oklch(0.205 0 0);
78
+ --sidebar-border: oklch(0.922 0 0);
79
+ --sidebar-ring: oklch(0.708 0 0);
80
+ }
81
+
82
+ .dark {
83
+ color-scheme: dark;
84
+
85
+ --background: oklch(0.145 0 0);
86
+ --foreground: oklch(0.985 0 0);
87
+ --card: oklch(0.205 0 0);
88
+ --card-foreground: oklch(0.985 0 0);
89
+ --popover: oklch(0.205 0 0);
90
+ --popover-foreground: oklch(0.985 0 0);
91
+ --primary: oklch(0.922 0 0);
92
+ --primary-foreground: oklch(0.205 0 0);
93
+ --secondary: oklch(0.269 0 0);
94
+ --secondary-foreground: oklch(0.985 0 0);
95
+ --muted: oklch(0.269 0 0);
96
+ --muted-foreground: oklch(0.708 0 0);
97
+ --accent: oklch(0.269 0 0);
98
+ --accent-foreground: oklch(0.985 0 0);
99
+ --destructive: oklch(0.704 0.191 22.216);
100
+ --border: oklch(1 0 0 / 10%);
101
+ --input: oklch(1 0 0 / 15%);
102
+ --ring: oklch(0.556 0 0);
103
+ --chart-1: oklch(0.87 0 0);
104
+ --chart-2: oklch(0.556 0 0);
105
+ --chart-3: oklch(0.439 0 0);
106
+ --chart-4: oklch(0.371 0 0);
107
+ --chart-5: oklch(0.269 0 0);
108
+ --sidebar: oklch(0.205 0 0);
109
+ --sidebar-foreground: oklch(0.985 0 0);
110
+ --sidebar-primary: oklch(0.488 0.243 264.376);
111
+ --sidebar-primary-foreground: oklch(0.985 0 0);
112
+ --sidebar-accent: oklch(0.269 0 0);
113
+ --sidebar-accent-foreground: oklch(0.985 0 0);
114
+ --sidebar-border: oklch(1 0 0 / 10%);
115
+ --sidebar-ring: oklch(0.556 0 0);
116
+ }
117
+
118
+ @theme inline {
119
+ --radius-sm: calc(var(--radius) - 4px);
120
+ --radius-md: calc(var(--radius) - 2px);
121
+ --radius-lg: var(--radius);
122
+ --radius-xl: calc(var(--radius) + 4px);
123
+ --color-background: var(--background);
124
+ --color-foreground: var(--foreground);
125
+ --color-card: var(--card);
126
+ --color-card-foreground: var(--card-foreground);
127
+ --color-popover: var(--popover);
128
+ --color-popover-foreground: var(--popover-foreground);
129
+ --color-primary: var(--primary);
130
+ --color-primary-foreground: var(--primary-foreground);
131
+ --color-secondary: var(--secondary);
132
+ --color-secondary-foreground: var(--secondary-foreground);
133
+ --color-muted: var(--muted);
134
+ --color-muted-foreground: var(--muted-foreground);
135
+ --color-accent: var(--accent);
136
+ --color-accent-foreground: var(--accent-foreground);
137
+ --color-destructive: var(--destructive);
138
+ --color-border: var(--border);
139
+ --color-input: var(--input);
140
+ --color-ring: var(--ring);
141
+ --color-chart-1: var(--chart-1);
142
+ --color-chart-2: var(--chart-2);
143
+ --color-chart-3: var(--chart-3);
144
+ --color-chart-4: var(--chart-4);
145
+ --color-chart-5: var(--chart-5);
146
+ --color-sidebar: var(--sidebar);
147
+ --color-sidebar-foreground: var(--sidebar-foreground);
148
+ --color-sidebar-primary: var(--sidebar-primary);
149
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
150
+ --color-sidebar-accent: var(--sidebar-accent);
151
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
152
+ --color-sidebar-border: var(--sidebar-border);
153
+ --color-sidebar-ring: var(--sidebar-ring);
154
+ }
155
+
156
+ @layer base {
157
+ * {
158
+ @apply border-border outline-ring/50;
159
+ }
160
+
161
+ body {
162
+ @apply bg-background text-foreground;
163
+ }
164
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "@repo/tsconfig/base.json",
3
+ "compilerOptions": {
4
+ "jsx": "react-jsx"
5
+ },
6
+ "include": ["src"]
7
+ }
@@ -0,0 +1,23 @@
1
+ # pnpm 11 workspace + settings (camelCase; .npmrc is auth/registry-only).
2
+ packages:
3
+ - "apps/*"
4
+ - "packages/*"
5
+ # `infra` (the deploy capability, ADR 0021) scaffolds at the repo root, a sibling of
6
+ # apps/ and packages/, not inside either — it isn't an app and it isn't a shared
7
+ # package, so it needs its own literal entry rather than fitting one of the globs.
8
+ - "infra"
9
+
10
+ # Pin exact versions so manifest and lockfile agree.
11
+ saveExact: true
12
+ # Fail installs when Node/pnpm don't satisfy `engines`.
13
+ engineStrict: true
14
+ # Collapse duplicate peer installs across the monorepo.
15
+ dedupePeerDependents: true
16
+
17
+ # Dependencies allowed to run install/build scripts (pnpm 11 blocks by default).
18
+ allowBuilds:
19
+ esbuild: true
20
+ workerd: true
21
+ sharp: true
22
+ # @pulumi/pulumi's gRPC transport (infra capability, ADR 0021) needs this postinstall.
23
+ protobufjs: true
@@ -0,0 +1,10 @@
1
+ import ultracite from "ultracite/prettier";
2
+
3
+ // Ultracite's Prettier config carries no `plugins` key, so this is a spread rather
4
+ // than a re-export: Astro parsing and Tailwind class sorting are added on top.
5
+ // `prettier-plugin-tailwindcss` must stay LAST — it wraps whichever printer runs
6
+ // before it, and loses its sorting if another plugin loads after it.
7
+ export default {
8
+ ...ultracite,
9
+ plugins: ["prettier-plugin-astro", "prettier-plugin-tailwindcss"],
10
+ };
@@ -0,0 +1,8 @@
1
+ {
2
+ "base": "web",
3
+ "aliases": {
4
+ "@web": "apps/web/src",
5
+ "@ui": "packages/ui/src"
6
+ },
7
+ "installed": []
8
+ }
@@ -0,0 +1,46 @@
1
+ import ultracite from "ultracite/stylelint";
2
+
3
+ // Ultracite's Stylelint config with the at-rule allow-list widened for Tailwind v4.
4
+ // Its list stops at tailwind/apply/layer/variants/responsive/screen/source/reference,
5
+ // and `packages/ui/src/styles/globals.css` also uses `@theme` and `@custom-variant`,
6
+ // so without these entries the config fails on the only CSS file you ship.
7
+ //
8
+ // The notation rules match shadcn's own output: its colour tokens are written
9
+ // `oklch(0.985 0 0)`, and rewriting them to `oklch(98.5% 0deg)` would have to be
10
+ // redone by hand after every `shadcn add` sync.
11
+ export default {
12
+ ...ultracite,
13
+
14
+ // Stylelint has no .gitignore support and its default ignore list is
15
+ // `node_modules` only, so build output has to be named here. `pnpm lint:css`
16
+ // globs `**/*.css`, which after a `pnpm build` would otherwise walk into
17
+ // `apps/*/dist/_astro/*.css` — Tailwind's minified output, ~600 findings of
18
+ // "violations" in code nobody wrote.
19
+ ignoreFiles: [
20
+ "**/node_modules/**",
21
+ "**/dist/**",
22
+ "**/build/**",
23
+ "**/.astro/**",
24
+ "**/.turbo/**",
25
+ "**/.wrangler/**",
26
+ ],
27
+ rules: {
28
+ ...ultracite.rules,
29
+ "import-notation": "string",
30
+ "hue-degree-notation": "number",
31
+ "lightness-notation": "number",
32
+ "at-rule-no-unknown": [
33
+ true,
34
+ {
35
+ ignoreAtRules: [
36
+ ...ultracite.rules["at-rule-no-unknown"][1].ignoreAtRules,
37
+ "custom-variant",
38
+ "plugin",
39
+ "theme",
40
+ "utility",
41
+ "variant",
42
+ ],
43
+ },
44
+ ],
45
+ },
46
+ };
@@ -0,0 +1,20 @@
1
+ {
2
+ "$schema": "https://turbo.build/schema.json",
3
+ "ui": "tui",
4
+ "tasks": {
5
+ "build": {
6
+ "dependsOn": ["^build"],
7
+ "outputs": ["dist/**", ".astro/**"]
8
+ },
9
+ "clean": {
10
+ "cache": false
11
+ },
12
+ "dev": {
13
+ "cache": false,
14
+ "persistent": true
15
+ },
16
+ "typecheck": {
17
+ "dependsOn": ["^build"]
18
+ }
19
+ }
20
+ }