@androbinco/library-cli 0.1.0 → 0.3.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 (53) hide show
  1. package/README.md +86 -37
  2. package/package.json +11 -16
  3. package/src/commands/add.js +107 -0
  4. package/src/commands/list.js +51 -0
  5. package/src/index.js +46 -15
  6. package/src/templates/carousel/components/navigation-buttons.tsx +1 -0
  7. package/src/templates/carousel/components/pagination/bullet.pagination.carousel.tsx +69 -0
  8. package/src/templates/carousel/components/pagination/number.pagination.carousel.tsx +30 -0
  9. package/src/templates/carousel/components/pagination/progress/progress.pagination.carousel.tsx +99 -0
  10. package/src/templates/carousel/components/pagination/progress/use-slide-progress.tsx +31 -0
  11. package/src/templates/carousel/components/pagination.tsx +47 -82
  12. package/src/templates/faqs-accordion/examples/faqs-showcase.tsx +42 -0
  13. package/src/templates/faqs-accordion/faqs-accordion.tsx +70 -0
  14. package/src/templates/faqs-accordion/mock-data.ts +38 -0
  15. package/src/templates/faqs-accordion/types.ts +18 -0
  16. package/src/templates/in-view/data.in-view.ts +89 -0
  17. package/src/templates/in-view/examples/in-view-examples.home.tsx +101 -0
  18. package/src/templates/in-view/examples/in-view-grid-showcase.tsx +41 -0
  19. package/src/templates/in-view/in-view-animation.tsx +72 -0
  20. package/src/templates/in-view/in-view-grid.tsx +81 -0
  21. package/src/templates/in-view/in-view-hidden-text.tsx +45 -0
  22. package/src/templates/in-view/in-view-stroke-line.tsx +30 -0
  23. package/src/templates/lenis/examples/providers.tsx +23 -0
  24. package/src/templates/lenis/lenis-provider.tsx +46 -0
  25. package/src/templates/scroll-components/hooks/use-client-dimensions.ts +21 -0
  26. package/src/templates/scroll-components/parallax/examples/parallax-showcase.tsx +87 -0
  27. package/src/templates/scroll-components/parallax/parallax.css +36 -0
  28. package/src/templates/scroll-components/parallax/parallax.tsx +67 -0
  29. package/src/templates/scroll-components/scale-gallery/components/expanding-element.tsx +40 -0
  30. package/src/templates/scroll-components/scale-gallery/examples/scale-gallery-showcase.tsx +68 -0
  31. package/src/templates/scroll-components/scale-gallery/scale-gallery.tsx +57 -0
  32. package/src/templates/scroll-components/scroll-tracker-provider.tsx +78 -0
  33. package/src/templates/scroll-components/scroll-tracker-showcase.tsx +44 -0
  34. package/src/templates/strapi-dynamic-zone/README.md +157 -0
  35. package/src/templates/strapi-dynamic-zone/dynamic-zone.tsx +113 -0
  36. package/src/templates/strapi-dynamic-zone/examples/page.tsx +53 -0
  37. package/src/templates/strapi-dynamic-zone/examples/renderers.tsx +74 -0
  38. package/src/templates/strapi-dynamic-zone/examples/types.ts +41 -0
  39. package/src/templates/strapi-dynamic-zone/index.ts +11 -0
  40. package/src/templates/strapi-dynamic-zone/types.ts +73 -0
  41. package/src/templates/ticker/css-ticker/css-ticker.tsx +61 -0
  42. package/src/templates/ticker/css-ticker/ticker.keyframes.css +86 -0
  43. package/src/templates/ticker/examples/ticker-hover-showcase.home.tsx +57 -0
  44. package/src/templates/ticker/examples/ticker-static-showcase.home.tsx +56 -0
  45. package/src/templates/ticker/hooks/use-ticker-clones.tsx +70 -0
  46. package/src/templates/ticker/hooks/use-ticker-incremental.tsx +72 -0
  47. package/src/templates/ticker/motion-ticker.tsx +93 -0
  48. package/src/utils/components.js +587 -54
  49. package/src/utils/files.js +89 -5
  50. package/src/templates/button/button.tsx +0 -5
  51. package/src/templates/card/card.tsx +0 -5
  52. package/src/templates/example/example.tsx +0 -5
  53. package/src/templates/hero/hero.tsx +0 -5
