elm-ssr 0.99.0 → 1.0.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.
package/bin/elm-ssr.mjs CHANGED
@@ -76,7 +76,7 @@ const printHelp = () => {
76
76
  build Generate wrapper modules and compile configured Elm SSR apps
77
77
  compress Pre-compress island and app bundles using Gzip for faster edge delivery
78
78
  dev Build and start wrangler dev using the current workspace config
79
- init <name> Initialize a self-contained single-app project in the current directory
79
+ init <name> Create ./<name>/ and scaffold a self-contained single-app project inside it
80
80
  (use --db to wire SQLite/migrations, --auth betterAuth|auth0 for auth guards, --tailwind for Tailwind CSS)
81
81
  new <name> Create a new app at <workspace>/<name>/ and register it in elm-ssr.config.json
82
82
  (use --in <subdir> to group, --db for SQLite, --auth betterAuth|auth0 for auth, --tailwind for Tailwind)
@@ -212,8 +212,15 @@ switch (command) {
212
212
  }
213
213
  }
214
214
 
215
- const created = await createAppScaffold(rootPath, name, { root: ".", db, auth, tailwind });
216
- console.log(`Initialized ${created.name} in current directory`);
215
+ // Create a dedicated directory for the project elm-ssr init t creates ./t/
216
+ // and scaffolds a self-contained single-app project inside it (root: ".").
217
+ const { mkdir: mkdirFn } = await import("node:fs/promises");
218
+ const targetDir = resolve(rootPath, name);
219
+ await mkdirFn(targetDir, { recursive: true });
220
+
221
+ const created = await createAppScaffold(targetDir, name, { root: ".", db, auth, tailwind });
222
+ console.log(`Initialized ${created.name} in ./${name}/`);
223
+ console.log(`\nNext:\n cd ${name}\n bun install\n bun run build\n bun run dev`);
217
224
  break;
218
225
  }
219
226
 
package/lib/scaffold.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { mkdir, readFile, writeFile } from "node:fs/promises";
1
+ import { mkdir, readFile, stat, writeFile } from "node:fs/promises";
2
2
  import { dirname, resolve } from "node:path";
3
3
  import { readWorkspaceConfig, writeWorkspaceConfig } from "./workspace.mjs";
4
4
 
@@ -633,15 +633,22 @@ export default worker;
633
633
  `;
634
634
 
635
635
  const stylesTemplate = () => `export const stylesheet = \`
636
+ @import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap");
637
+
638
+ *, *::before, *::after {
639
+ box-sizing: border-box;
640
+ }
641
+
636
642
  :root {
637
643
  color-scheme: light;
638
- font-family: "IBM Plex Sans", sans-serif;
639
- background: #f3efe7;
644
+ font-family: "Inter", ui-sans-serif, system-ui, -apple-system, sans-serif;
645
+ font-size: 16px;
640
646
  color: #18222f;
641
647
  }
642
648
 
643
649
  body {
644
650
  margin: 0;
651
+ min-height: 100vh;
645
652
  background:
646
653
  radial-gradient(circle at top, rgba(255, 255, 255, 0.85), transparent 45%),
647
654
  linear-gradient(180deg, #f8f3ea 0%, #efe7dc 100%);
@@ -653,40 +660,146 @@ body {
653
660
  padding: 4rem 1.5rem;
654
661
  }
655
662
 
656
- .counter {
657
- display: grid;
658
- grid-template-columns: auto 1fr auto;
659
- gap: 0.75rem;
660
- align-items: center;
661
- margin: 2rem 0;
663
+ h1 {
664
+ font-size: 2rem;
665
+ font-weight: 700;
666
+ letter-spacing: -0.02em;
667
+ margin: 0 0 1rem;
668
+ color: #18222f;
662
669
  }
663
670
 
664
- .button,
665
- .input {
671
+ h2 {
672
+ font-size: 1.4rem;
673
+ font-weight: 600;
674
+ margin: 0 0 0.75rem;
675
+ color: #18222f;
676
+ }
677
+
678
+ p {
679
+ line-height: 1.6;
680
+ margin: 0 0 1rem;
681
+ color: #4a5568;
682
+ }
683
+
684
+ a.link {
685
+ color: #18222f;
686
+ text-decoration: underline;
687
+ text-underline-offset: 2px;
688
+ }
689
+
690
+ a.link:hover {
691
+ text-decoration: none;
692
+ }
693
+
694
+ .button {
695
+ display: inline-flex;
696
+ align-items: center;
697
+ gap: 0.5rem;
666
698
  border-radius: 999px;
667
- border: 1px solid #18222f;
668
- padding: 0.85rem 1.1rem;
699
+ border: 1.5px solid #18222f;
700
+ padding: 0.6rem 1.2rem;
669
701
  font: inherit;
702
+ font-size: 0.9rem;
703
+ font-weight: 500;
670
704
  background: white;
705
+ color: #18222f;
706
+ cursor: pointer;
707
+ text-decoration: none;
708
+ transition: background 0.15s, color 0.15s;
671
709
  }
672
710
 
673
- .button {
674
- cursor: pointer;
711
+ .button:hover {
712
+ background: #f0ebe3;
713
+ }
714
+
715
+ .button.primary {
716
+ background: #18222f;
717
+ color: white;
718
+ border-color: #18222f;
719
+ }
720
+
721
+ .button.primary:hover {
722
+ background: #2d3748;
723
+ }
724
+
725
+ .counter {
726
+ display: grid;
727
+ grid-template-columns: auto 1fr auto;
728
+ gap: 0.75rem;
729
+ align-items: center;
730
+ margin: 2rem 0;
675
731
  }
676
732
 
677
733
  .value {
678
734
  text-align: center;
679
- font-size: 2rem;
735
+ font-size: 2.5rem;
680
736
  font-weight: 700;
737
+ color: #18222f;
681
738
  }
682
739
 
683
740
  .form {
684
- margin-top: 1rem;
741
+ display: flex;
742
+ flex-direction: column;
743
+ gap: 1rem;
744
+ margin-top: 1.5rem;
745
+ }
746
+
747
+ .field {
748
+ display: flex;
749
+ flex-direction: column;
750
+ gap: 0.35rem;
751
+ }
752
+
753
+ .field label,
754
+ .field span {
755
+ font-size: 0.875rem;
756
+ font-weight: 500;
757
+ color: #4a5568;
685
758
  }
686
759
 
687
760
  .input {
688
761
  width: 100%;
689
- box-sizing: border-box;
762
+ border-radius: 8px;
763
+ border: 1.5px solid #d1cdc7;
764
+ padding: 0.65rem 0.9rem;
765
+ font: inherit;
766
+ font-size: 0.95rem;
767
+ background: white;
768
+ color: #18222f;
769
+ transition: border-color 0.15s;
770
+ }
771
+
772
+ .input:focus {
773
+ outline: none;
774
+ border-color: #18222f;
775
+ }
776
+
777
+ .login-container {
778
+ margin-top: 2rem;
779
+ padding: 2rem;
780
+ background: white;
781
+ border-radius: 12px;
782
+ border: 1px solid rgba(0, 0, 0, 0.08);
783
+ max-width: 22rem;
784
+ }
785
+
786
+ .card {
787
+ padding: 1.5rem;
788
+ background: white;
789
+ border-radius: 12px;
790
+ border: 1px solid rgba(0, 0, 0, 0.08);
791
+ margin-bottom: 1rem;
792
+ }
793
+
794
+ .muted {
795
+ color: #718096;
796
+ font-size: 0.875rem;
797
+ }
798
+
799
+ .error {
800
+ color: #c53030;
801
+ font-size: 0.875rem;
802
+ margin-top: 0.25rem;
690
803
  }
691
804
  \`;
692
805
  `;
