@nautui/core 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.
- package/README.md +148 -0
- package/package.json +35 -0
- package/src/components/Accordion.astro +24 -0
- package/src/components/AccordionItem.astro +172 -0
- package/src/components/Background.astro +75 -0
- package/src/components/Badge.astro +140 -0
- package/src/components/Bento.astro +37 -0
- package/src/components/BentoItem.astro +26 -0
- package/src/components/Box.astro +189 -0
- package/src/components/Breadcrumb.astro +62 -0
- package/src/components/Button.astro +273 -0
- package/src/components/Card.astro +228 -0
- package/src/components/Container.astro +76 -0
- package/src/components/Divider.astro +85 -0
- package/src/components/Drawer.astro +139 -0
- package/src/components/Flex.astro +150 -0
- package/src/components/Flow.astro +119 -0
- package/src/components/Grid.astro +335 -0
- package/src/components/GridItem.astro +225 -0
- package/src/components/Group.astro +106 -0
- package/src/components/Image.astro +191 -0
- package/src/components/Link.astro +118 -0
- package/src/components/List.astro +57 -0
- package/src/components/ListItem.astro +31 -0
- package/src/components/Mark.astro +161 -0
- package/src/components/Marquee.astro +193 -0
- package/src/components/Masonry.astro +75 -0
- package/src/components/MasonryItem.astro +28 -0
- package/src/components/Menu.astro +71 -0
- package/src/components/MenuItem.astro +93 -0
- package/src/components/NavBar.astro +211 -0
- package/src/components/Section.astro +108 -0
- package/src/components/Space.astro +400 -0
- package/src/components/Stack.astro +237 -0
- package/src/components/Text.astro +270 -0
- package/src/components/Theme.astro +37 -0
- package/src/components/ThemeToggle.astro +141 -0
- package/src/components/Title.astro +141 -0
- package/src/index.d.ts +80 -0
- package/src/index.ts +77 -0
- package/src/lib/border.ts +92 -0
- package/src/lib/pattern.ts +37 -0
- package/src/lib/spacing.ts +48 -0
- package/src/styles/border.css +180 -0
- package/src/styles/colors.css +99 -0
- package/src/styles/global.css +57 -0
- package/src/styles/radius.css +22 -0
- package/src/styles/shadow.css +11 -0
- package/src/styles/spacing/display.css +198 -0
- package/src/styles/spacing/gap.css +19 -0
- package/src/styles/spacing/margin.css +157 -0
- package/src/styles/spacing/padding.css +154 -0
- package/src/styles/spacing/spacing.css +2 -0
- package/src/types.ts +10 -0
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
import "../styles/spacing/gap.css";
|
|
3
|
+
import type { Base, Gap, Responsive } from "../types";
|
|
4
|
+
|
|
5
|
+
type Align = "inherit" | "start" | "center" | "end" | "stretch";
|
|
6
|
+
type Justify =
|
|
7
|
+
| "start"
|
|
8
|
+
| "center"
|
|
9
|
+
| "end"
|
|
10
|
+
| "space-between"
|
|
11
|
+
| "space-around"
|
|
12
|
+
| "space-evenly";
|
|
13
|
+
|
|
14
|
+
type AlignResponsive = {
|
|
15
|
+
[key in Responsive]?: Align;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type JustifyResponsive = {
|
|
19
|
+
[key in Responsive]?: Justify;
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export interface StackProps extends Base {
|
|
23
|
+
align?: AlignResponsive | Align;
|
|
24
|
+
gap?: Gap;
|
|
25
|
+
justify?: JustifyResponsive | Justify;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const {
|
|
29
|
+
class: className,
|
|
30
|
+
align,
|
|
31
|
+
justify = "start",
|
|
32
|
+
gap = "md",
|
|
33
|
+
...rest
|
|
34
|
+
} = Astro.props as StackProps;
|
|
35
|
+
const items = typeof align === "string" ? { base: align } : align;
|
|
36
|
+
const content = typeof justify === "string" ? { base: justify } : justify;
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
<div
|
|
40
|
+
class:list={[
|
|
41
|
+
"naut-stack",
|
|
42
|
+
`gap-${gap}`,
|
|
43
|
+
items?.base && `items-${items.base}`,
|
|
44
|
+
items?.sm && `sm-items-${items.sm}`,
|
|
45
|
+
items?.md && `md-items-${items.md}`,
|
|
46
|
+
items?.lg && `lg-items-${items.lg}`,
|
|
47
|
+
items?.xl && `xl-items-${items.xl}`,
|
|
48
|
+
content?.base && `content-${content.base}`,
|
|
49
|
+
content?.sm && `sm-content-${content.sm}`,
|
|
50
|
+
content?.md && `md-content-${content.md}`,
|
|
51
|
+
content?.lg && `lg-content-${content.lg}`,
|
|
52
|
+
content?.xl && `xl-content-${content.xl}`,
|
|
53
|
+
className
|
|
54
|
+
]}
|
|
55
|
+
{...rest}
|
|
56
|
+
>
|
|
57
|
+
<slot />
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<style>
|
|
61
|
+
.naut-stack {
|
|
62
|
+
display: flex;
|
|
63
|
+
flex-direction: column;
|
|
64
|
+
|
|
65
|
+
&.content-start {
|
|
66
|
+
justify-content: flex-start;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
&.content-center {
|
|
70
|
+
justify-content: center;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
&.content-end {
|
|
74
|
+
justify-content: flex-end;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
&.content-space-between {
|
|
78
|
+
justify-content: space-between;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
&.content-space-around {
|
|
82
|
+
justify-content: space-around;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
&.content-space-evenly {
|
|
86
|
+
justify-content: space-evenly;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
&.items-start {
|
|
90
|
+
align-items: flex-start;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
&.items-center {
|
|
94
|
+
align-items: center;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
&.items-end {
|
|
98
|
+
align-items: flex-end;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
&.items-stretch {
|
|
102
|
+
align-items: stretch;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
@media only screen and (max-width: 817px) {
|
|
106
|
+
&.sm-content-start {
|
|
107
|
+
justify-content: flex-start;
|
|
108
|
+
}
|
|
109
|
+
&.sm-content-center {
|
|
110
|
+
justify-content: center;
|
|
111
|
+
}
|
|
112
|
+
&.sm-content-end {
|
|
113
|
+
justify-content: flex-end;
|
|
114
|
+
}
|
|
115
|
+
&.sm-content-space-between {
|
|
116
|
+
justify-content: space-between;
|
|
117
|
+
}
|
|
118
|
+
&.sm-content-space-around {
|
|
119
|
+
justify-content: space-around;
|
|
120
|
+
}
|
|
121
|
+
&.sm-content-space-evenly {
|
|
122
|
+
justify-content: space-evenly;
|
|
123
|
+
}
|
|
124
|
+
&.sm-items-start {
|
|
125
|
+
align-items: flex-start;
|
|
126
|
+
}
|
|
127
|
+
&.sm-items-center {
|
|
128
|
+
align-items: center;
|
|
129
|
+
}
|
|
130
|
+
&.sm-items-end {
|
|
131
|
+
align-items: flex-end;
|
|
132
|
+
}
|
|
133
|
+
&.sm-items-stretch {
|
|
134
|
+
align-items: stretch;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
@media only screen and (min-width: 818px) and (max-width: 1041px) {
|
|
139
|
+
&.md-content-start {
|
|
140
|
+
justify-content: flex-start;
|
|
141
|
+
}
|
|
142
|
+
&.md-content-center {
|
|
143
|
+
justify-content: center;
|
|
144
|
+
}
|
|
145
|
+
&.md-content-end {
|
|
146
|
+
justify-content: flex-end;
|
|
147
|
+
}
|
|
148
|
+
&.md-content-space-between {
|
|
149
|
+
justify-content: space-between;
|
|
150
|
+
}
|
|
151
|
+
&.md-content-space-around {
|
|
152
|
+
justify-content: space-around;
|
|
153
|
+
}
|
|
154
|
+
&.md-content-space-evenly {
|
|
155
|
+
justify-content: space-evenly;
|
|
156
|
+
}
|
|
157
|
+
&.md-items-start {
|
|
158
|
+
align-items: flex-start;
|
|
159
|
+
}
|
|
160
|
+
&.md-items-center {
|
|
161
|
+
align-items: center;
|
|
162
|
+
}
|
|
163
|
+
&.md-items-end {
|
|
164
|
+
align-items: flex-end;
|
|
165
|
+
}
|
|
166
|
+
&.md-items-stretch {
|
|
167
|
+
align-items: stretch;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@media only screen and (min-width: 1042px) {
|
|
172
|
+
&.lg-content-start {
|
|
173
|
+
justify-content: flex-start;
|
|
174
|
+
}
|
|
175
|
+
&.lg-content-center {
|
|
176
|
+
justify-content: center;
|
|
177
|
+
}
|
|
178
|
+
&.lg-content-end {
|
|
179
|
+
justify-content: flex-end;
|
|
180
|
+
}
|
|
181
|
+
&.lg-content-space-between {
|
|
182
|
+
justify-content: space-between;
|
|
183
|
+
}
|
|
184
|
+
&.lg-content-space-around {
|
|
185
|
+
justify-content: space-around;
|
|
186
|
+
}
|
|
187
|
+
&.lg-content-space-evenly {
|
|
188
|
+
justify-content: space-evenly;
|
|
189
|
+
}
|
|
190
|
+
&.lg-items-start {
|
|
191
|
+
align-items: flex-start;
|
|
192
|
+
}
|
|
193
|
+
&.lg-items-center {
|
|
194
|
+
align-items: center;
|
|
195
|
+
}
|
|
196
|
+
&.lg-items-end {
|
|
197
|
+
align-items: flex-end;
|
|
198
|
+
}
|
|
199
|
+
&.lg-items-stretch {
|
|
200
|
+
align-items: stretch;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
@media only screen and (min-width: 1250px) {
|
|
205
|
+
&.xl-content-start {
|
|
206
|
+
justify-content: flex-start;
|
|
207
|
+
}
|
|
208
|
+
&.xl-content-center {
|
|
209
|
+
justify-content: center;
|
|
210
|
+
}
|
|
211
|
+
&.xl-content-end {
|
|
212
|
+
justify-content: flex-end;
|
|
213
|
+
}
|
|
214
|
+
&.xl-content-space-between {
|
|
215
|
+
justify-content: space-between;
|
|
216
|
+
}
|
|
217
|
+
&.xl-content-space-around {
|
|
218
|
+
justify-content: space-around;
|
|
219
|
+
}
|
|
220
|
+
&.xl-content-space-evenly {
|
|
221
|
+
justify-content: space-evenly;
|
|
222
|
+
}
|
|
223
|
+
&.xl-items-start {
|
|
224
|
+
align-items: flex-start;
|
|
225
|
+
}
|
|
226
|
+
&.xl-items-center {
|
|
227
|
+
align-items: center;
|
|
228
|
+
}
|
|
229
|
+
&.xl-items-end {
|
|
230
|
+
align-items: flex-end;
|
|
231
|
+
}
|
|
232
|
+
&.xl-items-stretch {
|
|
233
|
+
align-items: stretch;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
</style>
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
---
|
|
2
|
+
import "../styles/spacing/margin.css";
|
|
3
|
+
import {
|
|
4
|
+
extractSpacingProps,
|
|
5
|
+
getSpacingClasses,
|
|
6
|
+
MarginProps,
|
|
7
|
+
} from "../lib/spacing";
|
|
8
|
+
import type { Base, Size } from "../types";
|
|
9
|
+
|
|
10
|
+
export interface TextProps extends Base, MarginProps {
|
|
11
|
+
align?: "left" | "center" | "right" | "justify";
|
|
12
|
+
decoration?: "underline" | "strikethrough";
|
|
13
|
+
dimmed?: boolean;
|
|
14
|
+
inline?: boolean;
|
|
15
|
+
italic?: boolean;
|
|
16
|
+
maxWidth?: number | string;
|
|
17
|
+
size?: Size;
|
|
18
|
+
transform?: "capitalize" | "uppercase" | "lowercase";
|
|
19
|
+
weight?: "light" | "normal" | "medium" | "bold" | "semi-bold" | "extra-bold";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { margin, nonSpacing } = extractSpacingProps(Astro.props as TextProps);
|
|
23
|
+
|
|
24
|
+
const {
|
|
25
|
+
class: className,
|
|
26
|
+
weight,
|
|
27
|
+
transform,
|
|
28
|
+
decoration,
|
|
29
|
+
size,
|
|
30
|
+
maxWidth,
|
|
31
|
+
italic = false,
|
|
32
|
+
inline = false,
|
|
33
|
+
dimmed = false,
|
|
34
|
+
align,
|
|
35
|
+
...rest
|
|
36
|
+
} = nonSpacing;
|
|
37
|
+
|
|
38
|
+
const marginClasses = getSpacingClasses(margin);
|
|
39
|
+
|
|
40
|
+
const maxWidthStyle =
|
|
41
|
+
maxWidth === undefined
|
|
42
|
+
? undefined
|
|
43
|
+
: `max-width: ${typeof maxWidth === "number" ? `${maxWidth}px` : maxWidth}`;
|
|
44
|
+
|
|
45
|
+
const classList = [
|
|
46
|
+
"text",
|
|
47
|
+
italic && "italic",
|
|
48
|
+
dimmed && "dimmed",
|
|
49
|
+
align && `align-${align}`,
|
|
50
|
+
size && `size-${size}`,
|
|
51
|
+
weight && `weight-${weight}`,
|
|
52
|
+
transform && `transform-${transform}`,
|
|
53
|
+
decoration && `decoration-${decoration}`,
|
|
54
|
+
...marginClasses,
|
|
55
|
+
className,
|
|
56
|
+
];
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
{inline && <span class:list={classList} style={maxWidthStyle} {...rest}><slot /></span>}
|
|
60
|
+
{!inline && <p class:list={classList} style={maxWidthStyle} {...rest}><slot /></p>}
|
|
61
|
+
|
|
62
|
+
<style>
|
|
63
|
+
.text {
|
|
64
|
+
font-family: inherit;
|
|
65
|
+
font-size: inherit;
|
|
66
|
+
line-height: inherit;
|
|
67
|
+
|
|
68
|
+
&::selection {
|
|
69
|
+
color: var(--naut-color-content);
|
|
70
|
+
-webkit-text-fill-color: var(--naut-color-content);
|
|
71
|
+
background-color: var(--naut-color-selection);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
&.inline {
|
|
75
|
+
display: inline-block;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
&.italic {
|
|
79
|
+
font-style: italic;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
&.align-left {
|
|
83
|
+
text-align: left;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
&.align-center {
|
|
87
|
+
text-align: center;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
&.align-right {
|
|
91
|
+
text-align: right;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
&.align-justify {
|
|
95
|
+
text-align: justify;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
&.dimmed {
|
|
99
|
+
color: var(--naut-color-content-soft);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
&.size-xs {
|
|
103
|
+
font-size: var(--naut-font-size-xs);
|
|
104
|
+
line-height: calc(
|
|
105
|
+
var(--naut-font-size-xs) *
|
|
106
|
+
var(--naut-line-height-ratio)
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
&.size-sm {
|
|
111
|
+
font-size: var(--naut-font-size-sm);
|
|
112
|
+
line-height: calc(
|
|
113
|
+
var(--naut-font-size-sm) *
|
|
114
|
+
var(--naut-line-height-ratio)
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&.size-md {
|
|
119
|
+
font-size: var(--naut-font-size-md);
|
|
120
|
+
line-height: calc(
|
|
121
|
+
var(--naut-font-size-md) *
|
|
122
|
+
var(--naut-line-height-ratio)
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
&.size-lg {
|
|
127
|
+
font-size: clamp(1.15rem, 1.5vw + 1rem, var(--naut-font-size-lg));
|
|
128
|
+
line-height: clamp(1.8rem, 2.5vw + 1rem, 2.05rem);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
&.size-xl {
|
|
132
|
+
font-size: clamp(1.3rem, 1.3vw + 1rem, var(--naut-font-size-xl));
|
|
133
|
+
line-height: clamp(2rem, 2.5vw + 1rem, 2.34rem);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
&.size-xxl {
|
|
137
|
+
font-size: clamp(1.5rem, 1.5vw + 1rem, var(--naut-font-size-xxl));
|
|
138
|
+
line-height: clamp(2.2rem, 2vw + 1rem, 3.25rem);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
&.weight-light {
|
|
142
|
+
font-weight: 300;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
&.weight-medium {
|
|
146
|
+
font-weight: 500;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
&.weight-bold {
|
|
150
|
+
font-weight: 700;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
&.weight-semi-bold {
|
|
154
|
+
font-weight: 600;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
&.weight-extra-bold {
|
|
158
|
+
font-weight: 800;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
&.transform-capitalize {
|
|
162
|
+
text-transform: capitalize;
|
|
163
|
+
}
|
|
164
|
+
&.transform-uppercase {
|
|
165
|
+
text-transform: uppercase;
|
|
166
|
+
}
|
|
167
|
+
&.transform-lowercase {
|
|
168
|
+
text-transform: lowercase;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
&.decoration-underline {
|
|
172
|
+
text-decoration: underline;
|
|
173
|
+
}
|
|
174
|
+
&.decoration-strikethrough {
|
|
175
|
+
text-decoration: line-through;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/* Margins */
|
|
179
|
+
&.mt-0 {
|
|
180
|
+
margin-top: 0;
|
|
181
|
+
}
|
|
182
|
+
&.mb-0 {
|
|
183
|
+
margin-bottom: 0;
|
|
184
|
+
}
|
|
185
|
+
&.ml-0 {
|
|
186
|
+
margin-left: 0;
|
|
187
|
+
}
|
|
188
|
+
&.mr-0 {
|
|
189
|
+
margin-right: 0;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
&.mt-xs {
|
|
193
|
+
margin-top: var(--naut-spacing-xs);
|
|
194
|
+
}
|
|
195
|
+
&.mb-xs {
|
|
196
|
+
margin-bottom: var(--naut-spacing-xs);
|
|
197
|
+
}
|
|
198
|
+
&.ml-xs {
|
|
199
|
+
margin-left: var(--naut-spacing-xs);
|
|
200
|
+
}
|
|
201
|
+
&.mr-xs {
|
|
202
|
+
margin-right: var(--naut-spacing-xs);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
&.mt-sm {
|
|
206
|
+
margin-top: var(--naut-spacing-sm);
|
|
207
|
+
}
|
|
208
|
+
&.mb-sm {
|
|
209
|
+
margin-bottom: var(--naut-spacing-sm);
|
|
210
|
+
}
|
|
211
|
+
&.ml-sm {
|
|
212
|
+
margin-left: var(--naut-spacing-sm);
|
|
213
|
+
}
|
|
214
|
+
&.mr-sm {
|
|
215
|
+
margin-right: var(--naut-spacing-sm);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
&.mt-md {
|
|
219
|
+
margin-top: var(--naut-spacing-md);
|
|
220
|
+
}
|
|
221
|
+
&.mb-md {
|
|
222
|
+
margin-bottom: var(--naut-spacing-md);
|
|
223
|
+
}
|
|
224
|
+
&.ml-md {
|
|
225
|
+
margin-left: var(--naut-spacing-md);
|
|
226
|
+
}
|
|
227
|
+
&.mr-md {
|
|
228
|
+
margin-right: var(--naut-spacing-md);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
&.mt-lg {
|
|
232
|
+
margin-top: var(--naut-spacing-lg);
|
|
233
|
+
}
|
|
234
|
+
&.mb-lg {
|
|
235
|
+
margin-bottom: var(--naut-spacing-lg);
|
|
236
|
+
}
|
|
237
|
+
&.ml-lg {
|
|
238
|
+
margin-left: var(--naut-spacing-lg);
|
|
239
|
+
}
|
|
240
|
+
&.mr-lg {
|
|
241
|
+
margin-right: var(--naut-spacing-lg);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
&.mt-xl {
|
|
245
|
+
margin-top: var(--naut-spacing-xl);
|
|
246
|
+
}
|
|
247
|
+
&.mb-xl {
|
|
248
|
+
margin-bottom: var(--naut-spacing-xl);
|
|
249
|
+
}
|
|
250
|
+
&.ml-xl {
|
|
251
|
+
margin-left: var(--naut-spacing-xl);
|
|
252
|
+
}
|
|
253
|
+
&.mr-xl {
|
|
254
|
+
margin-right: var(--naut-spacing-xl);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
p.text {
|
|
259
|
+
&:first-child {
|
|
260
|
+
margin-top: 0;
|
|
261
|
+
}
|
|
262
|
+
&:last-child {
|
|
263
|
+
margin-bottom: 0;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
span.text {
|
|
268
|
+
display: inline-block;
|
|
269
|
+
}
|
|
270
|
+
</style>
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
import "../styles/global.css";
|
|
3
|
+
import "../styles/colors.css";
|
|
4
|
+
import type { Base } from "../types";
|
|
5
|
+
|
|
6
|
+
export interface ThemeProps extends Base {
|
|
7
|
+
dark?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { class: className, dark = true } = Astro.props as ThemeProps;
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
<Fragment class:list={["naut-theme", className]}> <slot /> </Fragment>
|
|
14
|
+
|
|
15
|
+
<script is:inline define:vars={{ dark }}>
|
|
16
|
+
(() => {
|
|
17
|
+
if (dark) {
|
|
18
|
+
if (window.__nautThemeInitialized) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
window.__nautThemeInitialized = true;
|
|
22
|
+
|
|
23
|
+
const getTheme = () => {
|
|
24
|
+
const stored = localStorage.getItem("naut-theme");
|
|
25
|
+
if (["dark", "light"].includes(stored)) {
|
|
26
|
+
return stored;
|
|
27
|
+
}
|
|
28
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
29
|
+
? "dark"
|
|
30
|
+
: "light";
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const theme = getTheme();
|
|
34
|
+
document.documentElement.setAttribute("data-theme", theme);
|
|
35
|
+
}
|
|
36
|
+
})();
|
|
37
|
+
</script>
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { Base } from "../types";
|
|
3
|
+
import Button from "./Button.astro";
|
|
4
|
+
|
|
5
|
+
export interface ThemeToggleProps extends Base {}
|
|
6
|
+
|
|
7
|
+
const { class: className } = Astro.props as ThemeToggleProps;
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<Button
|
|
11
|
+
variant="ghost"
|
|
12
|
+
aria-label="Toggle theme"
|
|
13
|
+
onclick="toggleTheme()"
|
|
14
|
+
class:list={["naut-theme-toggle", className]}
|
|
15
|
+
title="Toggle theme"
|
|
16
|
+
>
|
|
17
|
+
<svg
|
|
18
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
19
|
+
width="24"
|
|
20
|
+
height="24"
|
|
21
|
+
viewBox="0 0 24 24"
|
|
22
|
+
fill="none"
|
|
23
|
+
stroke="currentColor"
|
|
24
|
+
stroke-width="2"
|
|
25
|
+
stroke-linecap="round"
|
|
26
|
+
stroke-linejoin="round"
|
|
27
|
+
>
|
|
28
|
+
<title>Sun and Moon</title>
|
|
29
|
+
<g class="naut-theme-toggle--sun">
|
|
30
|
+
<circle cx="12" cy="12" r="4" />
|
|
31
|
+
<path d="M12 2v2" />
|
|
32
|
+
<path d="M12 20v2" />
|
|
33
|
+
<path d="m4.93 4.93 1.41 1.41" />
|
|
34
|
+
<path d="m17.66 17.66 1.41 1.41" />
|
|
35
|
+
<path d="M2 12h2" />
|
|
36
|
+
<path d="M20 12h2" />
|
|
37
|
+
<path d="m6.34 17.66-1.41 1.41" />
|
|
38
|
+
<path d="m19.07 4.93-1.41 1.41" />
|
|
39
|
+
</g>
|
|
40
|
+
<g class="naut-theme-toggle--moon">
|
|
41
|
+
<path
|
|
42
|
+
d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"
|
|
43
|
+
/>
|
|
44
|
+
</g>
|
|
45
|
+
</svg>
|
|
46
|
+
</Button>
|
|
47
|
+
|
|
48
|
+
<style>
|
|
49
|
+
.naut-theme-toggle--sun {
|
|
50
|
+
display: block;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.naut-theme-toggle--moon {
|
|
54
|
+
display: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
:global([data-theme="dark"]) .naut-theme-toggle--sun {
|
|
58
|
+
display: none;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
:global([data-theme="dark"]) .naut-theme-toggle--moon {
|
|
62
|
+
display: block;
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
65
|
+
|
|
66
|
+
<script>
|
|
67
|
+
declare global {
|
|
68
|
+
interface Window {
|
|
69
|
+
setTheme: (theme: string) => void;
|
|
70
|
+
toggleTheme: () => void;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Function to apply theme with naut-theme attribute
|
|
75
|
+
const applyTheme = (theme: string, isUserChoice = true) => {
|
|
76
|
+
document.documentElement.setAttribute("data-theme", theme);
|
|
77
|
+
localStorage.setItem("naut-theme", theme);
|
|
78
|
+
localStorage.setItem("themeSourceType", isUserChoice ? "user" : "system");
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// Function to handle theme change
|
|
82
|
+
const setTheme = (theme: string) => {
|
|
83
|
+
applyTheme(theme);
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Initialize theme on load
|
|
87
|
+
const initializeTheme = () => {
|
|
88
|
+
// Ensure themeSourceType is set if missing
|
|
89
|
+
if (!localStorage.getItem("themeSourceType")) {
|
|
90
|
+
localStorage.setItem("themeSourceType", "system");
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Main toggle function
|
|
95
|
+
const toggleTheme = () => {
|
|
96
|
+
const currentTheme =
|
|
97
|
+
document.documentElement.getAttribute("data-theme") ||
|
|
98
|
+
localStorage.getItem("naut-theme") ||
|
|
99
|
+
(window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
100
|
+
? "dark"
|
|
101
|
+
: "light");
|
|
102
|
+
|
|
103
|
+
const newTheme = currentTheme === "dark" ? "light" : "dark";
|
|
104
|
+
|
|
105
|
+
// Check if the new theme matches system preference
|
|
106
|
+
const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
|
|
107
|
+
.matches
|
|
108
|
+
? "dark"
|
|
109
|
+
: "light";
|
|
110
|
+
|
|
111
|
+
// Only mark as "user" choice if it differs from system preference
|
|
112
|
+
const isOverridingSystem = newTheme !== systemTheme;
|
|
113
|
+
applyTheme(newTheme, isOverridingSystem);
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Listen for system preference changes
|
|
117
|
+
const handleSystemThemeChange = (e: MediaQueryListEvent) => {
|
|
118
|
+
const themeSourceType = localStorage.getItem("themeSourceType");
|
|
119
|
+
const systemTheme = e.matches ? "dark" : "light";
|
|
120
|
+
const currentTheme = localStorage.getItem("naut-theme");
|
|
121
|
+
|
|
122
|
+
if (themeSourceType === "system") {
|
|
123
|
+
// Auto-switch because user hasn't overridden
|
|
124
|
+
applyTheme(systemTheme, false);
|
|
125
|
+
} else if (themeSourceType === "user" && currentTheme === systemTheme) {
|
|
126
|
+
// User's override now matches system preference, so re-enable auto-switching
|
|
127
|
+
localStorage.setItem("themeSourceType", "system");
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Set up system preference listener
|
|
132
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
|
|
133
|
+
mediaQuery.addEventListener("change", handleSystemThemeChange);
|
|
134
|
+
|
|
135
|
+
// Initialize on load
|
|
136
|
+
initializeTheme();
|
|
137
|
+
|
|
138
|
+
// Expose functions to window
|
|
139
|
+
window.toggleTheme = toggleTheme;
|
|
140
|
+
window.setTheme = setTheme;
|
|
141
|
+
</script>
|