@@ -0,0 +1,86 @@
1
+ .ticker {
2
+ --ticker-speed: 20s;
3
+ }
4
+ .ticker-slow {
5
+ --ticker-speed: 100s;
6
+ }
7
+
8
+ @keyframes base-ticker-right {
9
+ 0% {
10
+ transform: translateX(0%);
11
+ }
12
+
13
+ 50% {
14
+ transform: translateX(100%);
15
+ }
16
+
17
+ 50.001% {
18
+ transform: translateX(-100%);
19
+ }
20
+
21
+ 100% {
22
+ transform: translateX(0%);
23
+ }
24
+ }
25
+ @keyframes cloned-ticker-right {
26
+ 0% {
27
+ transform: translateX(0%);
28
+ }
29
+ 100% {
30
+ transform: translateX(200%);
31
+ }
32
+ }
33
+
34
+ @keyframes base-ticker-left {
35
+ 0% {
36
+ transform: translateX(0%);
37
+ }
38
+
39
+ 50% {
40
+ transform: translateX(-100%);
41
+ }
42
+
43
+ 50.001% {
44
+ transform: translateX(100%);
45
+ }
46
+
47
+ 100% {
48
+ transform: translateX(0%);
49
+ }
50
+ }
51
+ @keyframes cloned-ticker-left {
52
+ 0% {
53
+ transform: translateX(0%);
54
+ }
55
+ 100% {
56
+ transform: translateX(-200%);
57
+ }
58
+ }
59
+ .animate-base-ticker {
60
+ animation-name: base-ticker-right;
61
+ animation-duration: var(--ticker-speed);
62
+ animation-timing-function: linear;
63
+ animation-iteration-count: infinite;
64
+ }
65
+
66
+ .animate-cloned-ticker {
67
+ animation-name: cloned-ticker-right;
68
+ animation-duration: var(--ticker-speed);
69
+ animation-timing-function: linear;
70
+ animation-iteration-count: infinite;
71
+ }
72
+ .animate-base-ticker-left {
73
+ animation-name: base-ticker-left;
74
+ animation-duration: var(--ticker-speed);
75
+ animation-timing-function: linear;
76
+ animation-iteration-count: infinite;
77
+ }
78
+ .animate-cloned-ticker-left {
79
+ animation-name: cloned-ticker-left;
80
+ animation-duration: var(--ticker-speed);
81
+ animation-timing-function: linear;
82
+ animation-iteration-count: infinite;
83
+ }
84
+ .animate-pause {
85
+ animation-play-state: paused;
86
+ }
@@ -0,0 +1,57 @@
1
+ import { MotionTicker } from "../motion-ticker";
2
+ import { Text } from "@/common/ui/text/text";
3
+
4
+ /*
5
+ This is a ticker component that is used to display a list of items in a ticker.
6
+ It is a wrapper around the motion library and uses the useMotionValue hook to create the ticker.
7
+ It is a client component that is used to display a list of items in a ticker.
8
+
9
+ To test it you can just use it like this in any page:
10
+ <TickerHoverShowcaseHome />
11
+ */
12
+
13
+ const TickerExampleCard = ({
14
+ text = "BASIC TICKER EXAMPLE",
15
+ }: {
16
+ text?: string;
17
+ }) => {
18
+ return (
19
+ <div className="border-2 border-x-0 border-fill-brand-primary bg-bg-primary-inverse px-5 py-2">
20
+ <Text className="capitalize" variant="body.2">
21
+ {text}
22
+ </Text>
23
+ </div>
24
+ );
25
+ };
26
+ const CardWithSpacingExample = ({
27
+ text = "CARD WITH SPACING EXAMPLE",
28
+ }: {
29
+ text?: string;
30
+ }) => {
31
+ return (
32
+ <div className="px-1">
33
+ <div className="border-2 border-fill-brand-primary bg-bg-primary-inverse px-5 py-2">
34
+ <Text className="capitalize" variant="body.2">
35
+ {text}
36
+ </Text>
37
+ </div>
38
+ </div>
39
+ );
40
+ };
41
+
42
+ export const TickerHoverShowcaseHome = () => {
43
+ return (
44
+ <div className="flex flex-col gap-12">
45
+ <Text className="px-4 pb-15" variant="title.6">
46
+ Ticker with hover stop
47
+ </Text>
48
+ <MotionTicker>
49
+ <CardWithSpacingExample text="TICKER EXAMPLE" />
50
+ <CardWithSpacingExample text="HOVER TICKER" />
51
+ </MotionTicker>
52
+ <MotionTicker direction="left">
53
+ <TickerExampleCard text="TICKER EXAMPLE" />
54
+ </MotionTicker>
55
+ </div>
56
+ );
57
+ };
@@ -0,0 +1,56 @@
1
+ import { TickerStatic } from "../css-ticker/css-ticker";
2
+ import { Text } from "@/common/ui/text/text";
3
+
4
+ /*
5
+ This is a ticker component that is used to display a list of items in a ticker.
6
+ It is a wrapper around the css library and uses the css animations to create the ticker.
7
+ It is a client component that is used to display a list of items in a ticker.
8
+
9
+ To test it you can just use it like this in any page:
10
+ */
11
+
12
+ const TickerExampleCard = ({
13
+ text = "BASIC TICKER EXAMPLE",
14
+ }: {
15
+ text?: string;
16
+ }) => {
17
+ return (
18
+ <div className="border-2 border-x-0 border-fill-brand-primary bg-bg-primary-inverse px-5 py-2">
19
+ <Text className="capitalize" variant="body.2">
20
+ {text}
21
+ </Text>
22
+ </div>
23
+ );
24
+ };
25
+ const CardWithSpacingExample = ({
26
+ text = "CARD WITH SPACING EXAMPLE",
27
+ }: {
28
+ text?: string;
29
+ }) => {
30
+ return (
31
+ <div className="px-1">
32
+ <div className="border-2 border-fill-brand-primary bg-bg-primary-inverse px-5 py-2">
33
+ <Text className="capitalize" variant="body.2">
34
+ {text}
35
+ </Text>
36
+ </div>
37
+ </div>
38
+ );
39
+ };
40
+
41
+ export const TickerStaticShowcaseHome = () => {
42
+ return (
43
+ <div className="flex flex-col gap-12">
44
+ <Text className="px-4 pb-15" variant="title.6">
45
+ Ticker static
46
+ </Text>
47
+ <TickerStatic>
48
+ <TickerExampleCard text="STATIC TICKER EXAMPLE" />
49
+ <TickerExampleCard text="TICKER" />
50
+ </TickerStatic>
51
+ <TickerStatic direction="left">
52
+ <CardWithSpacingExample text="TICKER EXAMPLE" />
53
+ </TickerStatic>
54
+ </div>
55
+ );
56
+ };
@@ -0,0 +1,70 @@
1
+ import { useEffect, useRef, useState } from 'react';
2
+
3
+ export const useTickerClones = ({
4
+ tickerCard,
5
+ tickerClone,
6
+ onCloneWrapper,
7
+ direction,
8
+ }: {
9
+ tickerCard: React.RefObject<HTMLDivElement | null>;
10
+ tickerClone: React.RefObject<HTMLDivElement | null>;
11
+ onCloneWrapper?: (clone: HTMLElement) => void;
12
+ direction: 'left' | 'right';
13
+ }) => {
14
+ const calculatedWidth = useRef(0);
15
+ const [clonesNeeded, setClonesNeeded] = useState(1);
16
+
17
+ useEffect(() => {
18
+ if (typeof window === 'undefined') return;
19
+ const sizeCloneNeeded = () => {
20
+ const tickerCardContent = Array.from(tickerCard.current?.childNodes ?? []).reduce(
21
+ (acc, child) => {
22
+ if (child.nodeType === Node.TEXT_NODE) {
23
+ return acc;
24
+ }
25
+
26
+ return acc + (child as HTMLElement)?.offsetWidth;
27
+ },
28
+ 0,
29
+ );
30
+
31
+ const tickerCardWidth = tickerCardContent;
32
+
33
+ if (!tickerCardWidth) return;
34
+ calculatedWidth.current = tickerCardWidth;
35
+ const clonesCalc = Math.ceil(window.outerWidth / tickerCardWidth);
36
+
37
+ if (clonesCalc > 1) setClonesNeeded(clonesCalc);
38
+ };
39
+
40
+ sizeCloneNeeded();
41
+ window.addEventListener('resize', sizeCloneNeeded);
42
+
43
+ return () => {
44
+ window.removeEventListener('resize', sizeCloneNeeded);
45
+ };
46
+ }, [tickerCard]);
47
+ useEffect(() => {
48
+ if (typeof window === 'undefined') return;
49
+ const clonedTickerContent = tickerCard.current?.cloneNode(true) as HTMLElement;
50
+
51
+ if (!clonedTickerContent) return;
52
+ if (tickerClone?.current?.childNodes.length) {
53
+ tickerClone.current.removeChild(tickerClone.current.childNodes[0]);
54
+ }
55
+ clonedTickerContent.id = 'ticker-content-clone';
56
+
57
+ if (onCloneWrapper) onCloneWrapper(clonedTickerContent);
58
+
59
+ const tickerCardWidth = tickerCard.current?.offsetWidth;
60
+
61
+ tickerClone.current?.style.setProperty(
62
+ 'left',
63
+ direction === 'right' ? `-${tickerCardWidth}px` : `${tickerCardWidth}px`,
64
+ 'important',
65
+ );
66
+ tickerClone.current?.appendChild(clonedTickerContent);
67
+ }, [clonesNeeded, tickerCard, tickerClone, direction, onCloneWrapper]);
68
+
69
+ return { clonesNeeded, calculatedWidth };
70
+ };
@@ -0,0 +1,72 @@
1
+ 'use client';
2
+ import { useEffect, useRef } from 'react';
3
+
4
+ import { MotionValue, useMotionValue, useMotionValueEvent } from 'motion/react';
5
+
6
+ const directionModifier = {
7
+ left: false,
8
+ right: true,
9
+ };
10
+
11
+ export const useTickerIncremental = ({
12
+ direction,
13
+ speed,
14
+ delta,
15
+ stopIncrement,
16
+ onStop,
17
+ }: {
18
+ speed: number;
19
+ delta: number;
20
+ direction: 'left' | 'right';
21
+ stopIncrement?: boolean;
22
+ onStop?: (x: MotionValue<number>) => void;
23
+ }) => {
24
+ const x = useMotionValue(0);
25
+ const lastTimeRef = useRef<number>(0);
26
+ const fpsRef = useRef(60);
27
+ const translateX = useMotionValue('0%');
28
+ const clonedTranslateX = useMotionValue('0%');
29
+ const requestRef = useRef<number>(0);
30
+
31
+ useMotionValueEvent(x, 'change', (value) => {
32
+ const modifier = directionModifier[direction] ? 1 : -1;
33
+
34
+ translateX.set(`${modifier * (value > 100 ? value - 200 : value)}%`);
35
+ clonedTranslateX.set(`${modifier * value}%`);
36
+ });
37
+
38
+ useEffect(() => {
39
+ if (stopIncrement) {
40
+ cancelAnimationFrame(requestRef.current);
41
+ onStop?.(x);
42
+
43
+ return;
44
+ }
45
+ const animate = (now: number) => {
46
+ const currentX = x.get();
47
+ const deltaMs = now - lastTimeRef.current;
48
+
49
+ lastTimeRef.current = now;
50
+
51
+ fpsRef.current = 1000 / deltaMs;
52
+
53
+ if (currentX >= 200) {
54
+ x.set(0);
55
+ } else {
56
+ const newX = Number((currentX + speed * delta).toFixed(4));
57
+
58
+ x.set(newX);
59
+ }
60
+
61
+ requestRef.current = requestAnimationFrame(animate);
62
+ };
63
+
64
+ requestRef.current = requestAnimationFrame(animate);
65
+
66
+ return () => {
67
+ cancelAnimationFrame(requestRef.current);
68
+ };
69
+ }, [speed, delta, x, stopIncrement, onStop]);
70
+
71
+ return { x, x1: translateX, x2: clonedTranslateX, fps: fpsRef };
72
+ };
@@ -0,0 +1,93 @@
1
+ 'use client';
2
+ import { Fragment, useRef, useState } from 'react';
3
+
4
+ import { animate, motion, useInView } from 'motion/react';
5
+
6
+ import { cn } from '@/common/utils/classname-builder';
7
+
8
+ import { useTickerClones } from './hooks/use-ticker-clones';
9
+ import { useTickerIncremental } from './hooks/use-ticker-incremental';
10
+ type MotionTickerProps = {
11
+ direction?: 'left' | 'right';
12
+ speed?: number;
13
+ delta?: number;
14
+ className?: string;
15
+ wrapperClassName?: string;
16
+ children: React.ReactNode;
17
+ hoverStop?: boolean;
18
+ };
19
+
20
+ export const MotionTicker = ({
21
+ direction = 'right',
22
+ speed = 1,
23
+ delta = 0.05,
24
+ className,
25
+ children,
26
+ wrapperClassName,
27
+ hoverStop = true,
28
+ }: MotionTickerProps) => {
29
+ const containerRef = useRef<HTMLDivElement>(null);
30
+ const tickerClone = useRef<HTMLDivElement>(null);
31
+ const cardWrapper = useRef<HTMLDivElement>(null);
32
+ const [isHovering, setIsHovering] = useState(false);
33
+ const isInView = useInView(containerRef, {
34
+ once: false,
35
+ margin: '50% 0%',
36
+ });
37
+ const { clonesNeeded } = useTickerClones({ tickerCard: cardWrapper, tickerClone, direction });
38
+ const calculateProportionalDuration = (distance: number, fps?: number) => {
39
+ const distancePerFrame = speed * delta;
40
+ const framesNeeded = distance / distancePerFrame;
41
+
42
+ return framesNeeded / (fps ?? 60); // calc is based on 60fps
43
+ };
44
+ const { x1, x2, fps } = useTickerIncremental({
45
+ speed,
46
+ direction,
47
+ delta,
48
+ stopIncrement: isHovering || !isInView,
49
+ onStop: async (motionValue) => {
50
+ if (!isInView) return;
51
+ const distance = 3;
52
+ const EASE_OUT_COMPENSATION = 1.15;
53
+ const duration =
54
+ calculateProportionalDuration(distance, fps?.current) * EASE_OUT_COMPENSATION;
55
+
56
+ return await animate(motionValue, motionValue.get() + distance, {
57
+ duration,
58
+ ease: 'easeOut',
59
+ });
60
+ },
61
+ });
62
+
63
+ return (
64
+ <div
65
+ ref={containerRef}
66
+ className={cn('group relative w-full overflow-hidden', wrapperClassName)}
67
+ role="group"
68
+ onMouseEnter={() => {
69
+ if (!hoverStop) return;
70
+ setIsHovering(true);
71
+ }}
72
+ onMouseLeave={() => {
73
+ if (!hoverStop) return;
74
+ setIsHovering(false);
75
+ }}
76
+ >
77
+ <motion.div
78
+ ref={cardWrapper}
79
+ className={cn('flex w-max flex-row', className)}
80
+ style={{ x: x1 }}
81
+ >
82
+ {Array.from({ length: clonesNeeded }).map((_, index) => {
83
+ return <Fragment key={index}>{children}</Fragment>;
84
+ })}
85
+ </motion.div>
86
+ <motion.div
87
+ ref={tickerClone}
88
+ className={cn('absolute top-0 h-full w-max', className)}
89
+ style={{ x: x2 }}
90
+ />
91
+ </div>
92
+ );
93
+ };