@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.
Files changed (54) hide show
  1. package/README.md +148 -0
  2. package/package.json +35 -0
  3. package/src/components/Accordion.astro +24 -0
  4. package/src/components/AccordionItem.astro +172 -0
  5. package/src/components/Background.astro +75 -0
  6. package/src/components/Badge.astro +140 -0
  7. package/src/components/Bento.astro +37 -0
  8. package/src/components/BentoItem.astro +26 -0
  9. package/src/components/Box.astro +189 -0
  10. package/src/components/Breadcrumb.astro +62 -0
  11. package/src/components/Button.astro +273 -0
  12. package/src/components/Card.astro +228 -0
  13. package/src/components/Container.astro +76 -0
  14. package/src/components/Divider.astro +85 -0
  15. package/src/components/Drawer.astro +139 -0
  16. package/src/components/Flex.astro +150 -0
  17. package/src/components/Flow.astro +119 -0
  18. package/src/components/Grid.astro +335 -0
  19. package/src/components/GridItem.astro +225 -0
  20. package/src/components/Group.astro +106 -0
  21. package/src/components/Image.astro +191 -0
  22. package/src/components/Link.astro +118 -0
  23. package/src/components/List.astro +57 -0
  24. package/src/components/ListItem.astro +31 -0
  25. package/src/components/Mark.astro +161 -0
  26. package/src/components/Marquee.astro +193 -0
  27. package/src/components/Masonry.astro +75 -0
  28. package/src/components/MasonryItem.astro +28 -0
  29. package/src/components/Menu.astro +71 -0
  30. package/src/components/MenuItem.astro +93 -0
  31. package/src/components/NavBar.astro +211 -0
  32. package/src/components/Section.astro +108 -0
  33. package/src/components/Space.astro +400 -0
  34. package/src/components/Stack.astro +237 -0
  35. package/src/components/Text.astro +270 -0
  36. package/src/components/Theme.astro +37 -0
  37. package/src/components/ThemeToggle.astro +141 -0
  38. package/src/components/Title.astro +141 -0
  39. package/src/index.d.ts +80 -0
  40. package/src/index.ts +77 -0
  41. package/src/lib/border.ts +92 -0
  42. package/src/lib/pattern.ts +37 -0
  43. package/src/lib/spacing.ts +48 -0
  44. package/src/styles/border.css +180 -0
  45. package/src/styles/colors.css +99 -0
  46. package/src/styles/global.css +57 -0
  47. package/src/styles/radius.css +22 -0
  48. package/src/styles/shadow.css +11 -0
  49. package/src/styles/spacing/display.css +198 -0
  50. package/src/styles/spacing/gap.css +19 -0
  51. package/src/styles/spacing/margin.css +157 -0
  52. package/src/styles/spacing/padding.css +154 -0
  53. package/src/styles/spacing/spacing.css +2 -0
  54. package/src/types.ts +10 -0
