create-atsdc-stack 1.1.0 → 1.2.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/.claude/settings.local.json +3 -1
- package/CLAUDE.md +236 -215
- package/CONTRIBUTING.md +342 -342
- package/INSTALLATION.md +359 -359
- package/LICENSE +201 -201
- package/README.md +405 -405
- package/app/.env.example +17 -17
- package/app/.github/labeler.yml +61 -0
- package/app/.github/workflows/browser-tests.yml +101 -0
- package/app/.github/workflows/check.yml +24 -0
- package/app/.github/workflows/greetings.yml +16 -0
- package/app/.github/workflows/label.yml +22 -0
- package/app/.github/workflows/stale.yml +27 -0
- package/app/.github/workflows/summary.yml +34 -0
- package/app/.stylelintrc.json +8 -0
- package/app/README.md +251 -251
- package/app/astro.config.mjs +83 -83
- package/app/drizzle.config.ts +16 -16
- package/app/package.json +66 -52
- package/app/playwright.config.ts +27 -0
- package/app/public/manifest.webmanifest +36 -36
- package/app/pwa-assets.config.ts +8 -0
- package/app/src/components/Card.astro +36 -36
- package/app/src/db/initialize.ts +107 -107
- package/app/src/db/schema.ts +72 -72
- package/app/src/db/validations.ts +158 -158
- package/app/src/layouts/Layout.astro +63 -63
- package/app/src/lib/config.ts +36 -36
- package/app/src/lib/content-converter.ts +141 -141
- package/app/src/lib/dom-utils.ts +230 -230
- package/app/src/lib/exa-search.ts +269 -269
- package/app/src/pages/api/chat.ts +91 -91
- package/app/src/pages/api/posts.ts +350 -350
- package/app/src/pages/index.astro +87 -87
- package/app/src/styles/components/button.scss +152 -152
- package/app/src/styles/components/card.scss +180 -180
- package/app/src/styles/components/form.scss +240 -240
- package/app/src/styles/global.scss +141 -141
- package/app/src/styles/pages/index.scss +80 -80
- package/app/src/styles/reset.scss +83 -83
- package/app/src/styles/variables/globals.scss +96 -96
- package/app/src/styles/variables/mixins.scss +238 -238
- package/app/tests/browser.test.nopause.ts +10 -0
- package/app/tests/browser.test.ts +13 -0
- package/bin/cli.js +1151 -1151
- package/package.json +8 -6
- package/app/.astro/settings.json +0 -5
- package/app/.astro/types.d.ts +0 -1
|
@@ -1,96 +1,96 @@
|
|
|
1
|
-
// Color palette
|
|
2
|
-
$primary-color: #4f46e5;
|
|
3
|
-
$primary-hover: #4338ca;
|
|
4
|
-
$secondary-color: #06b6d4;
|
|
5
|
-
$accent-color: #f59e0b;
|
|
6
|
-
|
|
7
|
-
// Text colors
|
|
8
|
-
$text-primary: #1f2937;
|
|
9
|
-
$text-secondary: #6b7280;
|
|
10
|
-
$text-light: #9ca3af;
|
|
11
|
-
$text-inverse: #ffffff;
|
|
12
|
-
|
|
13
|
-
// Background colors
|
|
14
|
-
$bg-primary: #ffffff;
|
|
15
|
-
$bg-secondary: #f9fafb;
|
|
16
|
-
$bg-tertiary: #f3f4f6;
|
|
17
|
-
$bg-dark: #111827;
|
|
18
|
-
|
|
19
|
-
// Border colors
|
|
20
|
-
$border-color: #e5e7eb;
|
|
21
|
-
$border-focus: #4f46e5;
|
|
22
|
-
|
|
23
|
-
// Status colors
|
|
24
|
-
$success-color: #10b981;
|
|
25
|
-
$warning-color: #f59e0b;
|
|
26
|
-
$error-color: #ef4444;
|
|
27
|
-
$info-color: #3b82f6;
|
|
28
|
-
|
|
29
|
-
// Spacing scale (using OpenProps size tokens)
|
|
30
|
-
$spacing-extra-small: var(--size-2); // 0.5rem
|
|
31
|
-
$spacing-small: var(--size-3); // 1rem
|
|
32
|
-
$spacing-medium: var(--size-4); // 1.25rem
|
|
33
|
-
$spacing-large: var(--size-5); // 1.5rem
|
|
34
|
-
$spacing-extra-large: var(--size-6); // 1.75rem
|
|
35
|
-
$spacing-2x-large: var(--size-8); // 3rem
|
|
36
|
-
$spacing-3x-large: var(--size-10); // 4rem
|
|
37
|
-
|
|
38
|
-
// Typography
|
|
39
|
-
$font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
40
|
-
$font-family-mono: 'Fira Code', 'Consolas', 'Monaco', 'Courier New', monospace;
|
|
41
|
-
|
|
42
|
-
// Font sizes (using OpenProps font-size tokens)
|
|
43
|
-
$font-size-extra-small: var(--font-size-0); // 0.75rem
|
|
44
|
-
$font-size-small: var(--font-size-1); // 0.875rem
|
|
45
|
-
$font-size-base: var(--font-size-2); // 1rem
|
|
46
|
-
$font-size-large: var(--font-size-3); // 1.125rem
|
|
47
|
-
$font-size-extra-large: var(--font-size-4); // 1.25rem
|
|
48
|
-
$font-size-2x-large: var(--font-size-5); // 1.5rem
|
|
49
|
-
$font-size-3x-large: var(--font-size-6); // 1.875rem
|
|
50
|
-
$font-size-4x-large: var(--font-size-7); // 2.25rem
|
|
51
|
-
|
|
52
|
-
// Font weights (using OpenProps font-weight tokens)
|
|
53
|
-
$font-weight-normal: var(--font-weight-4); // 400
|
|
54
|
-
$font-weight-medium: var(--font-weight-5); // 500
|
|
55
|
-
$font-weight-semibold: var(--font-weight-6); // 600
|
|
56
|
-
$font-weight-bold: var(--font-weight-7); // 700
|
|
57
|
-
|
|
58
|
-
// Line heights (using OpenProps lineheight tokens)
|
|
59
|
-
$line-height-tight: var(--font-lineheight-0); // 1.25
|
|
60
|
-
$line-height-normal: var(--font-lineheight-3);// 1.5
|
|
61
|
-
$line-height-relaxed: var(--font-lineheight-4);// 1.75
|
|
62
|
-
|
|
63
|
-
// Border radius (using OpenProps radius tokens)
|
|
64
|
-
$radius-small: var(--radius-2); // 0.25rem
|
|
65
|
-
$radius-medium: var(--radius-3); // 0.5rem
|
|
66
|
-
$radius-large: var(--radius-4); // 1rem
|
|
67
|
-
$radius-extra-large: var(--radius-5); // 1.5rem
|
|
68
|
-
$radius-2x-large: var(--radius-6); // 2rem
|
|
69
|
-
$radius-full: var(--radius-round); // 9999px
|
|
70
|
-
|
|
71
|
-
// Shadows (using OpenProps shadow tokens)
|
|
72
|
-
$shadow-small: var(--shadow-2); // Subtle shadow
|
|
73
|
-
$shadow-medium: var(--shadow-3); // Medium shadow
|
|
74
|
-
$shadow-large: var(--shadow-4); // Large shadow
|
|
75
|
-
$shadow-extra-large: var(--shadow-6); // Extra large shadow
|
|
76
|
-
|
|
77
|
-
// Transitions (using OpenProps easing tokens)
|
|
78
|
-
$transition-fast: var(--ease-1); // Fast spring easing
|
|
79
|
-
$transition-base: var(--ease-3); // Standard easing
|
|
80
|
-
$transition-slow: var(--ease-4); // Slow easing
|
|
81
|
-
|
|
82
|
-
// Breakpoints
|
|
83
|
-
$breakpoint-tablet: 640px;
|
|
84
|
-
$breakpoint-desktop: 768px;
|
|
85
|
-
$breakpoint-wide: 1024px;
|
|
86
|
-
$breakpoint-extra-wide: 1280px;
|
|
87
|
-
$breakpoint-ultra-wide: 1536px;
|
|
88
|
-
|
|
89
|
-
// Z-index scale
|
|
90
|
-
$z-dropdown: 1000;
|
|
91
|
-
$z-sticky: 1020;
|
|
92
|
-
$z-fixed: 1030;
|
|
93
|
-
$z-modal-backdrop: 1040;
|
|
94
|
-
$z-modal: 1050;
|
|
95
|
-
$z-popover: 1060;
|
|
96
|
-
$z-tooltip: 1070;
|
|
1
|
+
// Color palette
|
|
2
|
+
$primary-color: #4f46e5;
|
|
3
|
+
$primary-hover: #4338ca;
|
|
4
|
+
$secondary-color: #06b6d4;
|
|
5
|
+
$accent-color: #f59e0b;
|
|
6
|
+
|
|
7
|
+
// Text colors
|
|
8
|
+
$text-primary: #1f2937;
|
|
9
|
+
$text-secondary: #6b7280;
|
|
10
|
+
$text-light: #9ca3af;
|
|
11
|
+
$text-inverse: #ffffff;
|
|
12
|
+
|
|
13
|
+
// Background colors
|
|
14
|
+
$bg-primary: #ffffff;
|
|
15
|
+
$bg-secondary: #f9fafb;
|
|
16
|
+
$bg-tertiary: #f3f4f6;
|
|
17
|
+
$bg-dark: #111827;
|
|
18
|
+
|
|
19
|
+
// Border colors
|
|
20
|
+
$border-color: #e5e7eb;
|
|
21
|
+
$border-focus: #4f46e5;
|
|
22
|
+
|
|
23
|
+
// Status colors
|
|
24
|
+
$success-color: #10b981;
|
|
25
|
+
$warning-color: #f59e0b;
|
|
26
|
+
$error-color: #ef4444;
|
|
27
|
+
$info-color: #3b82f6;
|
|
28
|
+
|
|
29
|
+
// Spacing scale (using OpenProps size tokens)
|
|
30
|
+
$spacing-extra-small: var(--size-2); // 0.5rem
|
|
31
|
+
$spacing-small: var(--size-3); // 1rem
|
|
32
|
+
$spacing-medium: var(--size-4); // 1.25rem
|
|
33
|
+
$spacing-large: var(--size-5); // 1.5rem
|
|
34
|
+
$spacing-extra-large: var(--size-6); // 1.75rem
|
|
35
|
+
$spacing-2x-large: var(--size-8); // 3rem
|
|
36
|
+
$spacing-3x-large: var(--size-10); // 4rem
|
|
37
|
+
|
|
38
|
+
// Typography
|
|
39
|
+
$font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
|
|
40
|
+
$font-family-mono: 'Fira Code', 'Consolas', 'Monaco', 'Courier New', monospace;
|
|
41
|
+
|
|
42
|
+
// Font sizes (using OpenProps font-size tokens)
|
|
43
|
+
$font-size-extra-small: var(--font-size-0); // 0.75rem
|
|
44
|
+
$font-size-small: var(--font-size-1); // 0.875rem
|
|
45
|
+
$font-size-base: var(--font-size-2); // 1rem
|
|
46
|
+
$font-size-large: var(--font-size-3); // 1.125rem
|
|
47
|
+
$font-size-extra-large: var(--font-size-4); // 1.25rem
|
|
48
|
+
$font-size-2x-large: var(--font-size-5); // 1.5rem
|
|
49
|
+
$font-size-3x-large: var(--font-size-6); // 1.875rem
|
|
50
|
+
$font-size-4x-large: var(--font-size-7); // 2.25rem
|
|
51
|
+
|
|
52
|
+
// Font weights (using OpenProps font-weight tokens)
|
|
53
|
+
$font-weight-normal: var(--font-weight-4); // 400
|
|
54
|
+
$font-weight-medium: var(--font-weight-5); // 500
|
|
55
|
+
$font-weight-semibold: var(--font-weight-6); // 600
|
|
56
|
+
$font-weight-bold: var(--font-weight-7); // 700
|
|
57
|
+
|
|
58
|
+
// Line heights (using OpenProps lineheight tokens)
|
|
59
|
+
$line-height-tight: var(--font-lineheight-0); // 1.25
|
|
60
|
+
$line-height-normal: var(--font-lineheight-3);// 1.5
|
|
61
|
+
$line-height-relaxed: var(--font-lineheight-4);// 1.75
|
|
62
|
+
|
|
63
|
+
// Border radius (using OpenProps radius tokens)
|
|
64
|
+
$radius-small: var(--radius-2); // 0.25rem
|
|
65
|
+
$radius-medium: var(--radius-3); // 0.5rem
|
|
66
|
+
$radius-large: var(--radius-4); // 1rem
|
|
67
|
+
$radius-extra-large: var(--radius-5); // 1.5rem
|
|
68
|
+
$radius-2x-large: var(--radius-6); // 2rem
|
|
69
|
+
$radius-full: var(--radius-round); // 9999px
|
|
70
|
+
|
|
71
|
+
// Shadows (using OpenProps shadow tokens)
|
|
72
|
+
$shadow-small: var(--shadow-2); // Subtle shadow
|
|
73
|
+
$shadow-medium: var(--shadow-3); // Medium shadow
|
|
74
|
+
$shadow-large: var(--shadow-4); // Large shadow
|
|
75
|
+
$shadow-extra-large: var(--shadow-6); // Extra large shadow
|
|
76
|
+
|
|
77
|
+
// Transitions (using OpenProps easing tokens)
|
|
78
|
+
$transition-fast: var(--ease-1); // Fast spring easing
|
|
79
|
+
$transition-base: var(--ease-3); // Standard easing
|
|
80
|
+
$transition-slow: var(--ease-4); // Slow easing
|
|
81
|
+
|
|
82
|
+
// Breakpoints
|
|
83
|
+
$breakpoint-tablet: 640px;
|
|
84
|
+
$breakpoint-desktop: 768px;
|
|
85
|
+
$breakpoint-wide: 1024px;
|
|
86
|
+
$breakpoint-extra-wide: 1280px;
|
|
87
|
+
$breakpoint-ultra-wide: 1536px;
|
|
88
|
+
|
|
89
|
+
// Z-index scale
|
|
90
|
+
$z-dropdown: 1000;
|
|
91
|
+
$z-sticky: 1020;
|
|
92
|
+
$z-fixed: 1030;
|
|
93
|
+
$z-modal-backdrop: 1040;
|
|
94
|
+
$z-modal: 1050;
|
|
95
|
+
$z-popover: 1060;
|
|
96
|
+
$z-tooltip: 1070;
|
|
@@ -1,238 +1,238 @@
|
|
|
1
|
-
@use './globals' as *;
|
|
2
|
-
|
|
3
|
-
// NOTE: All mixins below use variables from globals.scss which are now powered by OpenProps design tokens
|
|
4
|
-
// This provides consistent spacing, typography, shadows, and other design primitives throughout the app
|
|
5
|
-
|
|
6
|
-
// Responsive breakpoint mixins
|
|
7
|
-
@mixin tablet {
|
|
8
|
-
@media (min-width: $breakpoint-tablet) {
|
|
9
|
-
@content;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
@mixin desktop {
|
|
14
|
-
@media (min-width: $breakpoint-desktop) {
|
|
15
|
-
@content;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
@mixin wide {
|
|
20
|
-
@media (min-width: $breakpoint-wide) {
|
|
21
|
-
@content;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@mixin extra-wide {
|
|
26
|
-
@media (min-width: $breakpoint-extra-wide) {
|
|
27
|
-
@content;
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
@mixin ultra-wide {
|
|
32
|
-
@media (min-width: $breakpoint-ultra-wide) {
|
|
33
|
-
@content;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Flexbox utilities
|
|
38
|
-
@mixin flex-center {
|
|
39
|
-
display: flex;
|
|
40
|
-
align-items: center;
|
|
41
|
-
justify-content: center;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@mixin flex-between {
|
|
45
|
-
display: flex;
|
|
46
|
-
align-items: center;
|
|
47
|
-
justify-content: space-between;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
@mixin flex-column {
|
|
51
|
-
display: flex;
|
|
52
|
-
flex-direction: column;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Button mixin
|
|
56
|
-
@mixin button-base {
|
|
57
|
-
display: inline-flex;
|
|
58
|
-
align-items: center;
|
|
59
|
-
justify-content: center;
|
|
60
|
-
padding: $spacing-small $spacing-large;
|
|
61
|
-
font-family: $font-family-base;
|
|
62
|
-
font-size: $font-size-base;
|
|
63
|
-
font-weight: $font-weight-medium;
|
|
64
|
-
line-height: $line-height-normal;
|
|
65
|
-
border: none;
|
|
66
|
-
border-radius: $radius-medium;
|
|
67
|
-
cursor: pointer;
|
|
68
|
-
transition: all $transition-base;
|
|
69
|
-
text-decoration: none;
|
|
70
|
-
white-space: nowrap;
|
|
71
|
-
|
|
72
|
-
&:disabled {
|
|
73
|
-
opacity: 0.5;
|
|
74
|
-
cursor: not-allowed;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
&:focus-visible {
|
|
78
|
-
outline: 2px solid $border-focus;
|
|
79
|
-
outline-offset: 2px;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
@mixin button-primary {
|
|
84
|
-
@include button-base;
|
|
85
|
-
background-color: $primary-color;
|
|
86
|
-
color: $text-inverse;
|
|
87
|
-
|
|
88
|
-
&:hover:not(:disabled) {
|
|
89
|
-
background-color: $primary-hover;
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
@mixin button-secondary {
|
|
94
|
-
@include button-base;
|
|
95
|
-
background-color: transparent;
|
|
96
|
-
color: $primary-color;
|
|
97
|
-
border: 1px solid $border-color;
|
|
98
|
-
|
|
99
|
-
&:hover:not(:disabled) {
|
|
100
|
-
background-color: $bg-secondary;
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
// Card mixin
|
|
105
|
-
@mixin card {
|
|
106
|
-
background-color: $bg-primary;
|
|
107
|
-
border: 1px solid $border-color;
|
|
108
|
-
border-radius: $radius-large;
|
|
109
|
-
padding: $spacing-extra-large;
|
|
110
|
-
box-shadow: $shadow-small;
|
|
111
|
-
transition: box-shadow $transition-base;
|
|
112
|
-
|
|
113
|
-
&:hover {
|
|
114
|
-
box-shadow: $shadow-medium;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Input mixin
|
|
119
|
-
@mixin input-base {
|
|
120
|
-
width: 100%;
|
|
121
|
-
padding: $spacing-small $spacing-medium;
|
|
122
|
-
font-family: $font-family-base;
|
|
123
|
-
font-size: $font-size-base;
|
|
124
|
-
line-height: $line-height-normal;
|
|
125
|
-
color: $text-primary;
|
|
126
|
-
background-color: $bg-primary;
|
|
127
|
-
border: 1px solid $border-color;
|
|
128
|
-
border-radius: $radius-medium;
|
|
129
|
-
transition: border-color $transition-fast;
|
|
130
|
-
|
|
131
|
-
&:focus {
|
|
132
|
-
outline: none;
|
|
133
|
-
border-color: $border-focus;
|
|
134
|
-
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
&::placeholder {
|
|
138
|
-
color: $text-light;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
&:disabled {
|
|
142
|
-
background-color: $bg-tertiary;
|
|
143
|
-
cursor: not-allowed;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
// Container mixin
|
|
148
|
-
@mixin container {
|
|
149
|
-
width: 100%;
|
|
150
|
-
max-width: $breakpoint-extra-wide;
|
|
151
|
-
margin-left: auto;
|
|
152
|
-
margin-right: auto;
|
|
153
|
-
padding-left: $spacing-medium;
|
|
154
|
-
padding-right: $spacing-medium;
|
|
155
|
-
|
|
156
|
-
@include wide {
|
|
157
|
-
padding-left: $spacing-extra-large;
|
|
158
|
-
padding-right: $spacing-extra-large;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Typography mixins
|
|
163
|
-
@mixin heading-1 {
|
|
164
|
-
font-size: $font-size-3x-large;
|
|
165
|
-
font-weight: $font-weight-bold;
|
|
166
|
-
line-height: $line-height-tight;
|
|
167
|
-
color: $text-primary;
|
|
168
|
-
|
|
169
|
-
@include desktop {
|
|
170
|
-
font-size: $font-size-4x-large;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
@mixin heading-2 {
|
|
175
|
-
font-size: $font-size-2x-large;
|
|
176
|
-
font-weight: $font-weight-bold;
|
|
177
|
-
line-height: $line-height-tight;
|
|
178
|
-
color: $text-primary;
|
|
179
|
-
|
|
180
|
-
@include desktop {
|
|
181
|
-
font-size: $font-size-3x-large;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
@mixin heading-3 {
|
|
186
|
-
font-size: $font-size-extra-large;
|
|
187
|
-
font-weight: $font-weight-semibold;
|
|
188
|
-
line-height: $line-height-tight;
|
|
189
|
-
color: $text-primary;
|
|
190
|
-
|
|
191
|
-
@include desktop {
|
|
192
|
-
font-size: $font-size-2x-large;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// Truncate text
|
|
197
|
-
@mixin truncate {
|
|
198
|
-
overflow: hidden;
|
|
199
|
-
text-overflow: ellipsis;
|
|
200
|
-
white-space: nowrap;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Multi-line truncate
|
|
204
|
-
@mixin line-clamp($lines: 2) {
|
|
205
|
-
display: -webkit-box;
|
|
206
|
-
-webkit-line-clamp: $lines;
|
|
207
|
-
-webkit-box-orient: vertical;
|
|
208
|
-
overflow: hidden;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Visually hidden (accessible)
|
|
212
|
-
@mixin visually-hidden {
|
|
213
|
-
position: absolute;
|
|
214
|
-
width: 1px;
|
|
215
|
-
height: 1px;
|
|
216
|
-
padding: 0;
|
|
217
|
-
margin: -1px;
|
|
218
|
-
overflow: hidden;
|
|
219
|
-
clip: rect(0, 0, 0, 0);
|
|
220
|
-
white-space: nowrap;
|
|
221
|
-
border-width: 0;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
// Focus visible outline
|
|
225
|
-
@mixin focus-visible {
|
|
226
|
-
&:focus-visible {
|
|
227
|
-
outline: 2px solid $border-focus;
|
|
228
|
-
outline-offset: 2px;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Smooth scrolling
|
|
233
|
-
@mixin smooth-scroll {
|
|
234
|
-
scroll-behavior: smooth;
|
|
235
|
-
@supports(-webkit-overflow-scrolling: touch) {
|
|
236
|
-
-webkit-overflow-scrolling: touch;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
1
|
+
@use './globals' as *;
|
|
2
|
+
|
|
3
|
+
// NOTE: All mixins below use variables from globals.scss which are now powered by OpenProps design tokens
|
|
4
|
+
// This provides consistent spacing, typography, shadows, and other design primitives throughout the app
|
|
5
|
+
|
|
6
|
+
// Responsive breakpoint mixins
|
|
7
|
+
@mixin tablet {
|
|
8
|
+
@media (min-width: $breakpoint-tablet) {
|
|
9
|
+
@content;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@mixin desktop {
|
|
14
|
+
@media (min-width: $breakpoint-desktop) {
|
|
15
|
+
@content;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@mixin wide {
|
|
20
|
+
@media (min-width: $breakpoint-wide) {
|
|
21
|
+
@content;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@mixin extra-wide {
|
|
26
|
+
@media (min-width: $breakpoint-extra-wide) {
|
|
27
|
+
@content;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
@mixin ultra-wide {
|
|
32
|
+
@media (min-width: $breakpoint-ultra-wide) {
|
|
33
|
+
@content;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Flexbox utilities
|
|
38
|
+
@mixin flex-center {
|
|
39
|
+
display: flex;
|
|
40
|
+
align-items: center;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@mixin flex-between {
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
justify-content: space-between;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@mixin flex-column {
|
|
51
|
+
display: flex;
|
|
52
|
+
flex-direction: column;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Button mixin
|
|
56
|
+
@mixin button-base {
|
|
57
|
+
display: inline-flex;
|
|
58
|
+
align-items: center;
|
|
59
|
+
justify-content: center;
|
|
60
|
+
padding: $spacing-small $spacing-large;
|
|
61
|
+
font-family: $font-family-base;
|
|
62
|
+
font-size: $font-size-base;
|
|
63
|
+
font-weight: $font-weight-medium;
|
|
64
|
+
line-height: $line-height-normal;
|
|
65
|
+
border: none;
|
|
66
|
+
border-radius: $radius-medium;
|
|
67
|
+
cursor: pointer;
|
|
68
|
+
transition: all $transition-base;
|
|
69
|
+
text-decoration: none;
|
|
70
|
+
white-space: nowrap;
|
|
71
|
+
|
|
72
|
+
&:disabled {
|
|
73
|
+
opacity: 0.5;
|
|
74
|
+
cursor: not-allowed;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
&:focus-visible {
|
|
78
|
+
outline: 2px solid $border-focus;
|
|
79
|
+
outline-offset: 2px;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
@mixin button-primary {
|
|
84
|
+
@include button-base;
|
|
85
|
+
background-color: $primary-color;
|
|
86
|
+
color: $text-inverse;
|
|
87
|
+
|
|
88
|
+
&:hover:not(:disabled) {
|
|
89
|
+
background-color: $primary-hover;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@mixin button-secondary {
|
|
94
|
+
@include button-base;
|
|
95
|
+
background-color: transparent;
|
|
96
|
+
color: $primary-color;
|
|
97
|
+
border: 1px solid $border-color;
|
|
98
|
+
|
|
99
|
+
&:hover:not(:disabled) {
|
|
100
|
+
background-color: $bg-secondary;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Card mixin
|
|
105
|
+
@mixin card {
|
|
106
|
+
background-color: $bg-primary;
|
|
107
|
+
border: 1px solid $border-color;
|
|
108
|
+
border-radius: $radius-large;
|
|
109
|
+
padding: $spacing-extra-large;
|
|
110
|
+
box-shadow: $shadow-small;
|
|
111
|
+
transition: box-shadow $transition-base;
|
|
112
|
+
|
|
113
|
+
&:hover {
|
|
114
|
+
box-shadow: $shadow-medium;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Input mixin
|
|
119
|
+
@mixin input-base {
|
|
120
|
+
width: 100%;
|
|
121
|
+
padding: $spacing-small $spacing-medium;
|
|
122
|
+
font-family: $font-family-base;
|
|
123
|
+
font-size: $font-size-base;
|
|
124
|
+
line-height: $line-height-normal;
|
|
125
|
+
color: $text-primary;
|
|
126
|
+
background-color: $bg-primary;
|
|
127
|
+
border: 1px solid $border-color;
|
|
128
|
+
border-radius: $radius-medium;
|
|
129
|
+
transition: border-color $transition-fast;
|
|
130
|
+
|
|
131
|
+
&:focus {
|
|
132
|
+
outline: none;
|
|
133
|
+
border-color: $border-focus;
|
|
134
|
+
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
&::placeholder {
|
|
138
|
+
color: $text-light;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
&:disabled {
|
|
142
|
+
background-color: $bg-tertiary;
|
|
143
|
+
cursor: not-allowed;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Container mixin
|
|
148
|
+
@mixin container {
|
|
149
|
+
width: 100%;
|
|
150
|
+
max-width: $breakpoint-extra-wide;
|
|
151
|
+
margin-left: auto;
|
|
152
|
+
margin-right: auto;
|
|
153
|
+
padding-left: $spacing-medium;
|
|
154
|
+
padding-right: $spacing-medium;
|
|
155
|
+
|
|
156
|
+
@include wide {
|
|
157
|
+
padding-left: $spacing-extra-large;
|
|
158
|
+
padding-right: $spacing-extra-large;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Typography mixins
|
|
163
|
+
@mixin heading-1 {
|
|
164
|
+
font-size: $font-size-3x-large;
|
|
165
|
+
font-weight: $font-weight-bold;
|
|
166
|
+
line-height: $line-height-tight;
|
|
167
|
+
color: $text-primary;
|
|
168
|
+
|
|
169
|
+
@include desktop {
|
|
170
|
+
font-size: $font-size-4x-large;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
@mixin heading-2 {
|
|
175
|
+
font-size: $font-size-2x-large;
|
|
176
|
+
font-weight: $font-weight-bold;
|
|
177
|
+
line-height: $line-height-tight;
|
|
178
|
+
color: $text-primary;
|
|
179
|
+
|
|
180
|
+
@include desktop {
|
|
181
|
+
font-size: $font-size-3x-large;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
@mixin heading-3 {
|
|
186
|
+
font-size: $font-size-extra-large;
|
|
187
|
+
font-weight: $font-weight-semibold;
|
|
188
|
+
line-height: $line-height-tight;
|
|
189
|
+
color: $text-primary;
|
|
190
|
+
|
|
191
|
+
@include desktop {
|
|
192
|
+
font-size: $font-size-2x-large;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Truncate text
|
|
197
|
+
@mixin truncate {
|
|
198
|
+
overflow: hidden;
|
|
199
|
+
text-overflow: ellipsis;
|
|
200
|
+
white-space: nowrap;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Multi-line truncate
|
|
204
|
+
@mixin line-clamp($lines: 2) {
|
|
205
|
+
display: -webkit-box;
|
|
206
|
+
-webkit-line-clamp: $lines;
|
|
207
|
+
-webkit-box-orient: vertical;
|
|
208
|
+
overflow: hidden;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Visually hidden (accessible)
|
|
212
|
+
@mixin visually-hidden {
|
|
213
|
+
position: absolute;
|
|
214
|
+
width: 1px;
|
|
215
|
+
height: 1px;
|
|
216
|
+
padding: 0;
|
|
217
|
+
margin: -1px;
|
|
218
|
+
overflow: hidden;
|
|
219
|
+
clip: rect(0, 0, 0, 0);
|
|
220
|
+
white-space: nowrap;
|
|
221
|
+
border-width: 0;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// Focus visible outline
|
|
225
|
+
@mixin focus-visible {
|
|
226
|
+
&:focus-visible {
|
|
227
|
+
outline: 2px solid $border-focus;
|
|
228
|
+
outline-offset: 2px;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Smooth scrolling
|
|
233
|
+
@mixin smooth-scroll {
|
|
234
|
+
scroll-behavior: smooth;
|
|
235
|
+
@supports(-webkit-overflow-scrolling: touch) {
|
|
236
|
+
-webkit-overflow-scrolling: touch;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { test } from '@playwright/test'
|
|
2
|
+
import 'dotenv/config'
|
|
3
|
+
|
|
4
|
+
const base = 'http://localhost:4321';
|
|
5
|
+
const path = process.env.BROWSER_TEST_PATH || '';
|
|
6
|
+
|
|
7
|
+
test('test browser', async ({ page }) => {
|
|
8
|
+
// point this to wherever you want
|
|
9
|
+
await page.goto(`${base}${path.startsWith('/') ? path : `/${path}`}`)
|
|
10
|
+
})
|