create-bunspace 0.4.0 → 0.5.1
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/dist/bin.js +100 -0
- package/dist/templates/fumadocs/MUST-FOLLOW-GUIDELINES.md +283 -170
- package/dist/templates/monorepo/MUST-FOLLOW-GUIDELINES.md +283 -170
- package/dist/templates/react-starter/MUST-FOLLOW-GUIDELINES.md +1845 -0
- package/dist/templates/react-starter/README.md +100 -0
- package/dist/templates/react-starter/bun.lock +1298 -0
- package/dist/templates/react-starter/components.json +27 -0
- package/dist/templates/react-starter/eslint.config.js +23 -0
- package/dist/templates/react-starter/index.html +36 -0
- package/dist/templates/react-starter/package.json +57 -0
- package/dist/templates/react-starter/public/registry.json +115 -0
- package/dist/templates/react-starter/public/themes/darkmatteviolet-dark.css +34 -0
- package/dist/templates/react-starter/public/themes/darkmatteviolet-light.css +34 -0
- package/dist/templates/react-starter/public/themes/default-dark.css +33 -0
- package/dist/templates/react-starter/public/themes/default-light.css +34 -0
- package/dist/templates/react-starter/public/themes/graphite-dark.css +34 -0
- package/dist/templates/react-starter/public/themes/graphite-light.css +34 -0
- package/dist/templates/react-starter/public/themes/synthwave84-dark.css +34 -0
- package/dist/templates/react-starter/public/themes/synthwave84-light.css +34 -0
- package/dist/templates/react-starter/public/vite.svg +1 -0
- package/dist/templates/react-starter/src/App.tsx +245 -0
- package/dist/templates/react-starter/src/assets/react.svg +1 -0
- package/dist/templates/react-starter/src/components/ThemeSelector.tsx +106 -0
- package/dist/templates/react-starter/src/components/animate-ui/components/buttons/icon.tsx +86 -0
- package/dist/templates/react-starter/src/components/animate-ui/components/buttons/theme-toggler.tsx +92 -0
- package/dist/templates/react-starter/src/components/animate-ui/primitives/animate/slot.tsx +96 -0
- package/dist/templates/react-starter/src/components/animate-ui/primitives/buttons/button.tsx +31 -0
- package/dist/templates/react-starter/src/components/animate-ui/primitives/effects/particles.tsx +155 -0
- package/dist/templates/react-starter/src/components/animate-ui/primitives/effects/theme-toggler.tsx +148 -0
- package/dist/templates/react-starter/src/components/component-example.tsx +444 -0
- package/dist/templates/react-starter/src/components/example.tsx +56 -0
- package/dist/templates/react-starter/src/index.css +131 -0
- package/dist/templates/react-starter/src/main.tsx +13 -0
- package/dist/templates/react-starter/src/providers/ThemeProvider.tsx +27 -0
- package/dist/templates/react-starter/tsconfig.app.json +36 -0
- package/dist/templates/react-starter/tsconfig.json +13 -0
- package/dist/templates/react-starter/tsconfig.node.json +26 -0
- package/dist/templates/react-starter/vite.config.ts +17 -0
- package/dist/templates/telegram-bot/MUST-FOLLOW-GUIDELINES.md +283 -170
- package/package.json +1 -1
- package/templates/fumadocs/MUST-FOLLOW-GUIDELINES.md +283 -170
- package/templates/monorepo/MUST-FOLLOW-GUIDELINES.md +283 -170
- package/templates/react-starter/MUST-FOLLOW-GUIDELINES.md +1845 -0
- package/templates/react-starter/README.md +100 -0
- package/templates/react-starter/bun.lock +1298 -0
- package/templates/react-starter/components.json +27 -0
- package/templates/react-starter/eslint.config.js +23 -0
- package/templates/react-starter/index.html +36 -0
- package/templates/react-starter/package.json +57 -0
- package/templates/react-starter/public/registry.json +115 -0
- package/templates/react-starter/public/themes/darkmatteviolet-dark.css +34 -0
- package/templates/react-starter/public/themes/darkmatteviolet-light.css +34 -0
- package/templates/react-starter/public/themes/default-dark.css +33 -0
- package/templates/react-starter/public/themes/default-light.css +34 -0
- package/templates/react-starter/public/themes/graphite-dark.css +34 -0
- package/templates/react-starter/public/themes/graphite-light.css +34 -0
- package/templates/react-starter/public/themes/synthwave84-dark.css +34 -0
- package/templates/react-starter/public/themes/synthwave84-light.css +34 -0
- package/templates/react-starter/public/vite.svg +1 -0
- package/templates/react-starter/src/App.tsx +245 -0
- package/templates/react-starter/src/assets/react.svg +1 -0
- package/templates/react-starter/src/components/ThemeSelector.tsx +106 -0
- package/templates/react-starter/src/components/animate-ui/components/buttons/icon.tsx +86 -0
- package/templates/react-starter/src/components/animate-ui/components/buttons/theme-toggler.tsx +92 -0
- package/templates/react-starter/src/components/animate-ui/primitives/animate/slot.tsx +96 -0
- package/templates/react-starter/src/components/animate-ui/primitives/buttons/button.tsx +31 -0
- package/templates/react-starter/src/components/animate-ui/primitives/effects/particles.tsx +155 -0
- package/templates/react-starter/src/components/animate-ui/primitives/effects/theme-toggler.tsx +148 -0
- package/templates/react-starter/src/components/component-example.tsx +444 -0
- package/templates/react-starter/src/components/example.tsx +56 -0
- package/templates/react-starter/src/index.css +131 -0
- package/templates/react-starter/src/main.tsx +13 -0
- package/templates/react-starter/src/providers/ThemeProvider.tsx +27 -0
- package/templates/react-starter/tsconfig.app.json +36 -0
- package/templates/react-starter/tsconfig.json +13 -0
- package/templates/react-starter/tsconfig.node.json +26 -0
- package/templates/react-starter/vite.config.ts +17 -0
- package/templates/telegram-bot/MUST-FOLLOW-GUIDELINES.md +283 -170
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { motion, AnimatePresence, type HTMLMotionProps } from 'motion/react';
|
|
5
|
+
|
|
6
|
+
import { Slot, type WithAsChild } from '@/components/animate-ui/primitives/animate/slot';
|
|
7
|
+
import {
|
|
8
|
+
useIsInView,
|
|
9
|
+
type IUseIsInViewOptions,
|
|
10
|
+
getStrictContext,
|
|
11
|
+
} from '@mks2508/mks-ui/react';
|
|
12
|
+
|
|
13
|
+
type Side = 'top' | 'bottom' | 'left' | 'right';
|
|
14
|
+
type Align = 'start' | 'center' | 'end';
|
|
15
|
+
|
|
16
|
+
type ParticlesContextType = {
|
|
17
|
+
animate: boolean;
|
|
18
|
+
isInView: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const [ParticlesProvider, useParticles] =
|
|
22
|
+
getStrictContext<ParticlesContextType>('ParticlesContext');
|
|
23
|
+
|
|
24
|
+
type ParticlesProps = WithAsChild<
|
|
25
|
+
Omit<HTMLMotionProps<'div'>, 'children'> & {
|
|
26
|
+
animate?: boolean;
|
|
27
|
+
children: React.ReactNode;
|
|
28
|
+
} & IUseIsInViewOptions
|
|
29
|
+
>;
|
|
30
|
+
|
|
31
|
+
function Particles({
|
|
32
|
+
ref,
|
|
33
|
+
animate = true,
|
|
34
|
+
asChild = false,
|
|
35
|
+
inView = false,
|
|
36
|
+
inViewMargin = '0px',
|
|
37
|
+
inViewOnce = true,
|
|
38
|
+
children,
|
|
39
|
+
style,
|
|
40
|
+
...props
|
|
41
|
+
}: ParticlesProps) {
|
|
42
|
+
const { ref: localRef, isInView } = useIsInView(
|
|
43
|
+
ref as React.Ref<HTMLDivElement>,
|
|
44
|
+
{ inView, inViewOnce, inViewMargin },
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
const Component = asChild ? Slot : motion.div;
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<ParticlesProvider value={{ animate, isInView }}>
|
|
51
|
+
<Component
|
|
52
|
+
ref={localRef}
|
|
53
|
+
style={{ position: 'relative', ...style }}
|
|
54
|
+
{...props}
|
|
55
|
+
>
|
|
56
|
+
{children}
|
|
57
|
+
</Component>
|
|
58
|
+
</ParticlesProvider>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
type ParticlesEffectProps = Omit<HTMLMotionProps<'div'>, 'children'> & {
|
|
63
|
+
side?: Side;
|
|
64
|
+
align?: Align;
|
|
65
|
+
count?: number;
|
|
66
|
+
radius?: number;
|
|
67
|
+
spread?: number;
|
|
68
|
+
duration?: number;
|
|
69
|
+
holdDelay?: number;
|
|
70
|
+
sideOffset?: number;
|
|
71
|
+
alignOffset?: number;
|
|
72
|
+
delay?: number;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
function ParticlesEffect({
|
|
76
|
+
side = 'top',
|
|
77
|
+
align = 'center',
|
|
78
|
+
count = 6,
|
|
79
|
+
radius = 30,
|
|
80
|
+
spread = 360,
|
|
81
|
+
duration = 0.8,
|
|
82
|
+
holdDelay = 0.05,
|
|
83
|
+
sideOffset = 0,
|
|
84
|
+
alignOffset = 0,
|
|
85
|
+
delay = 0,
|
|
86
|
+
transition,
|
|
87
|
+
style,
|
|
88
|
+
...props
|
|
89
|
+
}: ParticlesEffectProps) {
|
|
90
|
+
const { animate, isInView } = useParticles();
|
|
91
|
+
|
|
92
|
+
const isVertical = side === 'top' || side === 'bottom';
|
|
93
|
+
const alignPct = align === 'start' ? '0%' : align === 'end' ? '100%' : '50%';
|
|
94
|
+
|
|
95
|
+
const top = isVertical
|
|
96
|
+
? side === 'top'
|
|
97
|
+
? `calc(0% - ${sideOffset}px)`
|
|
98
|
+
: `calc(100% + ${sideOffset}px)`
|
|
99
|
+
: `calc(${alignPct} + ${alignOffset}px)`;
|
|
100
|
+
|
|
101
|
+
const left = isVertical
|
|
102
|
+
? `calc(${alignPct} + ${alignOffset}px)`
|
|
103
|
+
: side === 'left'
|
|
104
|
+
? `calc(0% - ${sideOffset}px)`
|
|
105
|
+
: `calc(100% + ${sideOffset}px)`;
|
|
106
|
+
|
|
107
|
+
const containerStyle: React.CSSProperties = {
|
|
108
|
+
position: 'absolute',
|
|
109
|
+
top,
|
|
110
|
+
left,
|
|
111
|
+
transform: 'translate(-50%, -50%)',
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const angleStep = (spread * (Math.PI / 180)) / Math.max(1, count - 1);
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<AnimatePresence>
|
|
118
|
+
{animate &&
|
|
119
|
+
isInView &&
|
|
120
|
+
[...Array(count)].map((_, i) => {
|
|
121
|
+
const angle = i * angleStep;
|
|
122
|
+
const x = Math.cos(angle) * radius;
|
|
123
|
+
const y = Math.sin(angle) * radius;
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<motion.div
|
|
127
|
+
key={i}
|
|
128
|
+
style={{ ...containerStyle, ...style }}
|
|
129
|
+
initial={{ scale: 0, opacity: 0 }}
|
|
130
|
+
animate={{
|
|
131
|
+
x: `${x}px`,
|
|
132
|
+
y: `${y}px`,
|
|
133
|
+
scale: [0, 1, 0],
|
|
134
|
+
opacity: [0, 1, 0],
|
|
135
|
+
}}
|
|
136
|
+
transition={{
|
|
137
|
+
duration,
|
|
138
|
+
delay: delay + i * holdDelay,
|
|
139
|
+
ease: 'easeOut',
|
|
140
|
+
...transition,
|
|
141
|
+
}}
|
|
142
|
+
{...props}
|
|
143
|
+
/>
|
|
144
|
+
);
|
|
145
|
+
})}
|
|
146
|
+
</AnimatePresence>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export {
|
|
151
|
+
Particles,
|
|
152
|
+
ParticlesEffect,
|
|
153
|
+
type ParticlesProps,
|
|
154
|
+
type ParticlesEffectProps,
|
|
155
|
+
};
|
package/templates/react-starter/src/components/animate-ui/primitives/effects/theme-toggler.tsx
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { flushSync } from 'react-dom';
|
|
5
|
+
|
|
6
|
+
type ThemeSelection = 'light' | 'dark' | 'system';
|
|
7
|
+
type Resolved = 'light' | 'dark';
|
|
8
|
+
type Direction = 'btt' | 'ttb' | 'ltr' | 'rtl';
|
|
9
|
+
|
|
10
|
+
type ChildrenRender =
|
|
11
|
+
| React.ReactNode
|
|
12
|
+
| ((state: {
|
|
13
|
+
resolved: Resolved;
|
|
14
|
+
effective: ThemeSelection;
|
|
15
|
+
toggleTheme: (theme: ThemeSelection) => void;
|
|
16
|
+
}) => React.ReactNode);
|
|
17
|
+
|
|
18
|
+
function getSystemEffective(): Resolved {
|
|
19
|
+
if (typeof window === 'undefined') return 'light';
|
|
20
|
+
return window.matchMedia('(prefers-color-scheme: dark)').matches
|
|
21
|
+
? 'dark'
|
|
22
|
+
: 'light';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getClipKeyframes(direction: Direction): [string, string] {
|
|
26
|
+
switch (direction) {
|
|
27
|
+
case 'ltr':
|
|
28
|
+
return ['inset(0 100% 0 0)', 'inset(0 0 0 0)'];
|
|
29
|
+
case 'rtl':
|
|
30
|
+
return ['inset(0 0 0 100%)', 'inset(0 0 0 0)'];
|
|
31
|
+
case 'ttb':
|
|
32
|
+
return ['inset(0 0 100% 0)', 'inset(0 0 0 0)'];
|
|
33
|
+
case 'btt':
|
|
34
|
+
return ['inset(100% 0 0 0)', 'inset(0 0 0 0)'];
|
|
35
|
+
default:
|
|
36
|
+
return ['inset(0 100% 0 0)', 'inset(0 0 0 0)'];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
type ThemeTogglerProps = {
|
|
41
|
+
theme: ThemeSelection;
|
|
42
|
+
resolvedTheme: Resolved;
|
|
43
|
+
setTheme: (theme: ThemeSelection) => void;
|
|
44
|
+
direction?: Direction;
|
|
45
|
+
onImmediateChange?: (theme: ThemeSelection) => void;
|
|
46
|
+
children?: ChildrenRender;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
function ThemeToggler({
|
|
50
|
+
theme,
|
|
51
|
+
resolvedTheme,
|
|
52
|
+
setTheme,
|
|
53
|
+
onImmediateChange,
|
|
54
|
+
direction = 'ltr',
|
|
55
|
+
children,
|
|
56
|
+
...props
|
|
57
|
+
}: ThemeTogglerProps) {
|
|
58
|
+
const [preview, setPreview] = React.useState<null | {
|
|
59
|
+
effective: ThemeSelection;
|
|
60
|
+
resolved: Resolved;
|
|
61
|
+
}>(null);
|
|
62
|
+
const [current, setCurrent] = React.useState<{
|
|
63
|
+
effective: ThemeSelection;
|
|
64
|
+
resolved: Resolved;
|
|
65
|
+
}>({
|
|
66
|
+
effective: theme,
|
|
67
|
+
resolved: resolvedTheme,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
React.useEffect(() => {
|
|
71
|
+
if (
|
|
72
|
+
preview &&
|
|
73
|
+
theme === preview.effective &&
|
|
74
|
+
resolvedTheme === preview.resolved
|
|
75
|
+
) {
|
|
76
|
+
setPreview(null);
|
|
77
|
+
}
|
|
78
|
+
}, [theme, resolvedTheme, preview]);
|
|
79
|
+
|
|
80
|
+
const [fromClip, toClip] = getClipKeyframes(direction);
|
|
81
|
+
|
|
82
|
+
const toggleTheme = React.useCallback(
|
|
83
|
+
async (theme: ThemeSelection) => {
|
|
84
|
+
const resolved = theme === 'system' ? getSystemEffective() : theme;
|
|
85
|
+
|
|
86
|
+
setCurrent({ effective: theme, resolved });
|
|
87
|
+
onImmediateChange?.(theme);
|
|
88
|
+
|
|
89
|
+
if (theme === 'system' && resolved === resolvedTheme) {
|
|
90
|
+
setTheme(theme);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!document.startViewTransition) {
|
|
95
|
+
flushSync(() => {
|
|
96
|
+
setPreview({ effective: theme, resolved });
|
|
97
|
+
});
|
|
98
|
+
setTheme(theme);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
await document.startViewTransition(() => {
|
|
103
|
+
flushSync(() => {
|
|
104
|
+
setPreview({ effective: theme, resolved });
|
|
105
|
+
document.documentElement.classList.toggle(
|
|
106
|
+
'dark',
|
|
107
|
+
resolved === 'dark',
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
}).ready;
|
|
111
|
+
|
|
112
|
+
document.documentElement
|
|
113
|
+
.animate(
|
|
114
|
+
{ clipPath: [fromClip, toClip] },
|
|
115
|
+
{
|
|
116
|
+
duration: 700,
|
|
117
|
+
easing: 'ease-in-out',
|
|
118
|
+
pseudoElement: '::view-transition-new(root)',
|
|
119
|
+
},
|
|
120
|
+
)
|
|
121
|
+
.finished.finally(() => {
|
|
122
|
+
setTheme(theme);
|
|
123
|
+
});
|
|
124
|
+
},
|
|
125
|
+
[onImmediateChange, resolvedTheme, fromClip, toClip, setTheme],
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
return (
|
|
129
|
+
<React.Fragment {...props}>
|
|
130
|
+
{typeof children === 'function'
|
|
131
|
+
? children({
|
|
132
|
+
effective: current.effective,
|
|
133
|
+
resolved: current.resolved,
|
|
134
|
+
toggleTheme,
|
|
135
|
+
})
|
|
136
|
+
: children}
|
|
137
|
+
<style>{`::view-transition-old(root), ::view-transition-new(root){animation:none;mix-blend-mode:normal;}`}</style>
|
|
138
|
+
</React.Fragment>
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export {
|
|
143
|
+
ThemeToggler,
|
|
144
|
+
type ThemeTogglerProps,
|
|
145
|
+
type ThemeSelection,
|
|
146
|
+
type Resolved,
|
|
147
|
+
type Direction,
|
|
148
|
+
};
|