create-atsdc-stack 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.
@@ -0,0 +1,87 @@
1
+ ---
2
+ /**
3
+ * Home Page
4
+ * Demonstrates SCSS architecture:
5
+ * - No inline styles
6
+ * - All styles imported from external SCSS file
7
+ * - Component-specific styles in separate files
8
+ */
9
+ import Layout from '@/layouts/Layout.astro';
10
+ import { siteConfig } from '@/lib/config';
11
+
12
+ // Import component-specific styles
13
+ import '@/styles/components/button.scss';
14
+ import '@/styles/pages/index.scss';
15
+ ---
16
+
17
+ <Layout pageTitle="Home">
18
+ <main class="home">
19
+ <div class="container">
20
+ <header class="home__header">
21
+ <h1 class="home__title">Welcome to {siteConfig.stackName}</h1>
22
+ <p class="home__subtitle">
23
+ A production-ready full-stack framework combining the best modern web technologies
24
+ </p>
25
+ </header>
26
+
27
+ <section class="home__features">
28
+ <div class="home__feature card">
29
+ <h3>⚡ Astro</h3>
30
+ <p>Lightning-fast static site generation with dynamic capabilities</p>
31
+ </div>
32
+
33
+ <div class="home__feature card">
34
+ <h3>📘 TypeScript</h3>
35
+ <p>Full type safety across your entire application</p>
36
+ </div>
37
+
38
+ <div class="home__feature card">
39
+ <h3>🗄️ Drizzle ORM</h3>
40
+ <p>Type-safe database operations with PostgreSQL</p>
41
+ </div>
42
+
43
+ <div class="home__feature card">
44
+ <h3>🔐 Clerk</h3>
45
+ <p>Complete authentication and user management</p>
46
+ </div>
47
+
48
+ <div class="home__feature card">
49
+ <h3>🎨 SCSS</h3>
50
+ <p>Powerful styling with variables, mixins, and modules</p>
51
+ </div>
52
+
53
+ <div class="home__feature card">
54
+ <h3>✅ Zod</h3>
55
+ <p>Runtime validation for API routes and forms</p>
56
+ </div>
57
+
58
+ <div class="home__feature card">
59
+ <h3>🤖 Vercel AI SDK</h3>
60
+ <p>Seamless integration with AI language models</p>
61
+ </div>
62
+
63
+ <div class="home__feature card">
64
+ <h3>🔑 NanoID</h3>
65
+ <p>Secure, URL-friendly unique identifiers</p>
66
+ </div>
67
+
68
+ <div class="home__feature card">
69
+ <h3>📱 PWA</h3>
70
+ <p>Progressive Web App with offline capabilities</p>
71
+ </div>
72
+ </section>
73
+
74
+ <section class="home__cta">
75
+ <h2>Get Started</h2>
76
+ <div class="home__cta-buttons">
77
+ <a href={siteConfig.docsUrl} class="btn btn-primary btn-lg">
78
+ Read Documentation
79
+ </a>
80
+ <a href={siteConfig.githubUrl} class="btn btn-secondary btn-lg">
81
+ View on GitHub
82
+ </a>
83
+ </div>
84
+ </section>
85
+ </div>
86
+ </main>
87
+ </Layout>
@@ -0,0 +1,152 @@
1
+ @use 'sass:color';
2
+ @use '../variables/globals' as *;
3
+ @use '../variables/mixins' as *;
4
+
5
+ // Button component styles
6
+ // Usage (preferred): <button class="btn" data-variant="primary" data-size="lg">Click me</button>
7
+ // Usage (alternative): <button class="btn primary lg">Class chaining</button>
8
+
9
+ .btn {
10
+ @include button-base;
11
+
12
+ // Variant modifiers using data attributes (preferred for state/variants)
13
+ &[data-variant='primary'] {
14
+ @include button-primary;
15
+ }
16
+
17
+ &[data-variant='secondary'] {
18
+ @include button-secondary;
19
+ }
20
+
21
+ &[data-variant='danger'] {
22
+ background-color: $error-color;
23
+ color: $text-inverse;
24
+
25
+ &:hover:not(:disabled) {
26
+ background-color: color.adjust($error-color, $lightness: -10%);
27
+ }
28
+ }
29
+
30
+ &[data-variant='success'] {
31
+ background-color: $success-color;
32
+ color: $text-inverse;
33
+
34
+ &:hover:not(:disabled) {
35
+ background-color: color.adjust($success-color, $lightness: -10%);
36
+ }
37
+ }
38
+
39
+ // Size modifiers using data attributes
40
+ &[data-size='small'] {
41
+ padding: $spacing-extra-small $spacing-small;
42
+ font-size: $font-size-small;
43
+ }
44
+
45
+ &[data-size='large'] {
46
+ padding: $spacing-medium $spacing-extra-large;
47
+ font-size: $font-size-large;
48
+ }
49
+
50
+ // State modifiers using data attributes
51
+ &[data-state='loading'] {
52
+ position: relative;
53
+ color: transparent;
54
+ pointer-events: none;
55
+
56
+ &::after {
57
+ content: '';
58
+ position: absolute;
59
+ width: 1rem;
60
+ height: 1rem;
61
+ top: 50%;
62
+ left: 50%;
63
+ margin-left: -0.5rem;
64
+ margin-top: -0.5rem;
65
+ border: 2px solid transparent;
66
+ border-top-color: currentColor;
67
+ border-radius: 50%;
68
+ animation: button-spin 0.6s linear infinite;
69
+ }
70
+ }
71
+
72
+ &[data-state='active'] {
73
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
74
+ }
75
+
76
+ // Layout modifiers using data attributes
77
+ &[data-width='full'] {
78
+ width: 100%;
79
+ }
80
+
81
+ &[data-has-icon='true'] {
82
+ display: inline-flex;
83
+ align-items: center;
84
+ gap: $spacing-small;
85
+
86
+ svg {
87
+ width: 1.25rem;
88
+ height: 1.25rem;
89
+ }
90
+ }
91
+
92
+ // Alternative: Class chaining for variants when data attributes aren't appropriate
93
+ // Use this when you need CSS-only solutions or when data attributes feel verbose
94
+ &.primary {
95
+ @include button-primary;
96
+ }
97
+
98
+ &.secondary {
99
+ @include button-secondary;
100
+ }
101
+
102
+ &.danger {
103
+ background-color: $error-color;
104
+ color: $text-inverse;
105
+
106
+ &:hover:not(:disabled) {
107
+ background-color: color.adjust($error-color, $lightness: -10%);
108
+ }
109
+ }
110
+
111
+ &.success {
112
+ background-color: $success-color;
113
+ color: $text-inverse;
114
+
115
+ &:hover:not(:disabled) {
116
+ background-color: color.adjust($success-color, $lightness: -10%);
117
+ }
118
+ }
119
+
120
+ // Size class chaining alternatives
121
+ &.small {
122
+ padding: $spacing-extra-small $spacing-small;
123
+ font-size: $font-size-small;
124
+ }
125
+
126
+ &.large {
127
+ padding: $spacing-medium $spacing-extra-large;
128
+ font-size: $font-size-large;
129
+ }
130
+
131
+ // Layout class chaining alternatives
132
+ &.full {
133
+ width: 100%;
134
+ }
135
+
136
+ &.with-icon {
137
+ display: inline-flex;
138
+ align-items: center;
139
+ gap: $spacing-small;
140
+
141
+ svg {
142
+ width: 1.25rem;
143
+ height: 1.25rem;
144
+ }
145
+ }
146
+ }
147
+
148
+ @keyframes button-spin {
149
+ to {
150
+ transform: rotate(360deg);
151
+ }
152
+ }
@@ -0,0 +1,180 @@
1
+ @use '../variables/globals' as *;
2
+ @use '../variables/mixins' as *;
3
+
4
+ // Card component styles
5
+ // Usage (preferred): <div class="card" data-variant="primary" data-state="active">...</div>
6
+ // Usage (alternative): <div class="card primary active">Class chaining</div>
7
+
8
+ .card-component {
9
+ @include card;
10
+ display: block;
11
+ text-decoration: none;
12
+ color: inherit;
13
+ transition: all $transition-base;
14
+
15
+ &:hover {
16
+ transform: translateY(-2px);
17
+ box-shadow: $shadow-large;
18
+ }
19
+
20
+ &__title {
21
+ font-size: $font-size-extra-large;
22
+ font-weight: $font-weight-semibold;
23
+ color: $text-primary;
24
+ margin-bottom: $spacing-medium;
25
+ }
26
+
27
+ &__content {
28
+ color: $text-secondary;
29
+ line-height: $line-height-relaxed;
30
+
31
+ p:last-child {
32
+ margin-bottom: 0;
33
+ }
34
+ }
35
+
36
+ // Variant modifiers using data attributes (preferred)
37
+ &[data-variant='primary'] {
38
+ border-color: $primary-color;
39
+ background: linear-gradient(135deg, rgba($primary-color, 0.05) 0%, transparent 100%);
40
+ }
41
+
42
+ &[data-variant='secondary'] {
43
+ border-color: $secondary-color;
44
+ background: linear-gradient(135deg, rgba($secondary-color, 0.05) 0%, transparent 100%);
45
+ }
46
+
47
+ &[data-variant='accent'] {
48
+ border-color: $accent-color;
49
+ background: linear-gradient(135deg, rgba($accent-color, 0.05) 0%, transparent 100%);
50
+ }
51
+
52
+ &[data-variant='ghost'] {
53
+ border-color: transparent;
54
+ background: transparent;
55
+ box-shadow: none;
56
+
57
+ &:hover {
58
+ background-color: $bg-secondary;
59
+ }
60
+ }
61
+
62
+ // State modifiers using data attributes
63
+ &[data-state='active'] {
64
+ border-color: $primary-color;
65
+ box-shadow: $shadow-medium;
66
+ }
67
+
68
+ &[data-state='disabled'] {
69
+ opacity: 0.6;
70
+ pointer-events: none;
71
+ cursor: not-allowed;
72
+ }
73
+
74
+ &[data-state='loading'] {
75
+ position: relative;
76
+ opacity: 0.7;
77
+ pointer-events: none;
78
+
79
+ &::after {
80
+ content: '';
81
+ position: absolute;
82
+ top: 50%;
83
+ left: 50%;
84
+ width: 2rem;
85
+ height: 2rem;
86
+ margin: -1rem 0 0 -1rem;
87
+ border: 3px solid $border-color;
88
+ border-top-color: $primary-color;
89
+ border-radius: 50%;
90
+ animation: card-spin 0.8s linear infinite;
91
+ }
92
+ }
93
+
94
+ // Layout modifiers using data attributes
95
+ &[data-padding='compact'] {
96
+ padding: $spacing-medium;
97
+ }
98
+
99
+ &[data-padding='comfortable'] {
100
+ padding: $spacing-2x-large;
101
+ }
102
+
103
+ &[data-hover='lift'] {
104
+ &:hover {
105
+ transform: translateY(-4px);
106
+ box-shadow: $shadow-extra-large;
107
+ }
108
+ }
109
+
110
+ &[data-hover='none'] {
111
+ &:hover {
112
+ transform: none;
113
+ box-shadow: $shadow-small;
114
+ }
115
+ }
116
+
117
+ // Alternative: Class chaining when data attributes aren't appropriate
118
+ &.primary {
119
+ border-color: $primary-color;
120
+ background: linear-gradient(135deg, rgba($primary-color, 0.05) 0%, transparent 100%);
121
+ }
122
+
123
+ &.secondary {
124
+ border-color: $secondary-color;
125
+ background: linear-gradient(135deg, rgba($secondary-color, 0.05) 0%, transparent 100%);
126
+ }
127
+
128
+ &.accent {
129
+ border-color: $accent-color;
130
+ background: linear-gradient(135deg, rgba($accent-color, 0.05) 0%, transparent 100%);
131
+ }
132
+
133
+ &.ghost {
134
+ border-color: transparent;
135
+ background: transparent;
136
+ box-shadow: none;
137
+
138
+ &:hover {
139
+ background-color: $bg-secondary;
140
+ }
141
+ }
142
+
143
+ // State class chaining alternatives
144
+ &.active {
145
+ border-color: $primary-color;
146
+ box-shadow: $shadow-medium;
147
+ }
148
+
149
+ &.disabled {
150
+ opacity: 0.6;
151
+ pointer-events: none;
152
+ cursor: not-allowed;
153
+ }
154
+
155
+ &.loading {
156
+ position: relative;
157
+ opacity: 0.7;
158
+ pointer-events: none;
159
+
160
+ &::after {
161
+ content: '';
162
+ position: absolute;
163
+ top: 50%;
164
+ left: 50%;
165
+ width: 2rem;
166
+ height: 2rem;
167
+ margin: -1rem 0 0 -1rem;
168
+ border: 3px solid $border-color;
169
+ border-top-color: $primary-color;
170
+ border-radius: 50%;
171
+ animation: card-spin 0.8s linear infinite;
172
+ }
173
+ }
174
+ }
175
+
176
+ @keyframes card-spin {
177
+ to {
178
+ transform: rotate(360deg);
179
+ }
180
+ }
@@ -0,0 +1,240 @@
1
+ @use '../variables/globals' as *;
2
+ @use '../variables/mixins' as *;
3
+
4
+ // Form component styles
5
+ // Usage (preferred): <input class="form-input" data-state="error" data-size="lg" />
6
+ // Usage (alternative): <input class="form-input error lg" />
7
+
8
+ .form {
9
+ width: 100%;
10
+ max-width: 600px;
11
+
12
+ &-group {
13
+ margin-bottom: $spacing-large;
14
+ }
15
+
16
+ &-label {
17
+ display: block;
18
+ margin-bottom: $spacing-extra-small;
19
+ font-size: $font-size-small;
20
+ font-weight: $font-weight-medium;
21
+ color: $text-primary;
22
+
23
+ // Use data attributes for required state
24
+ &[data-required='true']::after {
25
+ content: ' *';
26
+ color: $error-color;
27
+ }
28
+
29
+ // Alternative: class chaining
30
+ &.required::after {
31
+ content: ' *';
32
+ color: $error-color;
33
+ }
34
+ }
35
+
36
+ &-input,
37
+ &-textarea,
38
+ &-select {
39
+ @include input-base;
40
+
41
+ // State modifiers using data attributes (preferred)
42
+ &[data-state='error'] {
43
+ border-color: $error-color;
44
+
45
+ &:focus {
46
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
47
+ }
48
+ }
49
+
50
+ &[data-state='success'] {
51
+ border-color: $success-color;
52
+
53
+ &:focus {
54
+ box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
55
+ }
56
+ }
57
+
58
+ &[data-state='warning'] {
59
+ border-color: $warning-color;
60
+
61
+ &:focus {
62
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1);
63
+ }
64
+ }
65
+
66
+ // Size modifiers using data attributes
67
+ &[data-size='small'] {
68
+ padding: $spacing-extra-small $spacing-small;
69
+ font-size: $font-size-small;
70
+ }
71
+
72
+ &[data-size='large'] {
73
+ padding: $spacing-medium $spacing-large;
74
+ font-size: $font-size-large;
75
+ }
76
+
77
+ // Alternative: class chaining for states
78
+ &.error {
79
+ border-color: $error-color;
80
+
81
+ &:focus {
82
+ box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
83
+ }
84
+ }
85
+
86
+ &.success {
87
+ border-color: $success-color;
88
+
89
+ &:focus {
90
+ box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1);
91
+ }
92
+ }
93
+
94
+ &.warning {
95
+ border-color: $warning-color;
96
+
97
+ &:focus {
98
+ box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1);
99
+ }
100
+ }
101
+
102
+ // Size class chaining alternatives
103
+ &.small {
104
+ padding: $spacing-extra-small $spacing-small;
105
+ font-size: $font-size-small;
106
+ }
107
+
108
+ &.large {
109
+ padding: $spacing-medium $spacing-large;
110
+ font-size: $font-size-large;
111
+ }
112
+ }
113
+
114
+ &-textarea {
115
+ min-height: 120px;
116
+ resize: vertical;
117
+
118
+ &[data-resize='none'] {
119
+ resize: none;
120
+ }
121
+
122
+ &[data-resize='horizontal'] {
123
+ resize: horizontal;
124
+ }
125
+
126
+ &.no-resize {
127
+ resize: none;
128
+ }
129
+ }
130
+
131
+ &-select {
132
+ cursor: pointer;
133
+ appearance: none;
134
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E");
135
+ background-position: right $spacing-small center;
136
+ background-repeat: no-repeat;
137
+ background-size: 1.5rem 1.5rem;
138
+ padding-right: $spacing-2x-large;
139
+ }
140
+
141
+ &-helper {
142
+ margin-top: $spacing-extra-small;
143
+ font-size: $font-size-small;
144
+ color: $text-secondary;
145
+
146
+ &[data-state='error'] {
147
+ color: $error-color;
148
+ }
149
+
150
+ &[data-state='success'] {
151
+ color: $success-color;
152
+ }
153
+
154
+ &[data-state='warning'] {
155
+ color: $warning-color;
156
+ }
157
+ }
158
+
159
+ &-error {
160
+ margin-top: $spacing-extra-small;
161
+ font-size: $font-size-small;
162
+ color: $error-color;
163
+ }
164
+
165
+ &-checkbox,
166
+ &-radio {
167
+ display: flex;
168
+ align-items: center;
169
+ gap: $spacing-small;
170
+ margin-bottom: $spacing-small;
171
+
172
+ input {
173
+ width: 1.125rem;
174
+ height: 1.125rem;
175
+ cursor: pointer;
176
+ accent-color: $primary-color;
177
+ }
178
+
179
+ label {
180
+ cursor: pointer;
181
+ font-size: $font-size-base;
182
+ color: $text-primary;
183
+ }
184
+
185
+ &[data-state='disabled'] {
186
+ opacity: 0.5;
187
+ cursor: not-allowed;
188
+
189
+ input,
190
+ label {
191
+ cursor: not-allowed;
192
+ }
193
+ }
194
+
195
+ // Alternative class chaining
196
+ &.disabled {
197
+ opacity: 0.5;
198
+ cursor: not-allowed;
199
+
200
+ input,
201
+ label {
202
+ cursor: not-allowed;
203
+ }
204
+ }
205
+ }
206
+
207
+ &-actions {
208
+ @include flex-between;
209
+ margin-top: $spacing-extra-large;
210
+ gap: $spacing-medium;
211
+
212
+ &[data-layout='stack'] {
213
+ flex-direction: column;
214
+
215
+ button {
216
+ width: 100%;
217
+ }
218
+ }
219
+
220
+ &[data-align='center'] {
221
+ justify-content: center;
222
+ }
223
+
224
+ &[data-align='start'] {
225
+ justify-content: flex-start;
226
+ }
227
+
228
+ &[data-align='end'] {
229
+ justify-content: flex-end;
230
+ }
231
+
232
+ @media (max-width: $breakpoint-tablet) {
233
+ flex-direction: column;
234
+
235
+ button {
236
+ width: 100%;
237
+ }
238
+ }
239
+ }
240
+ }