@@ -749,6 +862,69 @@ SESSION_SECRET="change-me-to-a-secure-random-hmac-secret-key-that-is-at-least-32
749
862
  content: `@tailwind base;
750
863
  @tailwind components;
751
864
  @tailwind utilities;
865
+
866
+ @layer base {
867
+ *, *::before, *::after { box-sizing: border-box; }
868
+ h1 { @apply text-3xl font-bold tracking-tight text-gray-900 mb-4; }
869
+ h2 { @apply text-xl font-semibold text-gray-900 mb-3; }
870
+ p { @apply leading-relaxed text-gray-600 mb-4; }
871
+ a { @apply text-gray-900 underline underline-offset-2 hover:no-underline; }
872
+ }
873
+
874
+ @layer components {
875
+ .shell {
876
+ @apply max-w-2xl mx-auto px-6 py-16;
877
+ }
878
+
879
+ .button {
880
+ @apply inline-flex items-center gap-2 rounded-full border border-gray-900
881
+ px-5 py-2.5 text-sm font-medium bg-white text-gray-900 no-underline
882
+ cursor-pointer transition-colors hover:bg-gray-50;
883
+ }
884
+
885
+ .button.primary {
886
+ @apply bg-gray-900 text-white hover:bg-gray-700;
887
+ }
888
+
889
+ .counter {
890
+ @apply my-8 grid items-center gap-3;
891
+ grid-template-columns: auto 1fr auto;
892
+ }
893
+
894
+ .value {
895
+ @apply text-center text-5xl font-bold text-gray-900;
896
+ }
897
+
898
+ .form {
899
+ @apply flex flex-col gap-4 mt-6;
900
+ }
901
+
902
+ .field {
903
+ @apply flex flex-col gap-1.5;
904
+ }
905
+
906
+ .input {
907
+ @apply w-full rounded-lg border border-gray-300 px-3.5 py-2.5 text-sm
908
+ bg-white text-gray-900 focus:outline-none focus:border-gray-900
909
+ transition-colors;
910
+ }
911
+
912
+ .login-container {
913
+ @apply mt-8 p-8 bg-white rounded-xl border border-gray-100 max-w-sm;
914
+ }
915
+
916
+ .card {
917
+ @apply p-6 bg-white rounded-xl border border-gray-100 mb-4;
918
+ }
919
+
920
+ .muted {
921
+ @apply text-gray-500 text-sm;
922
+ }
923
+
924
+ .error {
925
+ @apply text-red-600 text-sm mt-1;
926
+ }
927
+ }
752
928
  `
753
929
  });
754
930
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elm-ssr",
3
- "version": "0.99.0",
3
+ "version": "1.0.0",
4
4
  "description": "Elm-first SSR library and framework for Cloudflare Workers (and Bun): file-based routes/islands, backend-neutral effect adapters (KV/D1/Redis/Postgres), background tasks (waitUntil/Queues), SQL-file migrations, CLI scaffold + build.",
5
5
  "license": "MIT",
6
6
  "author": "Michał Majchrzak <michmajchrzak@gmail.com>",