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 +10 -3
- package/lib/scaffold.mjs +194 -18
- package/package.json +1 -1
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>
|
|
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
|
-
|
|
216
|
-
|
|
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: "
|
|
639
|
-
|
|
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
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
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
|
-
|
|
665
|
-
.
|
|
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:
|
|
668
|
-
padding: 0.
|
|
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
|
-
|
|
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:
|
|
735
|
+
font-size: 2.5rem;
|
|
680
736
|
font-weight: 700;
|
|
737
|
+
color: #18222f;
|
|
681
738
|
}
|
|
682
739
|
|
|
683
740
|
.form {
|
|
684
|
-
|
|
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
|
-
|
|
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.
|
|
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>",
|