@@ -0,0 +1,193 @@
1
+ ---
2
+ import "../styles/spacing/spacing.css";
3
+ import "../styles/spacing/gap.css";
4
+ import {
5
+ extractSpacingProps,
6
+ getSpacingClasses,
7
+ SpacingProps,
8
+ } from "../lib/spacing";
9
+ import type { Base, Gap } from "../types";
10
+
11
+ export interface MarqueeProps extends Base, SpacingProps {
12
+ duration?: number;
13
+ fadeEdgeColor?: string;
14
+ fadeEdgeSize?: string;
15
+ fadeEdges?: boolean;
16
+ gap?: Gap;
17
+ orientation?: "horizontal" | "vertical";
18
+ pauseOnHover?: boolean;
19
+ repeat?: number;
20
+ reverse?: boolean;
21
+ }
22
+
23
+ const { spacing, nonSpacing } = extractSpacingProps(
24
+ Astro.props as MarqueeProps
25
+ );
26
+ const spacingClasses = getSpacingClasses(spacing);
27
+
28
+ const {
29
+ class: className,
30
+ duration = 40_000,
31
+ reverse = false,
32
+ repeat = 4,
33
+ gap = "md",
34
+ pauseOnHover = false,
35
+ orientation = "horizontal",
36
+ fadeEdges = true,
37
+ fadeEdgeColor = "var(--naut-color-base)",
38
+ fadeEdgeSize = "5%",
39
+ ...rest
40
+ } = nonSpacing;
41
+
42
+ const safeDuration = Math.max(1, duration);
43
+ const safeRepeat = Math.max(2, Math.floor(repeat));
44
+ ---
45
+
46
+ <div
47
+ class:list={[
48
+ "naut-marquee",
49
+ `orientation-${orientation}`,
50
+ reverse && "reverse",
51
+ pauseOnHover && "pause-on-hover",
52
+ !fadeEdges && "no-fade",
53
+ className,
54
+ ...spacingClasses
55
+ ]}
56
+ {...rest}
57
+ >
58
+ <div class="naut-marquee-track">
59
+ {Array.from({ length: safeRepeat }).map(() => (
60
+ <div class:list={["naut-marquee-group", `gap-${gap}`]}><slot /></div>
61
+ ))}
62
+ </div>
63
+ </div>
64
+
65
+ <style
66
+ define:vars={{
67
+ safeDuration,
68
+ safeRepeat,
69
+ fadeEdgeColor,
70
+ fadeEdgeSize
71
+ }}
72
+ >
73
+ .naut-marquee {
74
+ position: relative;
75
+ display: block;
76
+ overflow: hidden;
77
+ }
78
+
79
+ .naut-marquee-track {
80
+ display: flex;
81
+ width: max-content;
82
+ animation: scroll-x calc(var(--safeDuration) * 1ms) linear infinite;
83
+ will-change: transform;
84
+ }
85
+
86
+ .naut-marquee-group {
87
+ display: flex;
88
+ flex-shrink: 0;
89
+ align-items: center;
90
+ min-width: max-content;
91
+
92
+ /* space between connected marquee groups */
93
+ &.gap-sm {
94
+ margin-left: var(--naut-spacing-sm);
95
+ }
96
+
97
+ &.gap-md {
98
+ margin-left: var(--naut-spacing-md);
99
+ }
100
+
101
+ &.gap-lg {
102
+ margin-left: var(--naut-spacing-lg);
103
+ }
104
+
105
+ &.gap-xl {
106
+ margin-left: var(--naut-spacing-xl);
107
+ }
108
+ }
109
+
110
+ .naut-marquee.orientation-vertical .naut-marquee-track {
111
+ flex-direction: column;
112
+ height: max-content;
113
+ animation-name: scroll-y;
114
+ }
115
+
116
+ .naut-marquee.orientation-vertical .naut-marquee-group {
117
+ flex-direction: column;
118
+ min-height: max-content;
119
+ }
120
+
121
+ .naut-marquee.reverse .naut-marquee-track {
122
+ animation-direction: reverse;
123
+ }
124
+
125
+ .naut-marquee.pause-on-hover:hover .naut-marquee-track {
126
+ animation-play-state: paused;
127
+ }
128
+
129
+ .naut-marquee:not(.no-fade)::before,
130
+ .naut-marquee:not(.no-fade)::after {
131
+ position: absolute;
132
+ z-index: 1;
133
+ pointer-events: none;
134
+ content: "";
135
+ }
136
+
137
+ .naut-marquee.orientation-horizontal:not(.no-fade)::before {
138
+ top: 0;
139
+ left: 0;
140
+ width: var(--fadeEdgeSize);
141
+ height: 100%;
142
+ background: linear-gradient(to right, var(--fadeEdgeColor), transparent);
143
+ }
144
+
145
+ .naut-marquee.orientation-horizontal:not(.no-fade)::after {
146
+ top: 0;
147
+ right: 0;
148
+ width: var(--fadeEdgeSize);
149
+ height: 100%;
150
+ background: linear-gradient(to left, var(--fadeEdgeColor), transparent);
151
+ }
152
+
153
+ .naut-marquee.orientation-vertical:not(.no-fade)::before {
154
+ top: 0;
155
+ left: 0;
156
+ width: 100%;
157
+ height: var(--fadeEdgeSize);
158
+ background: linear-gradient(to bottom, var(--fadeEdgeColor), transparent);
159
+ }
160
+
161
+ .naut-marquee.orientation-vertical:not(.no-fade)::after {
162
+ bottom: 0;
163
+ left: 0;
164
+ width: 100%;
165
+ height: var(--fadeEdgeSize);
166
+ background: linear-gradient(to top, var(--fadeEdgeColor), transparent);
167
+ }
168
+
169
+ @keyframes scroll-x {
170
+ from {
171
+ transform: translate3d(0, 0, 0);
172
+ }
173
+ to {
174
+ transform: translate3d(calc(-100% / var(--safeRepeat)), 0, 0);
175
+ }
176
+ }
177
+
178
+ @keyframes scroll-y {
179
+ from {
180
+ transform: translate3d(0, 0, 0);
181
+ }
182
+ to {
183
+ transform: translate3d(0, calc(-100% / var(--safeRepeat)), 0);
184
+ }
185
+ }
186
+
187
+ @media (prefers-reduced-motion: reduce) {
188
+ .naut-marquee-track {
189
+ animation-duration: 1ms;
190
+ animation-iteration-count: 1;
191
+ }
192
+ }
193
+ </style>
@@ -0,0 +1,75 @@
1
+ ---
2
+ import "../styles/spacing/spacing.css";
3
+ import {
4
+ extractSpacingProps,
5
+ getSpacingClasses,
6
+ SpacingProps,
7
+ } from "../lib/spacing";
8
+ import type { Base, Gap } from "../types";
9
+
10
+ export interface MasonryProps extends Base, SpacingProps {
11
+ columns?: number;
12
+ gap?: Gap;
13
+ }
14
+
15
+ const { spacing, nonSpacing } = extractSpacingProps(
16
+ Astro.props as MasonryProps
17
+ );
18
+ const spacingClasses = getSpacingClasses(spacing);
19
+ const { class: className, columns = 4, gap = "md" } = nonSpacing;
20
+ ---
21
+
22
+ <div class:list={["naut-masonry", `gap-${gap}`, className, ...spacingClasses]}>
23
+ <slot />
24
+ </div>
25
+
26
+ <style define:vars={{ columns }}>
27
+ .naut-masonry {
28
+ column-count: 1; /* Stacked on mobile */
29
+ column-gap: 0;
30
+
31
+ @media only screen and (min-width: 576px) {
32
+ column-count: 2; /* 2 columns on tablet */
33
+ }
34
+
35
+ @media only screen and (min-width: 1042px) {
36
+ column-count: var(--columns); /* Desktop columns */
37
+ }
38
+
39
+ &.gap-sm {
40
+ column-gap: var(--naut-spacing-sm);
41
+ }
42
+
43
+ &.gap-md {
44
+ column-gap: var(--naut-spacing-md);
45
+ }
46
+
47
+ &.gap-lg {
48
+ column-gap: var(--naut-spacing-lg);
49
+ }
50
+
51
+ &.gap-xl {
52
+ column-gap: var(--naut-spacing-xl);
53
+ }
54
+ }
55
+
56
+ :global(.naut-masonry.gap-none > .naut-masonry-item) {
57
+ margin-bottom: 0;
58
+ }
59
+
60
+ :global(.naut-masonry.gap-sm > .naut-masonry-item) {
61
+ margin-bottom: var(--naut-spacing-sm);
62
+ }
63
+
64
+ :global(.naut-masonry.gap-md > .naut-masonry-item) {
65
+ margin-bottom: var(--naut-spacing-md);
66
+ }
67
+
68
+ :global(.naut-masonry.gap-lg > .naut-masonry-item) {
69
+ margin-bottom: var(--naut-spacing-lg);
70
+ }
71
+
72
+ :global(.naut-masonry.gap-xl > .naut-masonry-item) {
73
+ margin-bottom: var(--naut-spacing-xl);
74
+ }
75
+ </style>
@@ -0,0 +1,28 @@
1
+ ---
2
+ import "../styles/spacing/spacing.css";
3
+ import {
4
+ extractSpacingProps,
5
+ getSpacingClasses,
6
+ SpacingProps,
7
+ } from "../lib/spacing";
8
+ import type { Base } from "../types";
9
+
10
+ export interface MasonryItemProps extends Base, SpacingProps {}
11
+
12
+ const { spacing, nonSpacing } = extractSpacingProps(
13
+ Astro.props as MasonryItemProps
14
+ );
15
+ const spacingClasses = getSpacingClasses(spacing);
16
+
17
+ const { class: className, ...rest } = nonSpacing;
18
+ ---
19
+
20
+ <div class:list={["naut-masonry-item", ...spacingClasses, className]} {...rest}>
21
+ <slot />
22
+ </div>
23
+
24
+ <style>
25
+ .naut-masonry-item {
26
+ break-inside: avoid;
27
+ }
28
+ </style>
@@ -0,0 +1,71 @@
1
+ ---
2
+ import type { Base, Gap } from "../types";
3
+
4
+ export interface MenuProps extends Base {
5
+ divided?: boolean;
6
+ gap?: Gap;
7
+ horizontal?: boolean;
8
+ }
9
+
10
+ const {
11
+ class: className,
12
+ horizontal = false,
13
+ divided = false,
14
+ gap,
15
+ ...rest
16
+ } = Astro.props as MenuProps;
17
+ const gapVar = gap ? `var(--naut-spacing-${gap})` : "1px";
18
+ ---
19
+
20
+ <nav
21
+ class:list={[
22
+ "naut-menu",
23
+ horizontal && "horizontal",
24
+ divided && "divided",
25
+ className
26
+ ]}
27
+ {...rest}
28
+ >
29
+ <ul class:list={["naut-menu__list", gap && `gap-${gap}`]}>
30
+ <slot />
31
+ </ul>
32
+ </nav>
33
+
34
+ <style define:vars={{ gapVar }}>
35
+ .naut-menu {
36
+ ul.naut-menu__list {
37
+ display: flex;
38
+ flex-direction: column;
39
+ gap: var(--gapVar);
40
+ padding: 0;
41
+ margin: 0;
42
+ list-style: none;
43
+ }
44
+
45
+ &.horizontal ul.naut-menu__list {
46
+ display: inline-flex;
47
+ flex-direction: row;
48
+ }
49
+ }
50
+
51
+ :global(.naut-menu.horizontal ul.naut-menu__list .naut-menu-item) {
52
+ padding-right: 1rem;
53
+ padding-left: 1rem;
54
+ }
55
+
56
+ :global(
57
+ .naut-menu.divided:not(.horizontal)
58
+ .naut-menu__list-item:not(:last-child)
59
+ ) {
60
+ padding-bottom: var(--gapVar);
61
+ border-bottom: 1px solid var(--naut-color-border);
62
+ }
63
+
64
+ :global(
65
+ .naut-menu.divided.horizontal
66
+ .naut-menu__list-item:not(:last-child)
67
+ ) {
68
+ padding-right: var(--gapVar);
69
+ border-right: 1px solid var(--naut-color-border);
70
+ }
71
+ </style>
@@ -0,0 +1,93 @@
1
+ ---
2
+ import type { Base } from "../types";
3
+
4
+ export interface MenuItemProps extends Base {
5
+ active?: boolean;
6
+ color?: "text" | "link" | "dimmed";
7
+ href: string;
8
+ }
9
+
10
+ const {
11
+ class: className,
12
+ active = false,
13
+ color = "text",
14
+ href,
15
+ ...rest
16
+ } = Astro.props as MenuItemProps;
17
+
18
+ const classList = [
19
+ "naut-menu-item",
20
+ active && "active",
21
+ color !== "text" && `color-${color}`,
22
+ className,
23
+ ];
24
+ ---
25
+
26
+ <li class="naut-menu__list-item">
27
+ <a href={href} class:list={classList} {...rest}>
28
+ <span class="naut-menu-item--left"><slot name="before" /></span>
29
+ <span class="naut-menu-item--main"><slot /></span>
30
+ <span class="naut-menu-item--right"><slot name="after" /></span>
31
+ </a>
32
+ </li>
33
+
34
+ <style>
35
+ .naut-menu-item {
36
+ display: flex;
37
+ align-items: center;
38
+ padding: 0.5rem;
39
+ font-size: var(--naut-font-size-md);
40
+ color: var(--naut-color-content);
41
+ text-wrap: nowrap;
42
+ text-decoration: none;
43
+ cursor: pointer;
44
+
45
+ &:hover {
46
+ color: var(--naut-color-primary);
47
+ background-color: var(--naut-color-base-100);
48
+ opacity: 1;
49
+ }
50
+
51
+ &.active {
52
+ color: var(--naut-color-primary);
53
+ background-color: var(--naut-color-base-100);
54
+ }
55
+
56
+ &.color-dimmed {
57
+ color: var(--naut-color-content-soft);
58
+ opacity: 0.8;
59
+
60
+ &:hover {
61
+ color: var(--naut-color-content);
62
+ }
63
+ }
64
+
65
+ &.color-link {
66
+ color: var(--naut-color-link);
67
+ }
68
+
69
+ .naut-menu-item--main {
70
+ flex: 1;
71
+ text-align: left;
72
+ }
73
+
74
+ .naut-menu-item--left {
75
+ display: flex;
76
+ align-items: center;
77
+ margin-right: 0.4rem;
78
+ }
79
+
80
+ .naut-menu-item--left:empty {
81
+ display: none;
82
+ }
83
+
84
+ .naut-menu-item--right {
85
+ display: flex;
86
+ align-items: center;
87
+ }
88
+
89
+ .naut-menu-item--right:empty {
90
+ display: none;
91
+ }
92
+ }
93
+ </style>
@@ -0,0 +1,211 @@
1
+ ---
2
+ import type { Base, Radius, Shadow } from "../types";
3
+ import Container from "./Container.astro";
4
+
5
+ export interface NavBarProps extends Base {
6
+ autohide?: boolean;
7
+ bordered?: boolean;
8
+ dark?: boolean;
9
+ fluid?: boolean; // if true, the navbar will take the full width of the viewport
10
+ height: number;
11
+ offset?: number; // offset for sticky navbar
12
+ radius?: Radius | "full"; // border-radius for island variant
13
+ shadow?: Shadow;
14
+ sticky?: boolean;
15
+ variant?: "default" | "outline" | "island";
16
+ zindex?: number; // z-index for sticky navbar
17
+ }
18
+
19
+ const {
20
+ class: className,
21
+ dark = false,
22
+ variant = "default",
23
+ bordered = false,
24
+ sticky = false,
25
+ fluid = false,
26
+ autohide = false,
27
+ height = 70, // default height in pixels
28
+ shadow,
29
+ radius,
30
+ offset = 0,
31
+ zindex = 99,
32
+ ...rest
33
+ } = Astro.props as NavBarProps;
34
+ const offsetValue = offset ? `${offset}px` : "0";
35
+ const offsetIsland = offset === 0 ? "var(--naut-spacing-md)" : offsetValue;
36
+ const borderRadius = radius ? `var(--naut-border-radius-${radius})` : "0";
37
+ const barHeight = height ? `${height}px` : "70px";
38
+ const hiddenOffset = `${height + offset}px`;
39
+ ---
40
+
41
+ <nav
42
+ class:list={[
43
+ "naut-navbar",
44
+ `variant--${variant}`,
45
+ sticky && "sticky",
46
+ bordered && "bordered",
47
+ shadow && "shadow",
48
+ radius && `radius--${radius}`,
49
+ fluid && "fluid",
50
+ dark && "dark",
51
+ className
52
+ ]}
53
+ {...rest}
54
+ >
55
+ <div class="naut-space naut-space--left"></div>
56
+ <div class="naut-space naut-space--center">
57
+ <Container fluid={fluid}>
58
+ <div class="naut-navbar--content"><slot /></div>
59
+ </Container>
60
+ </div>
61
+ <div class="naut-space naut-space--right"></div>
62
+ </nav>
63
+
64
+ <style
65
+ define:vars={{
66
+ zindex,
67
+ barHeight,
68
+ borderRadius,
69
+ offsetValue,
70
+ offsetIsland,
71
+ hiddenOffset
72
+ }}
73
+ >
74
+ .naut-navbar {
75
+ --naut-color-navbar-bg: var(--naut-color-base);
76
+ display: flex;
77
+ align-items: center;
78
+ height: var(--barHeight);
79
+ overflow: hidden;
80
+ color: var(--naut-color-content);
81
+ border-radius: var(--borderRadius);
82
+ transition: top 0.3s ease;
83
+
84
+ &.bordered:not(.dark) {
85
+ border-bottom: 1px solid var(--naut-color-border);
86
+ }
87
+
88
+ &.sticky {
89
+ position: fixed;
90
+ top: var(--offsetValue);
91
+ z-index: var(--zindex);
92
+ width: 100%;
93
+
94
+ &.scrolled {
95
+ background-color: rgb(from var(--naut-color-base) r g b / 0.75);
96
+ -webkit-backdrop-filter: blur(20px) saturate(100%);
97
+ backdrop-filter: blur(20px) saturate(100%);
98
+ }
99
+
100
+ &.hidden {
101
+ top: calc(-1 * var(--hiddenOffset));
102
+ }
103
+ }
104
+
105
+ &.radius--none {
106
+ border-radius: 0;
107
+ }
108
+
109
+ &.variant--island {
110
+ margin: 0 var(--naut-spacing-md);
111
+
112
+ &.sticky {
113
+ top: var(--offsetIsland);
114
+ left: 50%;
115
+ width: calc(100% - 2 * var(--naut-spacing-md));
116
+ margin: 0;
117
+ transform: translateX(-50%);
118
+ }
119
+
120
+ &.bordered {
121
+ border: 1px solid var(--naut-color-border);
122
+ }
123
+
124
+ &:not(.fluid) {
125
+ /*Mobile*/
126
+ @media only screen and (min-width: 576px) {
127
+ max-width: calc(576px + 2 * var(--naut-spacing-md));
128
+ margin: 0 auto;
129
+ }
130
+
131
+ /* Tablet */
132
+ @media only screen and (min-width: 818px) and (max-width: 1041px) {
133
+ max-width: calc(768px + 2 * var(--naut-spacing-md));
134
+ }
135
+
136
+ /* Desktop */
137
+ @media only screen and (min-width: 1042px) and (max-width: 1249px) {
138
+ max-width: calc(992px + 2 * var(--naut-spacing-md));
139
+ }
140
+
141
+ /* Large Desktop */
142
+ @media only screen and (min-width: 1250px) {
143
+ max-width: calc(1200px + 2 * var(--naut-spacing-md));
144
+ }
145
+ }
146
+ }
147
+
148
+ &.variant--outline {
149
+ .naut-space {
150
+ flex-grow: 1;
151
+ height: 100%;
152
+ }
153
+ .naut-space--left {
154
+ padding-right: var(--naut-spacing-md);
155
+ border-right: 1px solid var(--naut-color-border);
156
+ }
157
+ .naut-space--right {
158
+ padding-left: var(--naut-spacing-md);
159
+ border-left: 1px solid var(--naut-color-border);
160
+ }
161
+ }
162
+
163
+ &.shadow {
164
+ box-shadow: calc(0.0625 * calc(1rem * 1)) calc(0.5 * calc(1rem * 1))
165
+ calc(1 * calc(1rem * 1)) #0000001a;
166
+ }
167
+
168
+ .naut-space--center {
169
+ flex: 0 0 100%;
170
+ }
171
+
172
+ .naut-navbar--content {
173
+ display: flex;
174
+ align-items: center;
175
+ justify-content: space-between;
176
+ height: var(--barHeight);
177
+ }
178
+ }
179
+ </style>
180
+
181
+ <script is:inline define:vars={{ autohide, height, offset }}>
182
+ const nav = document.querySelector(".naut-navbar");
183
+ let lastScrollY = 0;
184
+ if (nav) {
185
+ const update = () => {
186
+ const scrolled = window.scrollY > 0;
187
+ nav.classList.toggle("scrolled", scrolled);
188
+ if (autohide) {
189
+ const offsetPoint = height + offset;
190
+ const pastOffset = window.scrollY > offsetPoint;
191
+ const scrollingDown = window.scrollY > lastScrollY;
192
+ nav.classList.toggle("hidden", pastOffset && scrollingDown);
193
+ lastScrollY = window.scrollY;
194
+ }
195
+ };
196
+ window.addEventListener("scroll", update, { passive: true });
197
+ update();
198
+ }
199
+ </script>
200
+
201
+ <script>
202
+ const nav = document.querySelector(".naut-navbar");
203
+ const sections = document.querySelector(".naut-section.dark");
204
+ if (nav && sections) {
205
+ const observer = new IntersectionObserver(
206
+ ([entry]) => nav.classList.toggle("dark", entry.isIntersecting),
207
+ { threshold: 0.1 }
208
+ );
209
+ observer.observe(sections);
210
+ }
211
+ </script>